1f595a68aSyz147064 /* 2f595a68aSyz147064 * CDDL HEADER START 3f595a68aSyz147064 * 4f595a68aSyz147064 * The contents of this file are subject to the terms of the 5f595a68aSyz147064 * Common Development and Distribution License (the "License"). 6f595a68aSyz147064 * You may not use this file except in compliance with the License. 7f595a68aSyz147064 * 8f595a68aSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9f595a68aSyz147064 * or http://www.opensolaris.org/os/licensing. 10f595a68aSyz147064 * See the License for the specific language governing permissions 11f595a68aSyz147064 * and limitations under the License. 12f595a68aSyz147064 * 13f595a68aSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14f595a68aSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15f595a68aSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16f595a68aSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17f595a68aSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18f595a68aSyz147064 * 19f595a68aSyz147064 * CDDL HEADER END 20f595a68aSyz147064 */ 21f595a68aSyz147064 /* 22f595a68aSyz147064 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23f595a68aSyz147064 * Use is subject to license terms. 24f595a68aSyz147064 */ 25f595a68aSyz147064 26f595a68aSyz147064 #pragma ident "%Z%%M% %I% %E% SMI" 27f595a68aSyz147064 28f595a68aSyz147064 #include <libintl.h> 29f595a68aSyz147064 #include <stdio.h> 30f595a68aSyz147064 #include <stdlib.h> 31f595a68aSyz147064 #include <stddef.h> 32f595a68aSyz147064 #include <unistd.h> 33f595a68aSyz147064 #include <fcntl.h> 34f595a68aSyz147064 #include <string.h> 35f595a68aSyz147064 #include <stropts.h> 36f595a68aSyz147064 #include <libdevinfo.h> 37f595a68aSyz147064 #include <net/if.h> 38f595a68aSyz147064 #include <net/if_dl.h> 39f595a68aSyz147064 #include <net/if_types.h> 40*a399b765Szf162725 #include <libscf.h> 41f595a68aSyz147064 #include <libdlwlan.h> 42f595a68aSyz147064 #include <libdlwlan_impl.h> 43*a399b765Szf162725 #include <net/wpa.h> 44f595a68aSyz147064 45f595a68aSyz147064 typedef struct val_desc { 46f595a68aSyz147064 char *vd_name; 47f595a68aSyz147064 uint_t vd_val; 48f595a68aSyz147064 } val_desc_t; 49f595a68aSyz147064 50f595a68aSyz147064 struct prop_desc; 51f595a68aSyz147064 52f595a68aSyz147064 typedef dladm_status_t wl_pd_getf_t(int, wldp_t *, char **, uint_t *); 53f595a68aSyz147064 typedef dladm_status_t wl_pd_setf_t(int, wldp_t *, val_desc_t *, uint_t); 54f595a68aSyz147064 typedef dladm_status_t wl_pd_checkf_t(int, wldp_t *, struct prop_desc *, 55f595a68aSyz147064 char **, uint_t, val_desc_t **); 56f595a68aSyz147064 typedef struct prop_desc { 57f595a68aSyz147064 char *pd_name; 58f595a68aSyz147064 val_desc_t pd_defval; 59f595a68aSyz147064 val_desc_t *pd_modval; 60f595a68aSyz147064 uint_t pd_nmodval; 61f595a68aSyz147064 wl_pd_setf_t *pd_set; 62f595a68aSyz147064 wl_pd_getf_t *pd_getmod; 63f595a68aSyz147064 wl_pd_getf_t *pd_get; 64f595a68aSyz147064 wl_pd_checkf_t *pd_check; 65f595a68aSyz147064 } prop_desc_t; 66f595a68aSyz147064 67*a399b765Szf162725 static int wpa_instance_create(const char *, void *); 68*a399b765Szf162725 static int wpa_instance_delete(const char *); 69*a399b765Szf162725 70f595a68aSyz147064 static int do_get_bsstype(int, wldp_t *); 71f595a68aSyz147064 static int do_get_essid(int, wldp_t *); 72f595a68aSyz147064 static int do_get_bssid(int, wldp_t *); 73f595a68aSyz147064 static int do_get_signal(int, wldp_t *); 74f595a68aSyz147064 static int do_get_encryption(int, wldp_t *); 75f595a68aSyz147064 static int do_get_authmode(int, wldp_t *); 76f595a68aSyz147064 static int do_get_linkstatus(int, wldp_t *); 77f595a68aSyz147064 static int do_get_esslist(int, wldp_t *); 78f595a68aSyz147064 static int do_get_rate(int, wldp_t *); 79f595a68aSyz147064 static int do_get_phyconf(int, wldp_t *); 80f595a68aSyz147064 static int do_get_powermode(int, wldp_t *); 81f595a68aSyz147064 static int do_get_radio(int, wldp_t *); 82f595a68aSyz147064 static int do_get_mode(int, wldp_t *); 83*a399b765Szf162725 static int do_get_capability(int, wldp_t *); 84*a399b765Szf162725 static int do_get_wpamode(int, wldp_t *); 85f595a68aSyz147064 86f595a68aSyz147064 static int do_set_bsstype(int, wldp_t *, dladm_wlan_bsstype_t *); 87f595a68aSyz147064 static int do_set_authmode(int, wldp_t *, dladm_wlan_auth_t *); 88f595a68aSyz147064 static int do_set_encryption(int, wldp_t *, dladm_wlan_secmode_t *); 89f595a68aSyz147064 static int do_set_essid(int, wldp_t *, dladm_wlan_essid_t *); 90f595a68aSyz147064 static int do_set_createibss(int, wldp_t *, boolean_t *); 91*a399b765Szf162725 static int do_set_key(int, wldp_t *, dladm_wlan_key_t *, uint_t); 92f595a68aSyz147064 static int do_set_rate(int, wldp_t *, dladm_wlan_rates_t *); 93f595a68aSyz147064 static int do_set_powermode(int, wldp_t *, dladm_wlan_powermode_t *); 94f595a68aSyz147064 static int do_set_radio(int, wldp_t *, dladm_wlan_radio_t *); 95f595a68aSyz147064 static int do_set_channel(int, wldp_t *, dladm_wlan_channel_t *); 96f595a68aSyz147064 97f595a68aSyz147064 static int open_link(const char *); 98f595a68aSyz147064 static int do_scan(int, wldp_t *); 99*a399b765Szf162725 static int do_disconnect(const char *, int, wldp_t *); 100f595a68aSyz147064 static boolean_t find_val_by_name(const char *, val_desc_t *, uint_t, uint_t *); 101f595a68aSyz147064 static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); 102f595a68aSyz147064 static void generate_essid(dladm_wlan_essid_t *); 103f595a68aSyz147064 104f595a68aSyz147064 static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); 105f595a68aSyz147064 106f595a68aSyz147064 static wl_pd_getf_t do_get_rate_mod, do_get_rate_prop, do_get_channel_prop, 107f595a68aSyz147064 do_get_powermode_prop, do_get_radio_prop; 108f595a68aSyz147064 static wl_pd_setf_t do_set_rate_prop, do_set_powermode_prop, 109f595a68aSyz147064 do_set_radio_prop; 110f595a68aSyz147064 static wl_pd_checkf_t do_check_prop, do_check_rate; 111f595a68aSyz147064 112f595a68aSyz147064 static val_desc_t linkstatus_vals[] = { 113f595a68aSyz147064 { "disconnected", DLADM_WLAN_LINKSTATUS_DISCONNECTED }, 114f595a68aSyz147064 { "connected", DLADM_WLAN_LINKSTATUS_CONNECTED } 115f595a68aSyz147064 }; 116f595a68aSyz147064 117f595a68aSyz147064 static val_desc_t secmode_vals[] = { 118f595a68aSyz147064 { "none", DLADM_WLAN_SECMODE_NONE }, 119*a399b765Szf162725 { "wep", DLADM_WLAN_SECMODE_WEP }, 120*a399b765Szf162725 { "wpa", DLADM_WLAN_SECMODE_WPA } 121f595a68aSyz147064 }; 122f595a68aSyz147064 123f595a68aSyz147064 static val_desc_t strength_vals[] = { 124f595a68aSyz147064 { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, 125f595a68aSyz147064 { "weak", DLADM_WLAN_STRENGTH_WEAK }, 126f595a68aSyz147064 { "good", DLADM_WLAN_STRENGTH_GOOD }, 127f595a68aSyz147064 { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, 128f595a68aSyz147064 { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } 129f595a68aSyz147064 }; 130f595a68aSyz147064 131f595a68aSyz147064 static val_desc_t mode_vals[] = { 132f595a68aSyz147064 { "a", DLADM_WLAN_MODE_80211A }, 133f595a68aSyz147064 { "b", DLADM_WLAN_MODE_80211B }, 134f595a68aSyz147064 { "g", DLADM_WLAN_MODE_80211G }, 135f595a68aSyz147064 }; 136f595a68aSyz147064 137f595a68aSyz147064 static val_desc_t auth_vals[] = { 138f595a68aSyz147064 { "open", DLADM_WLAN_AUTH_OPEN }, 139f595a68aSyz147064 { "shared", DLADM_WLAN_AUTH_SHARED } 140f595a68aSyz147064 }; 141f595a68aSyz147064 142f595a68aSyz147064 static val_desc_t bsstype_vals[] = { 143f595a68aSyz147064 { "bss", DLADM_WLAN_BSSTYPE_BSS }, 144f595a68aSyz147064 { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, 145f595a68aSyz147064 { "any", DLADM_WLAN_BSSTYPE_ANY } 146f595a68aSyz147064 }; 147f595a68aSyz147064 148f595a68aSyz147064 static val_desc_t radio_vals[] = { 149f595a68aSyz147064 { "on", DLADM_WLAN_RADIO_ON }, 150f595a68aSyz147064 { "off", DLADM_WLAN_RADIO_OFF } 151f595a68aSyz147064 }; 152f595a68aSyz147064 153f595a68aSyz147064 static val_desc_t powermode_vals[] = { 154f595a68aSyz147064 { "off", DLADM_WLAN_PM_OFF }, 155f595a68aSyz147064 { "fast", DLADM_WLAN_PM_FAST }, 156f595a68aSyz147064 { "max", DLADM_WLAN_PM_MAX } 157f595a68aSyz147064 }; 158f595a68aSyz147064 159f595a68aSyz147064 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 160f595a68aSyz147064 static prop_desc_t prop_table[] = { 161f595a68aSyz147064 162f595a68aSyz147064 { "channel", { NULL, 0 }, NULL, 0, 163f595a68aSyz147064 NULL, NULL, do_get_channel_prop, do_check_prop}, 164f595a68aSyz147064 165f595a68aSyz147064 { "powermode", { "off", DLADM_WLAN_PM_OFF }, powermode_vals, 166f595a68aSyz147064 VALCNT(powermode_vals), 167f595a68aSyz147064 do_set_powermode_prop, NULL, 168f595a68aSyz147064 do_get_powermode_prop, do_check_prop}, 169f595a68aSyz147064 170f595a68aSyz147064 { "radio", { "on", DLADM_WLAN_RADIO_ON }, radio_vals, 171f595a68aSyz147064 VALCNT(radio_vals), 172f595a68aSyz147064 do_set_radio_prop, NULL, 173f595a68aSyz147064 do_get_radio_prop, do_check_prop}, 174f595a68aSyz147064 175f595a68aSyz147064 { "speed", { "", 0 }, NULL, 0, 176f595a68aSyz147064 do_set_rate_prop, do_get_rate_mod, 177f595a68aSyz147064 do_get_rate_prop, do_check_rate} 178f595a68aSyz147064 }; 179f595a68aSyz147064 /* 180f595a68aSyz147064 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 181f595a68aSyz147064 * rates to be retrieved. However, we cannot increase it at this 182f595a68aSyz147064 * time because it will break binary comatibility with unbundled 183f595a68aSyz147064 * WiFi drivers and utilities. So for now we define an additional 184f595a68aSyz147064 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 185f595a68aSyz147064 */ 186f595a68aSyz147064 #define MAX_SUPPORT_RATES 64 187f595a68aSyz147064 #define DLADM_WLAN_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 188f595a68aSyz147064 #define IS_CONNECTED(gbuf) \ 189f595a68aSyz147064 ((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED)) 190f595a68aSyz147064 191f595a68aSyz147064 static dladm_status_t 192f595a68aSyz147064 dladm_wlan_wlresult2status(wldp_t *gbuf) 193f595a68aSyz147064 { 194f595a68aSyz147064 switch (gbuf->wldp_result) { 195f595a68aSyz147064 case WL_SUCCESS: 196f595a68aSyz147064 return (DLADM_STATUS_OK); 197f595a68aSyz147064 198f595a68aSyz147064 case WL_NOTSUPPORTED: 199f595a68aSyz147064 case WL_LACK_FEATURE: 200f595a68aSyz147064 return (DLADM_STATUS_NOTSUP); 201f595a68aSyz147064 202f595a68aSyz147064 case WL_READONLY: 203f595a68aSyz147064 return (DLADM_STATUS_PROPRDONLY); 204f595a68aSyz147064 205f595a68aSyz147064 default: 206f595a68aSyz147064 break; 207f595a68aSyz147064 } 208f595a68aSyz147064 209f595a68aSyz147064 return (DLADM_STATUS_FAILED); 210f595a68aSyz147064 } 211f595a68aSyz147064 212f595a68aSyz147064 static int 213f595a68aSyz147064 open_link(const char *link) 214f595a68aSyz147064 { 215f595a68aSyz147064 char linkname[MAXPATHLEN]; 216f595a68aSyz147064 wldp_t *gbuf; 217f595a68aSyz147064 int fd; 218f595a68aSyz147064 219f595a68aSyz147064 if (link == NULL) 220f595a68aSyz147064 return (-1); 221f595a68aSyz147064 222f595a68aSyz147064 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 223f595a68aSyz147064 if ((fd = open(linkname, O_RDWR)) < 0) 224f595a68aSyz147064 return (-1); 225f595a68aSyz147064 226f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 227f595a68aSyz147064 (void) close(fd); 228f595a68aSyz147064 return (-1); 229f595a68aSyz147064 } 230f595a68aSyz147064 231f595a68aSyz147064 /* 232f595a68aSyz147064 * Check to see if the link is wireless. 233f595a68aSyz147064 */ 234f595a68aSyz147064 if (do_get_bsstype(fd, gbuf) < 0) { 235f595a68aSyz147064 free(gbuf); 236f595a68aSyz147064 (void) close(fd); 237f595a68aSyz147064 return (-1); 238f595a68aSyz147064 } 239f595a68aSyz147064 240f595a68aSyz147064 free(gbuf); 241f595a68aSyz147064 return (fd); 242f595a68aSyz147064 } 243f595a68aSyz147064 244f595a68aSyz147064 static dladm_wlan_mode_t 245f595a68aSyz147064 do_convert_mode(wl_phy_conf_t *phyp) 246f595a68aSyz147064 { 247f595a68aSyz147064 switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) { 248f595a68aSyz147064 case WL_ERP: 249f595a68aSyz147064 return (DLADM_WLAN_MODE_80211G); 250f595a68aSyz147064 case WL_OFDM: 251f595a68aSyz147064 return (DLADM_WLAN_MODE_80211A); 252f595a68aSyz147064 case WL_DSSS: 253f595a68aSyz147064 case WL_FHSS: 254f595a68aSyz147064 return (DLADM_WLAN_MODE_80211B); 255f595a68aSyz147064 default: 256f595a68aSyz147064 break; 257f595a68aSyz147064 } 258f595a68aSyz147064 259f595a68aSyz147064 return (DLADM_WLAN_MODE_NONE); 260f595a68aSyz147064 } 261f595a68aSyz147064 262f595a68aSyz147064 static boolean_t 263f595a68aSyz147064 do_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) 264f595a68aSyz147064 { 265f595a68aSyz147064 wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf; 266f595a68aSyz147064 wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf; 267f595a68aSyz147064 268f595a68aSyz147064 switch (wlfp->wl_fhss_subtype) { 269f595a68aSyz147064 case WL_FHSS: 270f595a68aSyz147064 case WL_DSSS: 271f595a68aSyz147064 case WL_IRBASE: 272f595a68aSyz147064 case WL_HRDS: 273f595a68aSyz147064 case WL_ERP: 274f595a68aSyz147064 *channelp = wlfp->wl_fhss_channel; 275f595a68aSyz147064 break; 276f595a68aSyz147064 case WL_OFDM: 277f595a68aSyz147064 *channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency); 278f595a68aSyz147064 break; 279f595a68aSyz147064 default: 280f595a68aSyz147064 return (B_FALSE); 281f595a68aSyz147064 } 282f595a68aSyz147064 return (B_TRUE); 283f595a68aSyz147064 } 284f595a68aSyz147064 285f595a68aSyz147064 #define IEEE80211_RATE 0x7f 286f595a68aSyz147064 static void 287f595a68aSyz147064 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp) 288f595a68aSyz147064 { 289f595a68aSyz147064 int i; 290f595a68aSyz147064 291f595a68aSyz147064 (void) memset(attrp, 0, sizeof (*attrp)); 292f595a68aSyz147064 293f595a68aSyz147064 (void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN, 294f595a68aSyz147064 "%s", wlp->wl_ess_conf_essid.wl_essid_essid); 295f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 296f595a68aSyz147064 297f595a68aSyz147064 (void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid, 298f595a68aSyz147064 DLADM_WLAN_BSSID_LEN); 299f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 300f595a68aSyz147064 301f595a68aSyz147064 attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled == 302f595a68aSyz147064 WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE); 303*a399b765Szf162725 if (wlp->wl_ess_conf_reserved[0] > 0) 304*a399b765Szf162725 attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 305f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 306f595a68aSyz147064 307f595a68aSyz147064 attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ? 308f595a68aSyz147064 DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS); 309f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 310f595a68aSyz147064 311f595a68aSyz147064 attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ? 312f595a68aSyz147064 DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED); 313f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 314f595a68aSyz147064 315f595a68aSyz147064 attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl); 316f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 317f595a68aSyz147064 318f595a68aSyz147064 attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf); 319f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 320f595a68aSyz147064 321f595a68aSyz147064 for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) { 322f595a68aSyz147064 wlp->wl_supported_rates[i] &= IEEE80211_RATE; 323f595a68aSyz147064 if (wlp->wl_supported_rates[i] > attrp->wa_speed) 324f595a68aSyz147064 attrp->wa_speed = wlp->wl_supported_rates[i]; 325f595a68aSyz147064 } 326f595a68aSyz147064 if (attrp->wa_speed > 0) 327f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 328f595a68aSyz147064 329f595a68aSyz147064 if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, 330f595a68aSyz147064 &attrp->wa_channel)) 331f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL; 332f595a68aSyz147064 } 333f595a68aSyz147064 334f595a68aSyz147064 dladm_status_t 335f595a68aSyz147064 dladm_wlan_scan(const char *link, void *arg, 336f595a68aSyz147064 boolean_t (*func)(void *, dladm_wlan_attr_t *)) 337f595a68aSyz147064 { 338f595a68aSyz147064 int fd, i; 339f595a68aSyz147064 uint32_t count; 340f595a68aSyz147064 wl_ess_conf_t *wlp; 341f595a68aSyz147064 wldp_t *gbuf; 342f595a68aSyz147064 dladm_wlan_attr_t wlattr; 343f595a68aSyz147064 dladm_status_t status; 344f595a68aSyz147064 boolean_t connected; 345f595a68aSyz147064 346f595a68aSyz147064 if ((fd = open_link(link)) < 0) 347f595a68aSyz147064 return (DLADM_STATUS_LINKINVAL); 348f595a68aSyz147064 349f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 350f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 351f595a68aSyz147064 goto done; 352f595a68aSyz147064 } 353f595a68aSyz147064 354f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 355f595a68aSyz147064 status = DLADM_STATUS_FAILED; 356f595a68aSyz147064 goto done; 357f595a68aSyz147064 } 358f595a68aSyz147064 connected = IS_CONNECTED(gbuf); 359f595a68aSyz147064 360f595a68aSyz147064 if (do_scan(fd, gbuf) < 0) { 361f595a68aSyz147064 status = DLADM_STATUS_FAILED; 362f595a68aSyz147064 goto done; 363f595a68aSyz147064 } 364f595a68aSyz147064 365*a399b765Szf162725 if (func == NULL) { 366*a399b765Szf162725 status = DLADM_STATUS_OK; 367*a399b765Szf162725 goto done; 368*a399b765Szf162725 } 369*a399b765Szf162725 370f595a68aSyz147064 if (do_get_esslist(fd, gbuf) < 0) { 371f595a68aSyz147064 status = DLADM_STATUS_FAILED; 372f595a68aSyz147064 goto done; 373f595a68aSyz147064 } 374f595a68aSyz147064 375f595a68aSyz147064 wlp = ((wl_ess_list_t *)gbuf->wldp_buf)->wl_ess_list_ess; 376f595a68aSyz147064 count = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num; 377f595a68aSyz147064 378f595a68aSyz147064 for (i = 0; i < count; i++, wlp++) { 379f595a68aSyz147064 fill_wlan_attr(wlp, &wlattr); 380f595a68aSyz147064 if (!func(arg, &wlattr)) 381f595a68aSyz147064 break; 382f595a68aSyz147064 } 383f595a68aSyz147064 384f595a68aSyz147064 if (!connected) { 385f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 386f595a68aSyz147064 status = DLADM_STATUS_FAILED; 387f595a68aSyz147064 goto done; 388f595a68aSyz147064 } 389f595a68aSyz147064 if (IS_CONNECTED(gbuf)) 390*a399b765Szf162725 (void) do_disconnect(link, fd, gbuf); 391f595a68aSyz147064 } 392f595a68aSyz147064 393f595a68aSyz147064 status = DLADM_STATUS_OK; 394f595a68aSyz147064 done: 395f595a68aSyz147064 free(gbuf); 396f595a68aSyz147064 (void) close(fd); 397f595a68aSyz147064 return (status); 398f595a68aSyz147064 } 399f595a68aSyz147064 400f595a68aSyz147064 /* 401f595a68aSyz147064 * Structures used in building the list of eligible WLANs to connect to. 402f595a68aSyz147064 * Specifically, `connect_state' has the WLAN attributes that must be matched 403f595a68aSyz147064 * (in `cs_attr') and a growing list of WLANs that matched those attributes 404f595a68aSyz147064 * chained through `cs_list'. Each element in the list is of type `attr_node' 405f595a68aSyz147064 * and has the matching WLAN's attributes and a pointer to the next element. 406f595a68aSyz147064 * For convenience, `cs_count' tracks the number of elements in the list. 407f595a68aSyz147064 */ 408f595a68aSyz147064 typedef struct attr_node { 409f595a68aSyz147064 dladm_wlan_attr_t an_attr; 410f595a68aSyz147064 struct attr_node *an_next; 411f595a68aSyz147064 } attr_node_t; 412f595a68aSyz147064 413f595a68aSyz147064 typedef struct connect_state { 414f595a68aSyz147064 dladm_wlan_attr_t *cs_attr; 415f595a68aSyz147064 uint_t cs_count; 416f595a68aSyz147064 attr_node_t *cs_list; 417f595a68aSyz147064 } connect_state_t; 418f595a68aSyz147064 419f595a68aSyz147064 /* 420f595a68aSyz147064 * Compare two sets of WLAN attributes. For now, we only consider strength 421f595a68aSyz147064 * and speed (in that order), which matches the documented default policy for 422f595a68aSyz147064 * dladm_wlan_connect(). 423f595a68aSyz147064 */ 424f595a68aSyz147064 static int 425f595a68aSyz147064 attr_compare(const void *p1, const void *p2) 426f595a68aSyz147064 { 427f595a68aSyz147064 dladm_wlan_attr_t *attrp1, *attrp2; 428f595a68aSyz147064 429f595a68aSyz147064 attrp1 = (*(dladm_wlan_attr_t **)p1); 430f595a68aSyz147064 attrp2 = (*(dladm_wlan_attr_t **)p2); 431f595a68aSyz147064 432f595a68aSyz147064 if (attrp1->wa_strength < attrp2->wa_strength) 433f595a68aSyz147064 return (1); 434f595a68aSyz147064 435f595a68aSyz147064 if (attrp1->wa_strength > attrp2->wa_strength) 436f595a68aSyz147064 return (-1); 437f595a68aSyz147064 438f595a68aSyz147064 return (attrp2->wa_speed - attrp1->wa_speed); 439f595a68aSyz147064 } 440f595a68aSyz147064 441f595a68aSyz147064 /* 442f595a68aSyz147064 * Callback function used by dladm_wlan_connect() to filter out unwanted 443f595a68aSyz147064 * WLANs when scanning for available WLANs. Always returns B_TRUE to 444f595a68aSyz147064 * continue the scan. 445f595a68aSyz147064 */ 446f595a68aSyz147064 static boolean_t 447f595a68aSyz147064 connect_cb(void *arg, dladm_wlan_attr_t *attrp) 448f595a68aSyz147064 { 449f595a68aSyz147064 attr_node_t *nodep; 450f595a68aSyz147064 dladm_wlan_attr_t *fattrp; 451f595a68aSyz147064 connect_state_t *statep = (connect_state_t *)arg; 452f595a68aSyz147064 453f595a68aSyz147064 fattrp = statep->cs_attr; 454f595a68aSyz147064 if (fattrp == NULL) 455f595a68aSyz147064 goto append; 456f595a68aSyz147064 457f595a68aSyz147064 if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid) 458f595a68aSyz147064 return (B_TRUE); 459f595a68aSyz147064 460f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 && 461f595a68aSyz147064 strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes, 462f595a68aSyz147064 DLADM_WLAN_MAX_ESSID_LEN) != 0) 463f595a68aSyz147064 return (B_TRUE); 464f595a68aSyz147064 465f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 466f595a68aSyz147064 fattrp->wa_secmode != attrp->wa_secmode) 467f595a68aSyz147064 return (B_TRUE); 468f595a68aSyz147064 469f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 && 470f595a68aSyz147064 fattrp->wa_mode != attrp->wa_mode) 471f595a68aSyz147064 return (B_TRUE); 472f595a68aSyz147064 473f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 && 474f595a68aSyz147064 fattrp->wa_strength != attrp->wa_strength) 475f595a68aSyz147064 return (B_TRUE); 476f595a68aSyz147064 477f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 && 478f595a68aSyz147064 fattrp->wa_speed != attrp->wa_speed) 479f595a68aSyz147064 return (B_TRUE); 480f595a68aSyz147064 481f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) { 482f595a68aSyz147064 attrp->wa_auth = fattrp->wa_auth; 483f595a68aSyz147064 attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 484f595a68aSyz147064 } 485f595a68aSyz147064 486f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 487f595a68aSyz147064 fattrp->wa_bsstype != attrp->wa_bsstype) 488f595a68aSyz147064 return (B_TRUE); 489f595a68aSyz147064 490f595a68aSyz147064 if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 && 491f595a68aSyz147064 memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes, 492f595a68aSyz147064 DLADM_WLAN_BSSID_LEN) != 0) 493f595a68aSyz147064 return (B_TRUE); 494f595a68aSyz147064 append: 495f595a68aSyz147064 nodep = malloc(sizeof (attr_node_t)); 496f595a68aSyz147064 if (nodep == NULL) 497f595a68aSyz147064 return (B_TRUE); 498f595a68aSyz147064 499f595a68aSyz147064 (void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t)); 500f595a68aSyz147064 nodep->an_next = statep->cs_list; 501f595a68aSyz147064 statep->cs_list = nodep; 502f595a68aSyz147064 statep->cs_count++; 503f595a68aSyz147064 504f595a68aSyz147064 return (B_TRUE); 505f595a68aSyz147064 } 506f595a68aSyz147064 507*a399b765Szf162725 #define IEEE80211_C_WPA 0x01800000 508*a399b765Szf162725 509f595a68aSyz147064 static dladm_status_t 510*a399b765Szf162725 do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, 511f595a68aSyz147064 boolean_t create_ibss, void *keys, uint_t key_count, int timeout) 512f595a68aSyz147064 { 513f595a68aSyz147064 dladm_wlan_secmode_t secmode; 514f595a68aSyz147064 dladm_wlan_auth_t authmode; 515f595a68aSyz147064 dladm_wlan_bsstype_t bsstype; 516f595a68aSyz147064 dladm_wlan_essid_t essid; 517f595a68aSyz147064 boolean_t essid_valid = B_FALSE; 518f595a68aSyz147064 dladm_wlan_channel_t channel; 519f595a68aSyz147064 hrtime_t start; 520*a399b765Szf162725 wl_capability_t *caps; 521f595a68aSyz147064 522f595a68aSyz147064 if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) { 523f595a68aSyz147064 channel = attrp->wa_channel; 524f595a68aSyz147064 if (do_set_channel(fd, gbuf, &channel) < 0) 525f595a68aSyz147064 goto fail; 526f595a68aSyz147064 } 527f595a68aSyz147064 528f595a68aSyz147064 secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ? 529f595a68aSyz147064 attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE; 530f595a68aSyz147064 531f595a68aSyz147064 if (do_set_encryption(fd, gbuf, &secmode) < 0) 532f595a68aSyz147064 goto fail; 533f595a68aSyz147064 534f595a68aSyz147064 authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ? 535f595a68aSyz147064 attrp->wa_auth : DLADM_WLAN_AUTH_OPEN; 536f595a68aSyz147064 537f595a68aSyz147064 if (do_set_authmode(fd, gbuf, &authmode) < 0) 538f595a68aSyz147064 goto fail; 539f595a68aSyz147064 540f595a68aSyz147064 bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ? 541f595a68aSyz147064 attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS; 542f595a68aSyz147064 543f595a68aSyz147064 if (do_set_bsstype(fd, gbuf, &bsstype) < 0) 544f595a68aSyz147064 goto fail; 545f595a68aSyz147064 546f595a68aSyz147064 if (secmode == DLADM_WLAN_SECMODE_WEP) { 547f595a68aSyz147064 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 548f595a68aSyz147064 return (DLADM_STATUS_BADARG); 549*a399b765Szf162725 if (do_set_key(fd, gbuf, keys, key_count) < 0) 550f595a68aSyz147064 goto fail; 551*a399b765Szf162725 } else if (secmode == DLADM_WLAN_SECMODE_WPA) { 552*a399b765Szf162725 if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) 553*a399b765Szf162725 return (DLADM_STATUS_BADARG); 554*a399b765Szf162725 if (do_get_capability(fd, gbuf) < 0) 555*a399b765Szf162725 goto fail; 556*a399b765Szf162725 caps = (wl_capability_t *)(gbuf->wldp_buf); 557*a399b765Szf162725 if ((caps->caps & IEEE80211_C_WPA) == 0) 558*a399b765Szf162725 return (DLADM_STATUS_NOTSUP); 559f595a68aSyz147064 } 560f595a68aSyz147064 561f595a68aSyz147064 if (create_ibss) { 562f595a68aSyz147064 if (do_set_channel(fd, gbuf, &channel) < 0) 563f595a68aSyz147064 goto fail; 564f595a68aSyz147064 565f595a68aSyz147064 if (do_set_createibss(fd, gbuf, &create_ibss) < 0) 566f595a68aSyz147064 goto fail; 567f595a68aSyz147064 568f595a68aSyz147064 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) { 569f595a68aSyz147064 generate_essid(&essid); 570f595a68aSyz147064 essid_valid = B_TRUE; 571f595a68aSyz147064 } 572f595a68aSyz147064 } 573f595a68aSyz147064 574f595a68aSyz147064 if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) { 575f595a68aSyz147064 essid = attrp->wa_essid; 576f595a68aSyz147064 essid_valid = B_TRUE; 577f595a68aSyz147064 } 578f595a68aSyz147064 579f595a68aSyz147064 if (!essid_valid) 580f595a68aSyz147064 return (DLADM_STATUS_FAILED); 581f595a68aSyz147064 if (do_set_essid(fd, gbuf, &essid) < 0) 582f595a68aSyz147064 goto fail; 583f595a68aSyz147064 584*a399b765Szf162725 /* 585*a399b765Szf162725 * Because wpa daemon needs getting essid from driver, 586*a399b765Szf162725 * we need call do_set_essid() first, then call wpa_instance_create(). 587*a399b765Szf162725 */ 588*a399b765Szf162725 if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) 589*a399b765Szf162725 (void) wpa_instance_create(link, keys); 590*a399b765Szf162725 591f595a68aSyz147064 start = gethrtime(); 592f595a68aSyz147064 for (;;) { 593f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) 594f595a68aSyz147064 goto fail; 595f595a68aSyz147064 596f595a68aSyz147064 if (IS_CONNECTED(gbuf)) 597f595a68aSyz147064 break; 598f595a68aSyz147064 599f595a68aSyz147064 (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE); 600f595a68aSyz147064 if ((timeout >= 0) && (gethrtime() - start) / 601f595a68aSyz147064 NANOSEC >= timeout) 602f595a68aSyz147064 return (DLADM_STATUS_TIMEDOUT); 603f595a68aSyz147064 } 604f595a68aSyz147064 return (DLADM_STATUS_OK); 605f595a68aSyz147064 fail: 606f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 607f595a68aSyz147064 } 608f595a68aSyz147064 609f595a68aSyz147064 dladm_status_t 610f595a68aSyz147064 dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, 611f595a68aSyz147064 int timeout, void *keys, uint_t key_count, uint_t flags) 612f595a68aSyz147064 { 613f595a68aSyz147064 int fd, i; 614f595a68aSyz147064 wldp_t *gbuf = NULL; 615f595a68aSyz147064 connect_state_t state = {0, NULL, NULL}; 616f595a68aSyz147064 attr_node_t *nodep = NULL; 617f595a68aSyz147064 boolean_t create_ibss, set_authmode; 618f595a68aSyz147064 dladm_wlan_attr_t **wl_list = NULL; 619f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_FAILED; 620f595a68aSyz147064 621f595a68aSyz147064 if ((fd = open_link(link)) < 0) 622f595a68aSyz147064 return (DLADM_STATUS_LINKINVAL); 623f595a68aSyz147064 624f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 625f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 626f595a68aSyz147064 goto done; 627f595a68aSyz147064 } 628f595a68aSyz147064 629f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 630f595a68aSyz147064 status = DLADM_STATUS_FAILED; 631f595a68aSyz147064 goto done; 632f595a68aSyz147064 } 633f595a68aSyz147064 634f595a68aSyz147064 if (IS_CONNECTED(gbuf)) { 635f595a68aSyz147064 status = DLADM_STATUS_ISCONN; 636f595a68aSyz147064 goto done; 637f595a68aSyz147064 } 638f595a68aSyz147064 639f595a68aSyz147064 set_authmode = ((attrp != NULL) && 640f595a68aSyz147064 (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0); 641f595a68aSyz147064 create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 && 642f595a68aSyz147064 attrp != NULL && 643f595a68aSyz147064 (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 && 644f595a68aSyz147064 attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS); 645f595a68aSyz147064 646f595a68aSyz147064 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 || 647f595a68aSyz147064 (create_ibss && attrp != NULL && 648f595a68aSyz147064 (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) { 649*a399b765Szf162725 status = do_connect(link, fd, gbuf, attrp, 650f595a68aSyz147064 create_ibss, keys, key_count, timeout); 651f595a68aSyz147064 goto done; 652f595a68aSyz147064 } 653f595a68aSyz147064 654f595a68aSyz147064 state.cs_attr = attrp; 655f595a68aSyz147064 state.cs_list = NULL; 656f595a68aSyz147064 state.cs_count = 0; 657f595a68aSyz147064 658f595a68aSyz147064 status = dladm_wlan_scan(link, &state, connect_cb); 659f595a68aSyz147064 if (status != DLADM_STATUS_OK) 660f595a68aSyz147064 goto done; 661f595a68aSyz147064 662f595a68aSyz147064 if (state.cs_count == 0) { 663f595a68aSyz147064 if (!create_ibss) { 664f595a68aSyz147064 status = DLADM_STATUS_NOTFOUND; 665f595a68aSyz147064 goto done; 666f595a68aSyz147064 } 667*a399b765Szf162725 status = do_connect(link, fd, gbuf, attrp, create_ibss, 668f595a68aSyz147064 keys, key_count, timeout); 669f595a68aSyz147064 goto done; 670f595a68aSyz147064 } 671f595a68aSyz147064 672f595a68aSyz147064 wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *)); 673f595a68aSyz147064 if (wl_list == NULL) { 674f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 675f595a68aSyz147064 goto done; 676f595a68aSyz147064 } 677f595a68aSyz147064 678f595a68aSyz147064 nodep = state.cs_list; 679f595a68aSyz147064 for (i = 0; i < state.cs_count; i++) { 680f595a68aSyz147064 wl_list[i] = &nodep->an_attr; 681f595a68aSyz147064 nodep = nodep->an_next; 682f595a68aSyz147064 } 683f595a68aSyz147064 qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *), 684f595a68aSyz147064 attr_compare); 685f595a68aSyz147064 686f595a68aSyz147064 for (i = 0; i < state.cs_count; i++) { 687f595a68aSyz147064 dladm_wlan_attr_t *ap = wl_list[i]; 688f595a68aSyz147064 689*a399b765Szf162725 status = do_connect(link, fd, gbuf, ap, create_ibss, keys, 690f595a68aSyz147064 key_count, timeout); 691f595a68aSyz147064 if (status == DLADM_STATUS_OK) 692f595a68aSyz147064 break; 693f595a68aSyz147064 694f595a68aSyz147064 if (!set_authmode) { 695f595a68aSyz147064 ap->wa_auth = DLADM_WLAN_AUTH_SHARED; 696f595a68aSyz147064 ap->wa_valid |= DLADM_WLAN_ATTR_AUTH; 697*a399b765Szf162725 status = do_connect(link, fd, gbuf, ap, create_ibss, 698*a399b765Szf162725 keys, key_count, timeout); 699f595a68aSyz147064 if (status == DLADM_STATUS_OK) 700f595a68aSyz147064 break; 701f595a68aSyz147064 } 702f595a68aSyz147064 } 703f595a68aSyz147064 done: 704f595a68aSyz147064 if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN)) 705*a399b765Szf162725 (void) do_disconnect(link, fd, gbuf); 706f595a68aSyz147064 707f595a68aSyz147064 while (state.cs_list != NULL) { 708f595a68aSyz147064 nodep = state.cs_list; 709f595a68aSyz147064 state.cs_list = nodep->an_next; 710f595a68aSyz147064 free(nodep); 711f595a68aSyz147064 } 712f595a68aSyz147064 free(gbuf); 713f595a68aSyz147064 free(wl_list); 714f595a68aSyz147064 (void) close(fd); 715f595a68aSyz147064 return (status); 716f595a68aSyz147064 } 717f595a68aSyz147064 718f595a68aSyz147064 dladm_status_t 719f595a68aSyz147064 dladm_wlan_disconnect(const char *link) 720f595a68aSyz147064 { 721f595a68aSyz147064 int fd; 722f595a68aSyz147064 wldp_t *gbuf; 723f595a68aSyz147064 dladm_status_t status; 724f595a68aSyz147064 725f595a68aSyz147064 if ((fd = open_link(link)) < 0) 726f595a68aSyz147064 return (DLADM_STATUS_BADARG); 727f595a68aSyz147064 728f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 729f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 730f595a68aSyz147064 goto done; 731f595a68aSyz147064 } 732f595a68aSyz147064 733f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 734f595a68aSyz147064 status = DLADM_STATUS_FAILED; 735f595a68aSyz147064 goto done; 736f595a68aSyz147064 } 737f595a68aSyz147064 738f595a68aSyz147064 if (!IS_CONNECTED(gbuf)) { 739f595a68aSyz147064 status = DLADM_STATUS_NOTCONN; 740f595a68aSyz147064 goto done; 741f595a68aSyz147064 } 742f595a68aSyz147064 743*a399b765Szf162725 if (do_disconnect(link, fd, gbuf) < 0) { 744f595a68aSyz147064 status = DLADM_STATUS_FAILED; 745f595a68aSyz147064 goto done; 746f595a68aSyz147064 } 747f595a68aSyz147064 748f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) { 749f595a68aSyz147064 status = DLADM_STATUS_FAILED; 750f595a68aSyz147064 goto done; 751f595a68aSyz147064 } 752f595a68aSyz147064 753f595a68aSyz147064 if (IS_CONNECTED(gbuf)) { 754f595a68aSyz147064 status = DLADM_STATUS_FAILED; 755f595a68aSyz147064 goto done; 756f595a68aSyz147064 } 757f595a68aSyz147064 758f595a68aSyz147064 status = DLADM_STATUS_OK; 759f595a68aSyz147064 done: 760f595a68aSyz147064 free(gbuf); 761f595a68aSyz147064 (void) close(fd); 762f595a68aSyz147064 return (status); 763f595a68aSyz147064 } 764f595a68aSyz147064 765f595a68aSyz147064 typedef struct dladm_wlan_linkname { 766f595a68aSyz147064 char wl_name[MAXNAMELEN]; 767f595a68aSyz147064 struct dladm_wlan_linkname *wl_next; 768f595a68aSyz147064 } dladm_wlan_linkname_t; 769f595a68aSyz147064 770f595a68aSyz147064 typedef struct dladm_wlan_walk { 771f595a68aSyz147064 dladm_wlan_linkname_t *ww_list; 772f595a68aSyz147064 dladm_status_t ww_status; 773f595a68aSyz147064 } dladm_wlan_walk_t; 774f595a68aSyz147064 775f595a68aSyz147064 /* ARGSUSED */ 776f595a68aSyz147064 static int 777f595a68aSyz147064 append_linkname(di_node_t node, di_minor_t minor, void *arg) 778f595a68aSyz147064 { 779f595a68aSyz147064 dladm_wlan_walk_t *statep = arg; 780f595a68aSyz147064 dladm_wlan_linkname_t **lastp = &statep->ww_list; 781f595a68aSyz147064 dladm_wlan_linkname_t *wlp = *lastp; 782f595a68aSyz147064 char name[MAXNAMELEN]; 783f595a68aSyz147064 784f595a68aSyz147064 (void) snprintf(name, MAXNAMELEN, "%s%d", 785f595a68aSyz147064 di_driver_name(node), di_instance(node)); 786f595a68aSyz147064 787f595a68aSyz147064 while (wlp != NULL) { 788f595a68aSyz147064 if (strcmp(wlp->wl_name, name) == 0) 789f595a68aSyz147064 return (DI_WALK_CONTINUE); 790f595a68aSyz147064 791f595a68aSyz147064 lastp = &wlp->wl_next; 792f595a68aSyz147064 wlp = wlp->wl_next; 793f595a68aSyz147064 } 794f595a68aSyz147064 if ((wlp = malloc(sizeof (*wlp))) == NULL) { 795f595a68aSyz147064 statep->ww_status = DLADM_STATUS_NOMEM; 796f595a68aSyz147064 return (DI_WALK_CONTINUE); 797f595a68aSyz147064 } 798f595a68aSyz147064 799f595a68aSyz147064 (void) strlcpy(wlp->wl_name, name, MAXNAMELEN); 800f595a68aSyz147064 wlp->wl_next = NULL; 801f595a68aSyz147064 *lastp = wlp; 802f595a68aSyz147064 803f595a68aSyz147064 return (DI_WALK_CONTINUE); 804f595a68aSyz147064 } 805f595a68aSyz147064 806f595a68aSyz147064 dladm_status_t 807f595a68aSyz147064 dladm_wlan_walk(void *arg, boolean_t (*func)(void *, const char *)) 808f595a68aSyz147064 { 809f595a68aSyz147064 di_node_t root; 810f595a68aSyz147064 dladm_wlan_walk_t state; 811f595a68aSyz147064 dladm_wlan_linkname_t *wlp, *wlp_next; 812f595a68aSyz147064 boolean_t cont = B_TRUE; 813f595a68aSyz147064 814f595a68aSyz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 815f595a68aSyz147064 return (DLADM_STATUS_FAILED); 816f595a68aSyz147064 817f595a68aSyz147064 state.ww_list = NULL; 818f595a68aSyz147064 state.ww_status = DLADM_STATUS_OK; 819f595a68aSyz147064 (void) di_walk_minor(root, DDI_NT_NET_WIFI, DI_CHECK_ALIAS, 820f595a68aSyz147064 &state, append_linkname); 821f595a68aSyz147064 di_fini(root); 822f595a68aSyz147064 823f595a68aSyz147064 for (wlp = state.ww_list; wlp != NULL; wlp = wlp_next) { 824f595a68aSyz147064 /* 825f595a68aSyz147064 * NOTE: even if (*func)() returns B_FALSE, the loop continues 826f595a68aSyz147064 * since all memory must be freed. 827f595a68aSyz147064 */ 828f595a68aSyz147064 if (cont) 829f595a68aSyz147064 cont = (*func)(arg, wlp->wl_name); 830f595a68aSyz147064 wlp_next = wlp->wl_next; 831f595a68aSyz147064 free(wlp); 832f595a68aSyz147064 } 833f595a68aSyz147064 return (state.ww_status); 834f595a68aSyz147064 } 835f595a68aSyz147064 836f595a68aSyz147064 dladm_status_t 837f595a68aSyz147064 dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) 838f595a68aSyz147064 { 839f595a68aSyz147064 int fd; 840f595a68aSyz147064 wldp_t *gbuf; 841f595a68aSyz147064 wl_rssi_t signal; 842f595a68aSyz147064 wl_bss_type_t bsstype; 843f595a68aSyz147064 wl_authmode_t authmode; 844f595a68aSyz147064 wl_encryption_t encryption; 845f595a68aSyz147064 wl_rates_t *ratesp; 846f595a68aSyz147064 dladm_wlan_attr_t *wl_attrp; 847f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_FAILED; 848f595a68aSyz147064 849f595a68aSyz147064 if (attrp == NULL) 850f595a68aSyz147064 return (DLADM_STATUS_BADARG); 851f595a68aSyz147064 852f595a68aSyz147064 if ((fd = open_link(link)) < 0) 853f595a68aSyz147064 return (DLADM_STATUS_LINKINVAL); 854f595a68aSyz147064 855f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 856f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 857f595a68aSyz147064 goto done; 858f595a68aSyz147064 } 859f595a68aSyz147064 860f595a68aSyz147064 (void) memset(attrp, 0, sizeof (*attrp)); 861f595a68aSyz147064 wl_attrp = &attrp->la_wlan_attr; 862f595a68aSyz147064 863f595a68aSyz147064 if (do_get_linkstatus(fd, gbuf) < 0) 864f595a68aSyz147064 goto done; 865f595a68aSyz147064 866f595a68aSyz147064 attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS; 867f595a68aSyz147064 if (!IS_CONNECTED(gbuf)) { 868f595a68aSyz147064 attrp->la_status = DLADM_WLAN_LINKSTATUS_DISCONNECTED; 869*a399b765Szf162725 } else { 870f595a68aSyz147064 attrp->la_status = DLADM_WLAN_LINKSTATUS_CONNECTED; 871*a399b765Szf162725 } 872f595a68aSyz147064 873f595a68aSyz147064 if (do_get_essid(fd, gbuf) < 0) 874f595a68aSyz147064 goto done; 875f595a68aSyz147064 876f595a68aSyz147064 (void) strlcpy(wl_attrp->wa_essid.we_bytes, 877f595a68aSyz147064 ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid, 878f595a68aSyz147064 DLADM_WLAN_MAX_ESSID_LEN); 879f595a68aSyz147064 880f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; 881f595a68aSyz147064 882f595a68aSyz147064 if (do_get_bssid(fd, gbuf) < 0) 883f595a68aSyz147064 goto done; 884f595a68aSyz147064 885f595a68aSyz147064 (void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf, 886f595a68aSyz147064 DLADM_WLAN_BSSID_LEN); 887f595a68aSyz147064 888f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; 889f595a68aSyz147064 890*a399b765Szf162725 if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) { 891*a399b765Szf162725 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 892*a399b765Szf162725 status = DLADM_STATUS_OK; 893*a399b765Szf162725 goto done; 894*a399b765Szf162725 } 895*a399b765Szf162725 896f595a68aSyz147064 if (do_get_encryption(fd, gbuf) < 0) 897f595a68aSyz147064 goto done; 898f595a68aSyz147064 899f595a68aSyz147064 encryption = *(wl_encryption_t *)(gbuf->wldp_buf); 900f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE; 901f595a68aSyz147064 902f595a68aSyz147064 switch (encryption) { 903f595a68aSyz147064 case WL_NOENCRYPTION: 904f595a68aSyz147064 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE; 905f595a68aSyz147064 break; 906f595a68aSyz147064 case WL_ENC_WEP: 907f595a68aSyz147064 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP; 908f595a68aSyz147064 break; 909*a399b765Szf162725 case WL_ENC_WPA: 910*a399b765Szf162725 wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA; 911*a399b765Szf162725 break; 912f595a68aSyz147064 default: 913f595a68aSyz147064 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE; 914f595a68aSyz147064 break; 915f595a68aSyz147064 } 916f595a68aSyz147064 917f595a68aSyz147064 if (do_get_signal(fd, gbuf) < 0) 918f595a68aSyz147064 goto done; 919f595a68aSyz147064 920f595a68aSyz147064 signal = *(wl_rssi_t *)(gbuf->wldp_buf); 921f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; 922f595a68aSyz147064 wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal); 923f595a68aSyz147064 924f595a68aSyz147064 if (do_get_rate(fd, gbuf) < 0) 925f595a68aSyz147064 goto done; 926f595a68aSyz147064 927f595a68aSyz147064 ratesp = (wl_rates_t *)(gbuf->wldp_buf); 928f595a68aSyz147064 if (ratesp->wl_rates_num > 0) { 929f595a68aSyz147064 uint_t i, r = 0; 930f595a68aSyz147064 931f595a68aSyz147064 for (i = 0; i < ratesp->wl_rates_num; i++) { 932f595a68aSyz147064 if (ratesp->wl_rates_rates[i] > r) 933f595a68aSyz147064 r = ratesp->wl_rates_rates[i]; 934f595a68aSyz147064 } 935f595a68aSyz147064 wl_attrp->wa_speed = r; 936f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; 937f595a68aSyz147064 } 938f595a68aSyz147064 939f595a68aSyz147064 if (do_get_authmode(fd, gbuf) < 0) 940f595a68aSyz147064 goto done; 941f595a68aSyz147064 942f595a68aSyz147064 authmode = *(wl_authmode_t *)(gbuf->wldp_buf); 943f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH; 944f595a68aSyz147064 945f595a68aSyz147064 switch (authmode) { 946f595a68aSyz147064 case WL_OPENSYSTEM: 947f595a68aSyz147064 wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN; 948f595a68aSyz147064 break; 949f595a68aSyz147064 case WL_SHAREDKEY: 950f595a68aSyz147064 wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED; 951f595a68aSyz147064 break; 952f595a68aSyz147064 default: 953f595a68aSyz147064 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH; 954f595a68aSyz147064 break; 955f595a68aSyz147064 } 956f595a68aSyz147064 957f595a68aSyz147064 if (do_get_bsstype(fd, gbuf) < 0) 958f595a68aSyz147064 goto done; 959f595a68aSyz147064 960f595a68aSyz147064 bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf); 961f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 962f595a68aSyz147064 963f595a68aSyz147064 switch (bsstype) { 964f595a68aSyz147064 case WL_BSS_BSS: 965f595a68aSyz147064 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS; 966f595a68aSyz147064 break; 967f595a68aSyz147064 case WL_BSS_IBSS: 968f595a68aSyz147064 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS; 969f595a68aSyz147064 break; 970f595a68aSyz147064 case WL_BSS_ANY: 971f595a68aSyz147064 wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY; 972f595a68aSyz147064 break; 973f595a68aSyz147064 default: 974f595a68aSyz147064 wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE; 975f595a68aSyz147064 break; 976f595a68aSyz147064 } 977f595a68aSyz147064 978f595a68aSyz147064 if (do_get_mode(fd, gbuf) < 0) 979f595a68aSyz147064 goto done; 980f595a68aSyz147064 981f595a68aSyz147064 wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf)); 982f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 983f595a68aSyz147064 if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE) 984f595a68aSyz147064 wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE; 985f595a68aSyz147064 986f595a68aSyz147064 attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; 987f595a68aSyz147064 status = DLADM_STATUS_OK; 988f595a68aSyz147064 989f595a68aSyz147064 done: 990f595a68aSyz147064 free(gbuf); 991f595a68aSyz147064 (void) close(fd); 992f595a68aSyz147064 return (status); 993f595a68aSyz147064 } 994f595a68aSyz147064 995f595a68aSyz147064 boolean_t 996f595a68aSyz147064 dladm_wlan_is_valid(const char *link) 997f595a68aSyz147064 { 998f595a68aSyz147064 int fd = open_link(link); 999f595a68aSyz147064 1000f595a68aSyz147064 if (fd < 0) 1001f595a68aSyz147064 return (B_FALSE); 1002f595a68aSyz147064 1003f595a68aSyz147064 (void) close(fd); 1004f595a68aSyz147064 return (B_TRUE); 1005f595a68aSyz147064 } 1006f595a68aSyz147064 1007f595a68aSyz147064 /* ARGSUSED */ 1008f595a68aSyz147064 static dladm_status_t 1009f595a68aSyz147064 do_check_prop(int fd, wldp_t *guf, prop_desc_t *pdp, char **prop_val, 1010f595a68aSyz147064 uint_t val_cnt, val_desc_t **vdpp) 1011f595a68aSyz147064 { 1012f595a68aSyz147064 int i; 1013f595a68aSyz147064 val_desc_t *vdp; 1014f595a68aSyz147064 1015f595a68aSyz147064 if (pdp->pd_nmodval == 0) 1016f595a68aSyz147064 return (DLADM_STATUS_PROPRDONLY); 1017f595a68aSyz147064 1018f595a68aSyz147064 if (val_cnt != 1) 1019f595a68aSyz147064 return (DLADM_STATUS_BADVALCNT); 1020f595a68aSyz147064 1021f595a68aSyz147064 for (i = 0; i < pdp->pd_nmodval; i++) 1022f595a68aSyz147064 if (strcasecmp(*prop_val, pdp->pd_modval[i].vd_name) == 0) 1023f595a68aSyz147064 break; 1024f595a68aSyz147064 1025f595a68aSyz147064 if (i == pdp->pd_nmodval) 1026f595a68aSyz147064 return (DLADM_STATUS_BADVAL); 1027f595a68aSyz147064 1028f595a68aSyz147064 vdp = malloc(sizeof (val_desc_t)); 1029f595a68aSyz147064 if (vdp == NULL) 1030f595a68aSyz147064 return (DLADM_STATUS_NOMEM); 1031f595a68aSyz147064 1032f595a68aSyz147064 (void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t)); 1033f595a68aSyz147064 *vdpp = vdp; 1034f595a68aSyz147064 return (DLADM_STATUS_OK); 1035f595a68aSyz147064 } 1036f595a68aSyz147064 1037f595a68aSyz147064 static dladm_status_t 1038f595a68aSyz147064 do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp, 1039f595a68aSyz147064 char **prop_val, uint_t val_cnt) 1040f595a68aSyz147064 { 1041f595a68aSyz147064 dladm_status_t status; 1042f595a68aSyz147064 val_desc_t *vdp = NULL; 1043f595a68aSyz147064 uint_t cnt; 1044f595a68aSyz147064 1045f595a68aSyz147064 if (pdp->pd_set == NULL) 1046f595a68aSyz147064 return (DLADM_STATUS_PROPRDONLY); 1047f595a68aSyz147064 1048f595a68aSyz147064 if (prop_val != NULL) { 1049f595a68aSyz147064 status = pdp->pd_check(fd, gbuf, pdp, prop_val, 1050f595a68aSyz147064 val_cnt, &vdp); 1051f595a68aSyz147064 1052f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1053f595a68aSyz147064 return (status); 1054f595a68aSyz147064 1055f595a68aSyz147064 cnt = val_cnt; 1056f595a68aSyz147064 } else { 1057f595a68aSyz147064 if (pdp->pd_defval.vd_name == NULL) 1058f595a68aSyz147064 return (DLADM_STATUS_NOTSUP); 1059f595a68aSyz147064 1060f595a68aSyz147064 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 1061f595a68aSyz147064 return (DLADM_STATUS_NOMEM); 1062f595a68aSyz147064 1063f595a68aSyz147064 *vdp = pdp->pd_defval; 1064f595a68aSyz147064 cnt = 1; 1065f595a68aSyz147064 } 1066f595a68aSyz147064 status = pdp->pd_set(fd, gbuf, vdp, cnt); 1067f595a68aSyz147064 if (status == DLADM_STATUS_OK) { 1068f595a68aSyz147064 /* 1069f595a68aSyz147064 * Some ioctls return 0 but store error code in 1070f595a68aSyz147064 * wldp_result. Need to fix them. 1071f595a68aSyz147064 */ 1072f595a68aSyz147064 if (gbuf->wldp_result != WL_SUCCESS) 1073f595a68aSyz147064 status = dladm_wlan_wlresult2status(gbuf); 1074f595a68aSyz147064 } 1075f595a68aSyz147064 free(vdp); 1076f595a68aSyz147064 return (status); 1077f595a68aSyz147064 } 1078f595a68aSyz147064 1079f595a68aSyz147064 dladm_status_t 1080f595a68aSyz147064 dladm_wlan_set_prop(const char *link, const char *prop_name, 1081f595a68aSyz147064 char **prop_val, uint_t val_cnt, char **errprop) 1082f595a68aSyz147064 { 1083f595a68aSyz147064 int fd, i; 1084f595a68aSyz147064 wldp_t *gbuf = NULL; 1085f595a68aSyz147064 boolean_t found = B_FALSE; 1086f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_OK; 1087f595a68aSyz147064 1088f595a68aSyz147064 if ((prop_name == NULL && prop_val != NULL) || 1089f595a68aSyz147064 (prop_val != NULL && val_cnt == 0)) 1090f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1091f595a68aSyz147064 1092f595a68aSyz147064 if ((fd = open_link(link)) < 0) 1093f595a68aSyz147064 return (DLADM_STATUS_LINKINVAL); 1094f595a68aSyz147064 1095f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 1096f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 1097f595a68aSyz147064 goto done; 1098f595a68aSyz147064 } 1099f595a68aSyz147064 1100f595a68aSyz147064 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { 1101f595a68aSyz147064 prop_desc_t *pdp = &prop_table[i]; 1102f595a68aSyz147064 dladm_status_t s; 1103f595a68aSyz147064 1104f595a68aSyz147064 if (prop_name != NULL && 1105f595a68aSyz147064 (strcasecmp(prop_name, pdp->pd_name) != 0)) 1106f595a68aSyz147064 continue; 1107f595a68aSyz147064 1108f595a68aSyz147064 found = B_TRUE; 1109f595a68aSyz147064 s = do_set_prop(fd, gbuf, pdp, prop_val, val_cnt); 1110f595a68aSyz147064 1111f595a68aSyz147064 if (prop_name != NULL) { 1112f595a68aSyz147064 status = s; 1113f595a68aSyz147064 break; 1114f595a68aSyz147064 } else { 1115f595a68aSyz147064 if (s != DLADM_STATUS_OK && 1116f595a68aSyz147064 s != DLADM_STATUS_NOTSUP) { 1117f595a68aSyz147064 if (errprop != NULL) 1118f595a68aSyz147064 *errprop = pdp->pd_name; 1119f595a68aSyz147064 status = s; 1120f595a68aSyz147064 break; 1121f595a68aSyz147064 } 1122f595a68aSyz147064 } 1123f595a68aSyz147064 } 1124f595a68aSyz147064 if (!found) 1125f595a68aSyz147064 status = DLADM_STATUS_NOTFOUND; 1126f595a68aSyz147064 done: 1127f595a68aSyz147064 free(gbuf); 1128f595a68aSyz147064 (void) close(fd); 1129f595a68aSyz147064 return (status); 1130f595a68aSyz147064 } 1131f595a68aSyz147064 1132f595a68aSyz147064 /* ARGSUSED */ 1133f595a68aSyz147064 dladm_status_t 1134f595a68aSyz147064 dladm_wlan_walk_prop(const char *link, void *arg, 1135f595a68aSyz147064 boolean_t (*func)(void *, const char *)) 1136f595a68aSyz147064 { 1137f595a68aSyz147064 int i; 1138f595a68aSyz147064 1139f595a68aSyz147064 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { 1140f595a68aSyz147064 if (!func(arg, prop_table[i].pd_name)) 1141f595a68aSyz147064 break; 1142f595a68aSyz147064 } 1143f595a68aSyz147064 return (DLADM_STATUS_OK); 1144f595a68aSyz147064 } 1145f595a68aSyz147064 1146f595a68aSyz147064 dladm_status_t 1147f595a68aSyz147064 dladm_wlan_get_prop(const char *link, dladm_prop_type_t type, 1148f595a68aSyz147064 const char *prop_name, char **prop_val, uint_t *val_cnt) 1149f595a68aSyz147064 { 1150f595a68aSyz147064 int fd; 1151f595a68aSyz147064 int i; 1152f595a68aSyz147064 wldp_t *gbuf; 1153f595a68aSyz147064 dladm_status_t status; 1154f595a68aSyz147064 uint_t cnt; 1155f595a68aSyz147064 prop_desc_t *pdp; 1156f595a68aSyz147064 1157f595a68aSyz147064 if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0) 1158f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1159f595a68aSyz147064 1160f595a68aSyz147064 for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) 1161f595a68aSyz147064 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 1162f595a68aSyz147064 break; 1163f595a68aSyz147064 1164f595a68aSyz147064 if (i == DLADM_WLAN_MAX_PROPS) 1165f595a68aSyz147064 return (DLADM_STATUS_NOTFOUND); 1166f595a68aSyz147064 1167f595a68aSyz147064 if ((fd = open_link(link)) < 0) 1168f595a68aSyz147064 return (DLADM_STATUS_LINKINVAL); 1169f595a68aSyz147064 1170f595a68aSyz147064 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { 1171f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 1172f595a68aSyz147064 goto done; 1173f595a68aSyz147064 } 1174f595a68aSyz147064 pdp = &prop_table[i]; 1175f595a68aSyz147064 status = DLADM_STATUS_OK; 1176f595a68aSyz147064 1177f595a68aSyz147064 switch (type) { 1178f595a68aSyz147064 case DLADM_PROP_VAL_CURRENT: 1179f595a68aSyz147064 status = pdp->pd_get(fd, gbuf, prop_val, val_cnt); 1180f595a68aSyz147064 break; 1181f595a68aSyz147064 1182f595a68aSyz147064 case DLADM_PROP_VAL_DEFAULT: 1183f595a68aSyz147064 if (pdp->pd_defval.vd_name == NULL) { 1184f595a68aSyz147064 status = DLADM_STATUS_NOTSUP; 1185f595a68aSyz147064 break; 1186f595a68aSyz147064 } 1187f595a68aSyz147064 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 1188f595a68aSyz147064 *val_cnt = 1; 1189f595a68aSyz147064 break; 1190f595a68aSyz147064 1191f595a68aSyz147064 case DLADM_PROP_VAL_MODIFIABLE: 1192f595a68aSyz147064 if (pdp->pd_getmod != NULL) { 1193f595a68aSyz147064 status = pdp->pd_getmod(fd, gbuf, prop_val, val_cnt); 1194f595a68aSyz147064 break; 1195f595a68aSyz147064 } 1196f595a68aSyz147064 cnt = pdp->pd_nmodval; 1197f595a68aSyz147064 if (cnt == 0) { 1198f595a68aSyz147064 status = DLADM_STATUS_NOTSUP; 1199f595a68aSyz147064 } else if (cnt > *val_cnt) { 1200f595a68aSyz147064 status = DLADM_STATUS_TOOSMALL; 1201f595a68aSyz147064 } else { 1202f595a68aSyz147064 for (i = 0; i < cnt; i++) { 1203f595a68aSyz147064 (void) strcpy(prop_val[i], 1204f595a68aSyz147064 pdp->pd_modval[i].vd_name); 1205f595a68aSyz147064 } 1206f595a68aSyz147064 *val_cnt = cnt; 1207f595a68aSyz147064 } 1208f595a68aSyz147064 break; 1209f595a68aSyz147064 default: 1210f595a68aSyz147064 status = DLADM_STATUS_BADARG; 1211f595a68aSyz147064 break; 1212f595a68aSyz147064 } 1213f595a68aSyz147064 done: 1214f595a68aSyz147064 free(gbuf); 1215f595a68aSyz147064 (void) close(fd); 1216f595a68aSyz147064 return (status); 1217f595a68aSyz147064 } 1218f595a68aSyz147064 1219f595a68aSyz147064 static boolean_t 1220f595a68aSyz147064 find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp) 1221f595a68aSyz147064 { 1222f595a68aSyz147064 int i; 1223f595a68aSyz147064 1224f595a68aSyz147064 for (i = 0; i < cnt; i++) { 1225f595a68aSyz147064 if (strcasecmp(str, vdp[i].vd_name) == 0) { 1226f595a68aSyz147064 *valp = vdp[i].vd_val; 1227f595a68aSyz147064 return (B_TRUE); 1228f595a68aSyz147064 } 1229f595a68aSyz147064 } 1230f595a68aSyz147064 return (B_FALSE); 1231f595a68aSyz147064 } 1232f595a68aSyz147064 1233f595a68aSyz147064 static boolean_t 1234f595a68aSyz147064 find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp) 1235f595a68aSyz147064 { 1236f595a68aSyz147064 int i; 1237f595a68aSyz147064 1238f595a68aSyz147064 for (i = 0; i < cnt; i++) { 1239f595a68aSyz147064 if (val == vdp[i].vd_val) { 1240f595a68aSyz147064 *strp = vdp[i].vd_name; 1241f595a68aSyz147064 return (B_TRUE); 1242f595a68aSyz147064 } 1243f595a68aSyz147064 } 1244f595a68aSyz147064 return (B_FALSE); 1245f595a68aSyz147064 } 1246f595a68aSyz147064 1247f595a68aSyz147064 const char * 1248f595a68aSyz147064 dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf) 1249f595a68aSyz147064 { 1250f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes); 1251f595a68aSyz147064 return (buf); 1252f595a68aSyz147064 } 1253f595a68aSyz147064 1254f595a68aSyz147064 const char * 1255f595a68aSyz147064 dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf) 1256f595a68aSyz147064 { 1257f595a68aSyz147064 return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN, 1258f595a68aSyz147064 IFT_OTHER)); 1259f595a68aSyz147064 } 1260f595a68aSyz147064 1261f595a68aSyz147064 static const char * 1262f595a68aSyz147064 dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf) 1263f595a68aSyz147064 { 1264f595a68aSyz147064 char *s; 1265f595a68aSyz147064 1266f595a68aSyz147064 if (!find_name_by_val(val, vdp, cnt, &s)) 1267f595a68aSyz147064 s = ""; 1268f595a68aSyz147064 1269f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 1270f595a68aSyz147064 return (buf); 1271f595a68aSyz147064 } 1272f595a68aSyz147064 1273f595a68aSyz147064 const char * 1274f595a68aSyz147064 dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf) 1275f595a68aSyz147064 { 1276f595a68aSyz147064 return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals, 1277f595a68aSyz147064 VALCNT(secmode_vals), buf)); 1278f595a68aSyz147064 } 1279f595a68aSyz147064 1280f595a68aSyz147064 const char * 1281f595a68aSyz147064 dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf) 1282f595a68aSyz147064 { 1283f595a68aSyz147064 return (dladm_wlan_val2str((uint_t)*strength, strength_vals, 1284f595a68aSyz147064 VALCNT(strength_vals), buf)); 1285f595a68aSyz147064 } 1286f595a68aSyz147064 1287f595a68aSyz147064 const char * 1288f595a68aSyz147064 dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf) 1289f595a68aSyz147064 { 1290f595a68aSyz147064 return (dladm_wlan_val2str((uint_t)*mode, mode_vals, 1291f595a68aSyz147064 VALCNT(mode_vals), buf)); 1292f595a68aSyz147064 } 1293f595a68aSyz147064 1294f595a68aSyz147064 const char * 1295f595a68aSyz147064 dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf) 1296f595a68aSyz147064 { 1297f595a68aSyz147064 (void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2, 1298f595a68aSyz147064 (float)(*speed) / 2); 1299f595a68aSyz147064 return (buf); 1300f595a68aSyz147064 } 1301f595a68aSyz147064 1302f595a68aSyz147064 const char * 1303f595a68aSyz147064 dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf) 1304f595a68aSyz147064 { 1305f595a68aSyz147064 return (dladm_wlan_val2str((uint_t)*auth, auth_vals, 1306f595a68aSyz147064 VALCNT(auth_vals), buf)); 1307f595a68aSyz147064 } 1308f595a68aSyz147064 1309f595a68aSyz147064 const char * 1310f595a68aSyz147064 dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf) 1311f595a68aSyz147064 { 1312f595a68aSyz147064 return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals, 1313f595a68aSyz147064 VALCNT(bsstype_vals), buf)); 1314f595a68aSyz147064 } 1315f595a68aSyz147064 1316f595a68aSyz147064 const char * 1317f595a68aSyz147064 dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf) 1318f595a68aSyz147064 { 1319f595a68aSyz147064 return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals, 1320f595a68aSyz147064 VALCNT(linkstatus_vals), buf)); 1321f595a68aSyz147064 } 1322f595a68aSyz147064 1323f595a68aSyz147064 dladm_status_t 1324f595a68aSyz147064 dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid) 1325f595a68aSyz147064 { 1326f595a68aSyz147064 if (str[0] == '\0') 1327f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1328f595a68aSyz147064 1329f595a68aSyz147064 (void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN); 1330f595a68aSyz147064 return (DLADM_STATUS_OK); 1331f595a68aSyz147064 } 1332f595a68aSyz147064 1333f595a68aSyz147064 dladm_status_t 1334f595a68aSyz147064 dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid) 1335f595a68aSyz147064 { 1336f595a68aSyz147064 int len; 1337f595a68aSyz147064 uchar_t *buf; 1338f595a68aSyz147064 1339f595a68aSyz147064 buf = _link_aton(str, &len); 1340f595a68aSyz147064 if (buf == NULL) 1341f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1342f595a68aSyz147064 1343f595a68aSyz147064 if (len != DLADM_WLAN_BSSID_LEN) { 1344f595a68aSyz147064 free(buf); 1345f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1346f595a68aSyz147064 } 1347f595a68aSyz147064 1348f595a68aSyz147064 (void) memcpy(bssid->wb_bytes, buf, len); 1349f595a68aSyz147064 free(buf); 1350f595a68aSyz147064 return (DLADM_STATUS_OK); 1351f595a68aSyz147064 } 1352f595a68aSyz147064 1353f595a68aSyz147064 dladm_status_t 1354f595a68aSyz147064 dladm_wlan_str2secmode(const char *str, dladm_wlan_secmode_t *secmode) 1355f595a68aSyz147064 { 1356f595a68aSyz147064 uint_t val; 1357f595a68aSyz147064 1358f595a68aSyz147064 if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val)) 1359f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1360f595a68aSyz147064 1361f595a68aSyz147064 *secmode = (dladm_wlan_secmode_t)val; 1362f595a68aSyz147064 return (DLADM_STATUS_OK); 1363f595a68aSyz147064 } 1364f595a68aSyz147064 1365f595a68aSyz147064 dladm_status_t 1366f595a68aSyz147064 dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength) 1367f595a68aSyz147064 { 1368f595a68aSyz147064 uint_t val; 1369f595a68aSyz147064 1370f595a68aSyz147064 if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val)) 1371f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1372f595a68aSyz147064 1373f595a68aSyz147064 *strength = (dladm_wlan_strength_t)val; 1374f595a68aSyz147064 return (DLADM_STATUS_OK); 1375f595a68aSyz147064 } 1376f595a68aSyz147064 1377f595a68aSyz147064 dladm_status_t 1378f595a68aSyz147064 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode) 1379f595a68aSyz147064 { 1380f595a68aSyz147064 uint_t val; 1381f595a68aSyz147064 1382f595a68aSyz147064 if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val)) 1383f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1384f595a68aSyz147064 1385f595a68aSyz147064 *mode = (dladm_wlan_mode_t)val; 1386f595a68aSyz147064 return (DLADM_STATUS_OK); 1387f595a68aSyz147064 } 1388f595a68aSyz147064 1389f595a68aSyz147064 dladm_status_t 1390f595a68aSyz147064 dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed) 1391f595a68aSyz147064 { 1392f595a68aSyz147064 *speed = (dladm_wlan_speed_t)(atof(str) * 2); 1393f595a68aSyz147064 return (DLADM_STATUS_OK); 1394f595a68aSyz147064 } 1395f595a68aSyz147064 1396f595a68aSyz147064 dladm_status_t 1397f595a68aSyz147064 dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth) 1398f595a68aSyz147064 { 1399f595a68aSyz147064 uint_t val; 1400f595a68aSyz147064 1401f595a68aSyz147064 if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val)) 1402f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1403f595a68aSyz147064 1404f595a68aSyz147064 *auth = (dladm_wlan_auth_t)val; 1405f595a68aSyz147064 return (DLADM_STATUS_OK); 1406f595a68aSyz147064 } 1407f595a68aSyz147064 1408f595a68aSyz147064 dladm_status_t 1409f595a68aSyz147064 dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype) 1410f595a68aSyz147064 { 1411f595a68aSyz147064 uint_t val; 1412f595a68aSyz147064 1413f595a68aSyz147064 if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val)) 1414f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1415f595a68aSyz147064 1416f595a68aSyz147064 *bsstype = (dladm_wlan_bsstype_t)val; 1417f595a68aSyz147064 return (DLADM_STATUS_OK); 1418f595a68aSyz147064 } 1419f595a68aSyz147064 1420f595a68aSyz147064 dladm_status_t 1421f595a68aSyz147064 dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus) 1422f595a68aSyz147064 { 1423f595a68aSyz147064 uint_t val; 1424f595a68aSyz147064 1425f595a68aSyz147064 if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals), 1426f595a68aSyz147064 &val)) 1427f595a68aSyz147064 return (DLADM_STATUS_BADARG); 1428f595a68aSyz147064 1429f595a68aSyz147064 *linkstatus = (dladm_wlan_linkstatus_t)val; 1430f595a68aSyz147064 return (DLADM_STATUS_OK); 1431f595a68aSyz147064 } 1432f595a68aSyz147064 1433f595a68aSyz147064 static int 1434f595a68aSyz147064 do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) 1435f595a68aSyz147064 { 1436f595a68aSyz147064 int rc; 1437f595a68aSyz147064 struct strioctl stri; 1438f595a68aSyz147064 1439f595a68aSyz147064 gbuf->wldp_type = NET_802_11; 1440f595a68aSyz147064 gbuf->wldp_id = id; 1441f595a68aSyz147064 gbuf->wldp_length = len; 1442f595a68aSyz147064 1443f595a68aSyz147064 stri.ic_timout = 0; 1444f595a68aSyz147064 stri.ic_dp = (char *)gbuf; 1445f595a68aSyz147064 stri.ic_cmd = cmd; 1446f595a68aSyz147064 stri.ic_len = cmdlen; 1447f595a68aSyz147064 1448f595a68aSyz147064 if ((rc = ioctl(fd, I_STR, &stri)) != 0) { 1449f595a68aSyz147064 if (rc > 0) 1450f595a68aSyz147064 errno = rc; 1451f595a68aSyz147064 return (-1); 1452f595a68aSyz147064 } 1453f595a68aSyz147064 return (0); 1454f595a68aSyz147064 } 1455f595a68aSyz147064 1456f595a68aSyz147064 static int 1457f595a68aSyz147064 do_get_ioctl(int fd, wldp_t *gbuf, uint_t id) 1458f595a68aSyz147064 { 1459f595a68aSyz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 1460f595a68aSyz147064 return (do_ioctl(fd, gbuf, id, MAX_BUF_LEN, WLAN_GET_PARAM, 1461f595a68aSyz147064 MAX_BUF_LEN)); 1462f595a68aSyz147064 } 1463f595a68aSyz147064 1464f595a68aSyz147064 static int 1465f595a68aSyz147064 do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen) 1466f595a68aSyz147064 { 1467f595a68aSyz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 1468f595a68aSyz147064 (void) memcpy(gbuf->wldp_buf, buf, buflen); 1469f595a68aSyz147064 buflen += WIFI_BUF_OFFSET; 1470f595a68aSyz147064 return (do_ioctl(fd, gbuf, id, buflen, WLAN_SET_PARAM, buflen)); 1471f595a68aSyz147064 } 1472f595a68aSyz147064 1473f595a68aSyz147064 static int 1474f595a68aSyz147064 do_cmd_ioctl(int fd, wldp_t *gbuf, uint_t cmd) 1475f595a68aSyz147064 { 1476f595a68aSyz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 1477f595a68aSyz147064 return (do_ioctl(fd, gbuf, cmd, sizeof (wldp_t), WLAN_COMMAND, 1478f595a68aSyz147064 sizeof (wldp_t))); 1479f595a68aSyz147064 } 1480f595a68aSyz147064 1481f595a68aSyz147064 static int 1482f595a68aSyz147064 do_scan(int fd, wldp_t *gbuf) 1483f595a68aSyz147064 { 1484f595a68aSyz147064 return (do_cmd_ioctl(fd, gbuf, WL_SCAN)); 1485f595a68aSyz147064 } 1486f595a68aSyz147064 1487f595a68aSyz147064 static int 1488*a399b765Szf162725 do_disconnect(const char *link, int fd, wldp_t *gbuf) 1489f595a68aSyz147064 { 1490*a399b765Szf162725 if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf-> 1491*a399b765Szf162725 wldp_buf))->wpa_flag > 0) 1492*a399b765Szf162725 (void) wpa_instance_delete(link); 1493*a399b765Szf162725 1494f595a68aSyz147064 return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE)); 1495f595a68aSyz147064 } 1496f595a68aSyz147064 1497f595a68aSyz147064 static int 1498f595a68aSyz147064 do_get_esslist(int fd, wldp_t *gbuf) 1499f595a68aSyz147064 { 1500f595a68aSyz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 1501f595a68aSyz147064 return (do_ioctl(fd, gbuf, WL_ESS_LIST, MAX_BUF_LEN, 1502f595a68aSyz147064 WLAN_GET_PARAM, sizeof (wldp_t))); 1503f595a68aSyz147064 } 1504f595a68aSyz147064 1505f595a68aSyz147064 static int 1506f595a68aSyz147064 do_get_bssid(int fd, wldp_t *gbuf) 1507f595a68aSyz147064 { 1508f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_BSSID)); 1509f595a68aSyz147064 } 1510f595a68aSyz147064 1511f595a68aSyz147064 static int 1512f595a68aSyz147064 do_get_essid(int fd, wldp_t *gbuf) 1513f595a68aSyz147064 { 1514f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_ESSID)); 1515f595a68aSyz147064 } 1516f595a68aSyz147064 1517f595a68aSyz147064 static int 1518f595a68aSyz147064 do_get_bsstype(int fd, wldp_t *gbuf) 1519f595a68aSyz147064 { 1520f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_BSS_TYPE)); 1521f595a68aSyz147064 } 1522f595a68aSyz147064 1523f595a68aSyz147064 static int 1524f595a68aSyz147064 do_get_linkstatus(int fd, wldp_t *gbuf) 1525f595a68aSyz147064 { 1526f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_LINKSTATUS)); 1527f595a68aSyz147064 } 1528f595a68aSyz147064 1529f595a68aSyz147064 static int 1530f595a68aSyz147064 do_get_rate(int fd, wldp_t *gbuf) 1531f595a68aSyz147064 { 1532f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_DESIRED_RATES)); 1533f595a68aSyz147064 } 1534f595a68aSyz147064 1535f595a68aSyz147064 static int 1536f595a68aSyz147064 do_get_phyconf(int fd, wldp_t *gbuf) 1537f595a68aSyz147064 { 1538f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); 1539f595a68aSyz147064 } 1540f595a68aSyz147064 1541f595a68aSyz147064 static int 1542f595a68aSyz147064 do_get_powermode(int fd, wldp_t *gbuf) 1543f595a68aSyz147064 { 1544f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_POWER_MODE)); 1545f595a68aSyz147064 } 1546f595a68aSyz147064 1547f595a68aSyz147064 static int 1548f595a68aSyz147064 do_get_radio(int fd, wldp_t *gbuf) 1549f595a68aSyz147064 { 1550f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_RADIO)); 1551f595a68aSyz147064 } 1552f595a68aSyz147064 1553f595a68aSyz147064 static int 1554f595a68aSyz147064 do_get_authmode(int fd, wldp_t *gbuf) 1555f595a68aSyz147064 { 1556f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_AUTH_MODE)); 1557f595a68aSyz147064 } 1558f595a68aSyz147064 1559f595a68aSyz147064 static int 1560f595a68aSyz147064 do_get_encryption(int fd, wldp_t *gbuf) 1561f595a68aSyz147064 { 1562f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION)); 1563f595a68aSyz147064 } 1564f595a68aSyz147064 1565f595a68aSyz147064 static int 1566f595a68aSyz147064 do_get_signal(int fd, wldp_t *gbuf) 1567f595a68aSyz147064 { 1568f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_RSSI)); 1569f595a68aSyz147064 } 1570f595a68aSyz147064 1571f595a68aSyz147064 static int 1572f595a68aSyz147064 do_get_mode(int fd, wldp_t *gbuf) 1573f595a68aSyz147064 { 1574f595a68aSyz147064 return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); 1575f595a68aSyz147064 } 1576f595a68aSyz147064 1577f595a68aSyz147064 static dladm_status_t 1578f595a68aSyz147064 do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1579f595a68aSyz147064 { 1580f595a68aSyz147064 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 1581f595a68aSyz147064 uint_t cnt = wrp->wl_rates_num; 1582f595a68aSyz147064 uint_t i; 1583f595a68aSyz147064 1584f595a68aSyz147064 if (cnt > *val_cnt) 1585f595a68aSyz147064 return (DLADM_STATUS_TOOSMALL); 1586f595a68aSyz147064 if (wrp->wl_rates_rates[0] == 0) { 1587f595a68aSyz147064 prop_val[0][0] = '\0'; 1588f595a68aSyz147064 *val_cnt = 1; 1589f595a68aSyz147064 return (DLADM_STATUS_OK); 1590f595a68aSyz147064 } 1591f595a68aSyz147064 1592f595a68aSyz147064 for (i = 0; i < cnt; i++) { 1593f595a68aSyz147064 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1594f595a68aSyz147064 wrp->wl_rates_rates[i] % 2, 1595f595a68aSyz147064 (float)wrp->wl_rates_rates[i] / 2); 1596f595a68aSyz147064 } 1597f595a68aSyz147064 *val_cnt = cnt; 1598f595a68aSyz147064 return (DLADM_STATUS_OK); 1599f595a68aSyz147064 } 1600f595a68aSyz147064 1601f595a68aSyz147064 static dladm_status_t 1602f595a68aSyz147064 do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1603f595a68aSyz147064 { 1604f595a68aSyz147064 if (do_get_rate(fd, gbuf) < 0) 1605f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1606f595a68aSyz147064 1607f595a68aSyz147064 return (do_get_rate_common(gbuf, prop_val, val_cnt)); 1608f595a68aSyz147064 } 1609f595a68aSyz147064 1610f595a68aSyz147064 static dladm_status_t 1611f595a68aSyz147064 do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1612f595a68aSyz147064 { 1613f595a68aSyz147064 if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0) 1614f595a68aSyz147064 return (DLADM_STATUS_FAILED); 1615f595a68aSyz147064 1616f595a68aSyz147064 return (do_get_rate_common(gbuf, prop_val, val_cnt)); 1617f595a68aSyz147064 } 1618f595a68aSyz147064 1619f595a68aSyz147064 static dladm_status_t 1620f595a68aSyz147064 do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1621f595a68aSyz147064 { 1622f595a68aSyz147064 uint32_t channel; 1623f595a68aSyz147064 1624f595a68aSyz147064 if (do_get_phyconf(fd, gbuf) < 0) 1625f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1626f595a68aSyz147064 1627f595a68aSyz147064 if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel)) 1628f595a68aSyz147064 return (DLADM_STATUS_NOTFOUND); 1629f595a68aSyz147064 1630f595a68aSyz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1631f595a68aSyz147064 *val_cnt = 1; 1632f595a68aSyz147064 1633f595a68aSyz147064 return (DLADM_STATUS_OK); 1634f595a68aSyz147064 } 1635f595a68aSyz147064 1636f595a68aSyz147064 static dladm_status_t 1637f595a68aSyz147064 do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1638f595a68aSyz147064 { 1639f595a68aSyz147064 wl_ps_mode_t *mode; 1640f595a68aSyz147064 const char *s; 1641f595a68aSyz147064 1642f595a68aSyz147064 if (do_get_powermode(fd, gbuf) < 0) 1643f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1644f595a68aSyz147064 1645f595a68aSyz147064 mode = (wl_ps_mode_t *)(gbuf->wldp_buf); 1646f595a68aSyz147064 switch (mode->wl_ps_mode) { 1647f595a68aSyz147064 case WL_PM_AM: 1648f595a68aSyz147064 s = "off"; 1649f595a68aSyz147064 break; 1650f595a68aSyz147064 case WL_PM_MPS: 1651f595a68aSyz147064 s = "max"; 1652f595a68aSyz147064 break; 1653f595a68aSyz147064 case WL_PM_FAST: 1654f595a68aSyz147064 s = "fast"; 1655f595a68aSyz147064 break; 1656f595a68aSyz147064 default: 1657f595a68aSyz147064 return (DLADM_STATUS_NOTFOUND); 1658f595a68aSyz147064 } 1659f595a68aSyz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1660f595a68aSyz147064 *val_cnt = 1; 1661f595a68aSyz147064 1662f595a68aSyz147064 return (DLADM_STATUS_OK); 1663f595a68aSyz147064 } 1664f595a68aSyz147064 1665f595a68aSyz147064 static dladm_status_t 1666f595a68aSyz147064 do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) 1667f595a68aSyz147064 { 1668f595a68aSyz147064 wl_radio_t radio; 1669f595a68aSyz147064 const char *s; 1670f595a68aSyz147064 1671f595a68aSyz147064 if (do_get_radio(fd, gbuf) < 0) 1672f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1673f595a68aSyz147064 1674f595a68aSyz147064 radio = *(wl_radio_t *)(gbuf->wldp_buf); 1675f595a68aSyz147064 switch (radio) { 1676f595a68aSyz147064 case B_TRUE: 1677f595a68aSyz147064 s = "on"; 1678f595a68aSyz147064 break; 1679f595a68aSyz147064 case B_FALSE: 1680f595a68aSyz147064 s = "off"; 1681f595a68aSyz147064 break; 1682f595a68aSyz147064 default: 1683f595a68aSyz147064 return (DLADM_STATUS_NOTFOUND); 1684f595a68aSyz147064 } 1685f595a68aSyz147064 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1686f595a68aSyz147064 *val_cnt = 1; 1687f595a68aSyz147064 1688f595a68aSyz147064 return (DLADM_STATUS_OK); 1689f595a68aSyz147064 } 1690f595a68aSyz147064 1691f595a68aSyz147064 static int 1692f595a68aSyz147064 do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) 1693f595a68aSyz147064 { 1694f595a68aSyz147064 wl_bss_type_t ibsstype; 1695f595a68aSyz147064 1696f595a68aSyz147064 switch (*bsstype) { 1697f595a68aSyz147064 case DLADM_WLAN_BSSTYPE_BSS: 1698f595a68aSyz147064 ibsstype = WL_BSS_BSS; 1699f595a68aSyz147064 break; 1700f595a68aSyz147064 case DLADM_WLAN_BSSTYPE_IBSS: 1701f595a68aSyz147064 ibsstype = WL_BSS_IBSS; 1702f595a68aSyz147064 break; 1703f595a68aSyz147064 default: 1704f595a68aSyz147064 ibsstype = WL_BSS_ANY; 1705f595a68aSyz147064 break; 1706f595a68aSyz147064 } 1707f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype, 1708f595a68aSyz147064 sizeof (ibsstype))); 1709f595a68aSyz147064 } 1710f595a68aSyz147064 1711f595a68aSyz147064 static int 1712f595a68aSyz147064 do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) 1713f595a68aSyz147064 { 1714f595a68aSyz147064 wl_authmode_t auth_mode; 1715f595a68aSyz147064 1716f595a68aSyz147064 switch (*auth) { 1717f595a68aSyz147064 case DLADM_WLAN_AUTH_OPEN: 1718f595a68aSyz147064 auth_mode = WL_OPENSYSTEM; 1719f595a68aSyz147064 break; 1720f595a68aSyz147064 case DLADM_WLAN_AUTH_SHARED: 1721f595a68aSyz147064 auth_mode = WL_SHAREDKEY; 1722f595a68aSyz147064 break; 1723f595a68aSyz147064 default: 1724f595a68aSyz147064 return (-1); 1725f595a68aSyz147064 } 1726f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode, 1727f595a68aSyz147064 sizeof (auth_mode))); 1728f595a68aSyz147064 } 1729f595a68aSyz147064 1730f595a68aSyz147064 static int 1731f595a68aSyz147064 do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) 1732f595a68aSyz147064 { 1733f595a68aSyz147064 wl_encryption_t encryption; 1734f595a68aSyz147064 1735f595a68aSyz147064 switch (*secmode) { 1736f595a68aSyz147064 case DLADM_WLAN_SECMODE_NONE: 1737f595a68aSyz147064 encryption = WL_NOENCRYPTION; 1738f595a68aSyz147064 break; 1739f595a68aSyz147064 case DLADM_WLAN_SECMODE_WEP: 1740f595a68aSyz147064 encryption = WL_ENC_WEP; 1741f595a68aSyz147064 break; 1742*a399b765Szf162725 case DLADM_WLAN_SECMODE_WPA: 1743*a399b765Szf162725 return (0); 1744f595a68aSyz147064 default: 1745f595a68aSyz147064 return (-1); 1746f595a68aSyz147064 } 1747f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption, 1748f595a68aSyz147064 sizeof (encryption))); 1749f595a68aSyz147064 } 1750f595a68aSyz147064 1751f595a68aSyz147064 static int 1752*a399b765Szf162725 do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, 1753f595a68aSyz147064 uint_t key_count) 1754f595a68aSyz147064 { 1755f595a68aSyz147064 int i; 1756f595a68aSyz147064 wl_wep_key_t *wkp; 1757f595a68aSyz147064 wl_wep_key_tab_t wepkey_tab; 1758*a399b765Szf162725 dladm_wlan_key_t *kp; 1759f595a68aSyz147064 1760f595a68aSyz147064 if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL) 1761f595a68aSyz147064 return (-1); 1762f595a68aSyz147064 1763f595a68aSyz147064 (void) memset(wepkey_tab, 0, sizeof (wepkey_tab)); 1764f595a68aSyz147064 for (i = 0; i < MAX_NWEPKEYS; i++) 1765f595a68aSyz147064 wepkey_tab[i].wl_wep_operation = WL_NUL; 1766f595a68aSyz147064 1767f595a68aSyz147064 for (i = 0; i < key_count; i++) { 1768f595a68aSyz147064 kp = &keys[i]; 1769f595a68aSyz147064 if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS) 1770f595a68aSyz147064 return (-1); 1771f595a68aSyz147064 if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN && 1772f595a68aSyz147064 kp->wk_len != DLADM_WLAN_WEPKEY128_LEN) 1773f595a68aSyz147064 return (-1); 1774f595a68aSyz147064 1775f595a68aSyz147064 wkp = &wepkey_tab[kp->wk_idx - 1]; 1776f595a68aSyz147064 wkp->wl_wep_operation = WL_ADD; 1777f595a68aSyz147064 wkp->wl_wep_length = kp->wk_len; 1778f595a68aSyz147064 (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len); 1779f595a68aSyz147064 } 1780f595a68aSyz147064 1781f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab, 1782f595a68aSyz147064 sizeof (wepkey_tab))); 1783f595a68aSyz147064 } 1784f595a68aSyz147064 1785f595a68aSyz147064 static int 1786f595a68aSyz147064 do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) 1787f595a68aSyz147064 { 1788f595a68aSyz147064 wl_essid_t iessid; 1789f595a68aSyz147064 1790f595a68aSyz147064 (void) memset(&iessid, 0, sizeof (essid)); 1791f595a68aSyz147064 1792f595a68aSyz147064 if (essid != NULL && essid->we_bytes[0] != '\0') { 1793f595a68aSyz147064 iessid.wl_essid_length = strlen(essid->we_bytes); 1794f595a68aSyz147064 (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes, 1795f595a68aSyz147064 sizeof (iessid.wl_essid_essid)); 1796f595a68aSyz147064 } else { 1797f595a68aSyz147064 return (-1); 1798f595a68aSyz147064 } 1799f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_ESSID, &iessid, sizeof (iessid))); 1800f595a68aSyz147064 } 1801f595a68aSyz147064 1802f595a68aSyz147064 /* ARGSUSED */ 1803f595a68aSyz147064 static dladm_status_t 1804f595a68aSyz147064 do_check_rate(int fd, wldp_t *gbuf, prop_desc_t *pdp, char **prop_val, 1805f595a68aSyz147064 uint_t val_cnt, val_desc_t **vdpp) 1806f595a68aSyz147064 { 1807f595a68aSyz147064 int i; 1808f595a68aSyz147064 uint_t modval_cnt = MAX_SUPPORT_RATES; 1809f595a68aSyz147064 char *buf, **modval; 1810f595a68aSyz147064 dladm_status_t status; 1811f595a68aSyz147064 val_desc_t *vdp = NULL; 1812f595a68aSyz147064 1813f595a68aSyz147064 if (val_cnt != 1) 1814f595a68aSyz147064 return (DLADM_STATUS_BADVALCNT); 1815f595a68aSyz147064 1816f595a68aSyz147064 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * MAX_SUPPORT_RATES); 1817f595a68aSyz147064 if (buf == NULL) 1818f595a68aSyz147064 goto done; 1819f595a68aSyz147064 1820f595a68aSyz147064 modval = (char **)(void *)buf; 1821f595a68aSyz147064 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1822f595a68aSyz147064 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1823f595a68aSyz147064 i * DLADM_STRSIZE; 1824f595a68aSyz147064 } 1825f595a68aSyz147064 1826f595a68aSyz147064 status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt); 1827f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1828f595a68aSyz147064 goto done; 1829f595a68aSyz147064 1830f595a68aSyz147064 vdp = malloc(sizeof (val_desc_t)); 1831f595a68aSyz147064 if (vdp == NULL) { 1832f595a68aSyz147064 status = DLADM_STATUS_NOMEM; 1833f595a68aSyz147064 goto done; 1834f595a68aSyz147064 } 1835f595a68aSyz147064 1836f595a68aSyz147064 for (i = 0; i < modval_cnt; i++) { 1837f595a68aSyz147064 if (strcasecmp(*prop_val, modval[i]) == 0) { 1838f595a68aSyz147064 vdp->vd_val = (uint_t)(atof(*prop_val) * 2); 1839f595a68aSyz147064 status = DLADM_STATUS_OK; 1840f595a68aSyz147064 *vdpp = vdp; 1841f595a68aSyz147064 vdp = NULL; 1842f595a68aSyz147064 break; 1843f595a68aSyz147064 } 1844f595a68aSyz147064 } 1845f595a68aSyz147064 if (i == modval_cnt) 1846f595a68aSyz147064 status = DLADM_STATUS_BADVAL; 1847f595a68aSyz147064 done: 1848f595a68aSyz147064 free(buf); 1849f595a68aSyz147064 free(vdp); 1850f595a68aSyz147064 return (status); 1851f595a68aSyz147064 } 1852f595a68aSyz147064 1853f595a68aSyz147064 static dladm_status_t 1854f595a68aSyz147064 do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 1855f595a68aSyz147064 { 1856f595a68aSyz147064 dladm_wlan_rates_t rates; 1857f595a68aSyz147064 1858f595a68aSyz147064 if (val_cnt != 1) 1859f595a68aSyz147064 return (DLADM_STATUS_BADVALCNT); 1860f595a68aSyz147064 1861f595a68aSyz147064 rates.wr_cnt = 1; 1862f595a68aSyz147064 rates.wr_rates[0] = vdp[0].vd_val; 1863f595a68aSyz147064 1864f595a68aSyz147064 if (do_set_rate(fd, gbuf, &rates) < 0) 1865f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1866f595a68aSyz147064 1867f595a68aSyz147064 return (DLADM_STATUS_OK); 1868f595a68aSyz147064 } 1869f595a68aSyz147064 1870f595a68aSyz147064 static int 1871f595a68aSyz147064 do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates) 1872f595a68aSyz147064 { 1873f595a68aSyz147064 int i; 1874f595a68aSyz147064 uint_t len; 1875f595a68aSyz147064 wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; 1876f595a68aSyz147064 1877f595a68aSyz147064 (void) memset(gbuf, 0, MAX_BUF_LEN); 1878f595a68aSyz147064 1879f595a68aSyz147064 for (i = 0; i < rates->wr_cnt; i++) 1880f595a68aSyz147064 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1881f595a68aSyz147064 wrp->wl_rates_num = rates->wr_cnt; 1882f595a68aSyz147064 1883f595a68aSyz147064 len = offsetof(wl_rates_t, wl_rates_rates) + 1884f595a68aSyz147064 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1885f595a68aSyz147064 return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len)); 1886f595a68aSyz147064 } 1887f595a68aSyz147064 1888f595a68aSyz147064 /* ARGSUSED */ 1889f595a68aSyz147064 static dladm_status_t 1890f595a68aSyz147064 do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 1891f595a68aSyz147064 { 1892f595a68aSyz147064 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1893f595a68aSyz147064 1894f595a68aSyz147064 if (do_set_powermode(fd, gbuf, &powermode) < 0) 1895f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1896f595a68aSyz147064 1897f595a68aSyz147064 return (DLADM_STATUS_OK); 1898f595a68aSyz147064 } 1899f595a68aSyz147064 1900f595a68aSyz147064 static int 1901f595a68aSyz147064 do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm) 1902f595a68aSyz147064 { 1903f595a68aSyz147064 wl_ps_mode_t ps_mode; 1904f595a68aSyz147064 1905f595a68aSyz147064 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1906f595a68aSyz147064 1907f595a68aSyz147064 switch (*pm) { 1908f595a68aSyz147064 case DLADM_WLAN_PM_OFF: 1909f595a68aSyz147064 ps_mode.wl_ps_mode = WL_PM_AM; 1910f595a68aSyz147064 break; 1911f595a68aSyz147064 case DLADM_WLAN_PM_MAX: 1912f595a68aSyz147064 ps_mode.wl_ps_mode = WL_PM_MPS; 1913f595a68aSyz147064 break; 1914f595a68aSyz147064 case DLADM_WLAN_PM_FAST: 1915f595a68aSyz147064 ps_mode.wl_ps_mode = WL_PM_FAST; 1916f595a68aSyz147064 break; 1917f595a68aSyz147064 default: 1918f595a68aSyz147064 return (-1); 1919f595a68aSyz147064 } 1920f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode, 1921f595a68aSyz147064 sizeof (ps_mode))); 1922f595a68aSyz147064 } 1923f595a68aSyz147064 1924f595a68aSyz147064 /* ARGSUSED */ 1925f595a68aSyz147064 static dladm_status_t 1926f595a68aSyz147064 do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) 1927f595a68aSyz147064 { 1928f595a68aSyz147064 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 1929f595a68aSyz147064 1930f595a68aSyz147064 if (do_set_radio(fd, gbuf, &radio) < 0) 1931f595a68aSyz147064 return (dladm_wlan_wlresult2status(gbuf)); 1932f595a68aSyz147064 1933f595a68aSyz147064 return (DLADM_STATUS_OK); 1934f595a68aSyz147064 } 1935f595a68aSyz147064 1936f595a68aSyz147064 static int 1937f595a68aSyz147064 do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio) 1938f595a68aSyz147064 { 1939f595a68aSyz147064 wl_radio_t r; 1940f595a68aSyz147064 1941f595a68aSyz147064 switch (*radio) { 1942f595a68aSyz147064 case DLADM_WLAN_RADIO_ON: 1943f595a68aSyz147064 r = B_TRUE; 1944f595a68aSyz147064 break; 1945f595a68aSyz147064 case DLADM_WLAN_RADIO_OFF: 1946f595a68aSyz147064 r = B_FALSE; 1947f595a68aSyz147064 break; 1948f595a68aSyz147064 default: 1949f595a68aSyz147064 return (-1); 1950f595a68aSyz147064 } 1951f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r))); 1952f595a68aSyz147064 } 1953f595a68aSyz147064 1954f595a68aSyz147064 static int 1955f595a68aSyz147064 do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel) 1956f595a68aSyz147064 { 1957f595a68aSyz147064 wl_phy_conf_t phy_conf; 1958f595a68aSyz147064 1959f595a68aSyz147064 if (*channel > MAX_CHANNEL_NUM) 1960f595a68aSyz147064 return (-1); 1961f595a68aSyz147064 1962f595a68aSyz147064 (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); 1963f595a68aSyz147064 phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; 1964f595a68aSyz147064 1965f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf, 1966f595a68aSyz147064 sizeof (phy_conf))); 1967f595a68aSyz147064 } 1968f595a68aSyz147064 1969f595a68aSyz147064 static int 1970f595a68aSyz147064 do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss) 1971f595a68aSyz147064 { 1972f595a68aSyz147064 wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); 1973f595a68aSyz147064 1974f595a68aSyz147064 return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr))); 1975f595a68aSyz147064 } 1976f595a68aSyz147064 1977f595a68aSyz147064 static void 1978f595a68aSyz147064 generate_essid(dladm_wlan_essid_t *essid) 1979f595a68aSyz147064 { 1980f595a68aSyz147064 srandom(gethrtime()); 1981f595a68aSyz147064 (void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d", 1982f595a68aSyz147064 random()); 1983f595a68aSyz147064 } 1984*a399b765Szf162725 1985*a399b765Szf162725 static int 1986*a399b765Szf162725 do_get_capability(int fd, wldp_t *gbuf) 1987*a399b765Szf162725 { 1988*a399b765Szf162725 return (do_get_ioctl(fd, gbuf, WL_CAPABILITY)); 1989*a399b765Szf162725 } 1990*a399b765Szf162725 1991*a399b765Szf162725 static int 1992*a399b765Szf162725 do_get_wpamode(int fd, wldp_t *gbuf) 1993*a399b765Szf162725 { 1994*a399b765Szf162725 return (do_get_ioctl(fd, gbuf, WL_WPA)); 1995*a399b765Szf162725 } 1996*a399b765Szf162725 1997*a399b765Szf162725 static dladm_status_t 1998*a399b765Szf162725 ioctl_get(const char *link, int id, void *gbuf) 1999*a399b765Szf162725 { 2000*a399b765Szf162725 int fd; 2001*a399b765Szf162725 2002*a399b765Szf162725 if ((fd = open_link(link)) < 0) 2003*a399b765Szf162725 return (DLADM_STATUS_LINKINVAL); 2004*a399b765Szf162725 (void) do_get_ioctl(fd, gbuf, id); 2005*a399b765Szf162725 2006*a399b765Szf162725 (void) close(fd); 2007*a399b765Szf162725 return (dladm_wlan_wlresult2status(gbuf)); 2008*a399b765Szf162725 } 2009*a399b765Szf162725 2010*a399b765Szf162725 static dladm_status_t 2011*a399b765Szf162725 ioctl_set(const char *link, int id, void *buf, uint_t buflen) 2012*a399b765Szf162725 { 2013*a399b765Szf162725 int fd; 2014*a399b765Szf162725 wldp_t *gbuf; 2015*a399b765Szf162725 dladm_status_t status; 2016*a399b765Szf162725 2017*a399b765Szf162725 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2018*a399b765Szf162725 return (DLADM_STATUS_NOMEM); 2019*a399b765Szf162725 2020*a399b765Szf162725 if ((fd = open_link(link)) < 0) 2021*a399b765Szf162725 return (DLADM_STATUS_LINKINVAL); 2022*a399b765Szf162725 (void) do_set_ioctl(fd, gbuf, id, buf, buflen); 2023*a399b765Szf162725 2024*a399b765Szf162725 (void) close(fd); 2025*a399b765Szf162725 status = dladm_wlan_wlresult2status(gbuf); 2026*a399b765Szf162725 free(gbuf); 2027*a399b765Szf162725 2028*a399b765Szf162725 return (status); 2029*a399b765Szf162725 } 2030*a399b765Szf162725 2031*a399b765Szf162725 dladm_status_t 2032*a399b765Szf162725 dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, 2033*a399b765Szf162725 uint_t *estot) 2034*a399b765Szf162725 { 2035*a399b765Szf162725 int i, n; 2036*a399b765Szf162725 wldp_t *gbuf; 2037*a399b765Szf162725 wl_wpa_ess_t *es; 2038*a399b765Szf162725 dladm_status_t status; 2039*a399b765Szf162725 2040*a399b765Szf162725 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2041*a399b765Szf162725 return (DLADM_STATUS_NOMEM); 2042*a399b765Szf162725 2043*a399b765Szf162725 status = ioctl_get(link, WL_SCANRESULTS, gbuf); 2044*a399b765Szf162725 2045*a399b765Szf162725 if (status == DLADM_STATUS_OK) { 2046*a399b765Szf162725 es = (wl_wpa_ess_t *)(gbuf->wldp_buf); 2047*a399b765Szf162725 n = (es->count > escnt) ? escnt : es->count; 2048*a399b765Szf162725 for (i = 0; i < n; i ++) { 2049*a399b765Szf162725 (void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid, 2050*a399b765Szf162725 DLADM_WLAN_BSSID_LEN); 2051*a399b765Szf162725 sr[i].we_ssid_len = es->ess[i].ssid_len; 2052*a399b765Szf162725 (void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid, 2053*a399b765Szf162725 es->ess[i].ssid_len); 2054*a399b765Szf162725 sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len; 2055*a399b765Szf162725 (void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie, 2056*a399b765Szf162725 es->ess[i].wpa_ie_len); 2057*a399b765Szf162725 sr[i].we_freq = es->ess[i].freq; 2058*a399b765Szf162725 } 2059*a399b765Szf162725 *estot = n; 2060*a399b765Szf162725 } 2061*a399b765Szf162725 2062*a399b765Szf162725 free(gbuf); 2063*a399b765Szf162725 return (status); 2064*a399b765Szf162725 } 2065*a399b765Szf162725 2066*a399b765Szf162725 dladm_status_t 2067*a399b765Szf162725 dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, 2068*a399b765Szf162725 uint_t wpa_ie_len) 2069*a399b765Szf162725 { 2070*a399b765Szf162725 wl_wpa_ie_t *ie; 2071*a399b765Szf162725 uint_t len; 2072*a399b765Szf162725 dladm_status_t status; 2073*a399b765Szf162725 2074*a399b765Szf162725 if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN) 2075*a399b765Szf162725 return (DLADM_STATUS_BADARG); 2076*a399b765Szf162725 len = sizeof (wl_wpa_ie_t) + wpa_ie_len; 2077*a399b765Szf162725 ie = malloc(len); 2078*a399b765Szf162725 if (ie == NULL) 2079*a399b765Szf162725 return (DLADM_STATUS_NOMEM); 2080*a399b765Szf162725 2081*a399b765Szf162725 (void) memset(ie, 0, len); 2082*a399b765Szf162725 ie->wpa_ie_len = wpa_ie_len; 2083*a399b765Szf162725 (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); 2084*a399b765Szf162725 2085*a399b765Szf162725 status = ioctl_set(link, WL_SETOPTIE, ie, len); 2086*a399b765Szf162725 free(ie); 2087*a399b765Szf162725 2088*a399b765Szf162725 return (status); 2089*a399b765Szf162725 } 2090*a399b765Szf162725 2091*a399b765Szf162725 dladm_status_t 2092*a399b765Szf162725 dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag) 2093*a399b765Szf162725 { 2094*a399b765Szf162725 wl_wpa_t wpa; 2095*a399b765Szf162725 2096*a399b765Szf162725 wpa.wpa_flag = flag; 2097*a399b765Szf162725 return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t))); 2098*a399b765Szf162725 } 2099*a399b765Szf162725 2100*a399b765Szf162725 dladm_status_t 2101*a399b765Szf162725 dladm_wlan_wpa_del_key(const char *link, uint_t key_idx, 2102*a399b765Szf162725 const dladm_wlan_bssid_t *addr) 2103*a399b765Szf162725 { 2104*a399b765Szf162725 wl_del_key_t wk; 2105*a399b765Szf162725 2106*a399b765Szf162725 wk.idk_keyix = key_idx; 2107*a399b765Szf162725 if (addr != NULL) 2108*a399b765Szf162725 (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, 2109*a399b765Szf162725 DLADM_WLAN_BSSID_LEN); 2110*a399b765Szf162725 2111*a399b765Szf162725 return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t))); 2112*a399b765Szf162725 } 2113*a399b765Szf162725 2114*a399b765Szf162725 dladm_status_t 2115*a399b765Szf162725 dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, 2116*a399b765Szf162725 const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, 2117*a399b765Szf162725 uint_t key_idx, uint8_t *key, uint_t key_len) 2118*a399b765Szf162725 { 2119*a399b765Szf162725 wl_key_t wk; 2120*a399b765Szf162725 2121*a399b765Szf162725 (void) memset(&wk, 0, sizeof (wl_key_t)); 2122*a399b765Szf162725 switch (cipher) { 2123*a399b765Szf162725 case DLADM_WLAN_CIPHER_WEP: 2124*a399b765Szf162725 wk.ik_type = IEEE80211_CIPHER_WEP; 2125*a399b765Szf162725 break; 2126*a399b765Szf162725 case DLADM_WLAN_CIPHER_TKIP: 2127*a399b765Szf162725 wk.ik_type = IEEE80211_CIPHER_TKIP; 2128*a399b765Szf162725 break; 2129*a399b765Szf162725 case DLADM_WLAN_CIPHER_AES_OCB: 2130*a399b765Szf162725 wk.ik_type = IEEE80211_CIPHER_AES_OCB; 2131*a399b765Szf162725 break; 2132*a399b765Szf162725 case DLADM_WLAN_CIPHER_AES_CCM: 2133*a399b765Szf162725 wk.ik_type = IEEE80211_CIPHER_AES_CCM; 2134*a399b765Szf162725 break; 2135*a399b765Szf162725 case DLADM_WLAN_CIPHER_CKIP: 2136*a399b765Szf162725 wk.ik_type = IEEE80211_CIPHER_CKIP; 2137*a399b765Szf162725 break; 2138*a399b765Szf162725 case DLADM_WLAN_CIPHER_NONE: 2139*a399b765Szf162725 wk.ik_type = IEEE80211_CIPHER_NONE; 2140*a399b765Szf162725 break; 2141*a399b765Szf162725 default: 2142*a399b765Szf162725 return (DLADM_STATUS_BADARG); 2143*a399b765Szf162725 } 2144*a399b765Szf162725 wk.ik_flags = IEEE80211_KEY_RECV; 2145*a399b765Szf162725 if (set_tx) { 2146*a399b765Szf162725 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; 2147*a399b765Szf162725 (void) memcpy(wk.ik_macaddr, addr->wb_bytes, 2148*a399b765Szf162725 DLADM_WLAN_BSSID_LEN); 2149*a399b765Szf162725 } else 2150*a399b765Szf162725 (void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN); 2151*a399b765Szf162725 wk.ik_keyix = key_idx; 2152*a399b765Szf162725 wk.ik_keylen = key_len; 2153*a399b765Szf162725 (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ 2154*a399b765Szf162725 (void) memcpy(wk.ik_keydata, key, key_len); 2155*a399b765Szf162725 2156*a399b765Szf162725 return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t))); 2157*a399b765Szf162725 } 2158*a399b765Szf162725 2159*a399b765Szf162725 dladm_status_t 2160*a399b765Szf162725 dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, 2161*a399b765Szf162725 dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) 2162*a399b765Szf162725 { 2163*a399b765Szf162725 wl_mlme_t mlme; 2164*a399b765Szf162725 2165*a399b765Szf162725 (void) memset(&mlme, 0, sizeof (wl_mlme_t)); 2166*a399b765Szf162725 switch (op) { 2167*a399b765Szf162725 case DLADM_WLAN_MLME_ASSOC: 2168*a399b765Szf162725 mlme.im_op = IEEE80211_MLME_ASSOC; 2169*a399b765Szf162725 break; 2170*a399b765Szf162725 case DLADM_WLAN_MLME_DISASSOC: 2171*a399b765Szf162725 mlme.im_op = IEEE80211_MLME_DISASSOC; 2172*a399b765Szf162725 break; 2173*a399b765Szf162725 default: 2174*a399b765Szf162725 return (DLADM_STATUS_BADARG); 2175*a399b765Szf162725 } 2176*a399b765Szf162725 mlme.im_reason = reason; 2177*a399b765Szf162725 if (bssid != NULL) 2178*a399b765Szf162725 (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, 2179*a399b765Szf162725 DLADM_WLAN_BSSID_LEN); 2180*a399b765Szf162725 2181*a399b765Szf162725 return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t))); 2182*a399b765Szf162725 } 2183*a399b765Szf162725 2184*a399b765Szf162725 /* 2185*a399b765Szf162725 * routines of create instance 2186*a399b765Szf162725 */ 2187*a399b765Szf162725 static scf_propertygroup_t * 2188*a399b765Szf162725 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, 2189*a399b765Szf162725 const char *pg_name, const char *pg_type) 2190*a399b765Szf162725 { 2191*a399b765Szf162725 scf_propertygroup_t *pg; 2192*a399b765Szf162725 2193*a399b765Szf162725 pg = scf_pg_create(handle); 2194*a399b765Szf162725 if (pg == NULL) 2195*a399b765Szf162725 return (NULL); 2196*a399b765Szf162725 2197*a399b765Szf162725 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) { 2198*a399b765Szf162725 scf_pg_destroy(pg); 2199*a399b765Szf162725 return (NULL); 2200*a399b765Szf162725 } 2201*a399b765Szf162725 2202*a399b765Szf162725 return (pg); 2203*a399b765Szf162725 } 2204*a399b765Szf162725 2205*a399b765Szf162725 static int 2206*a399b765Szf162725 add_new_property(scf_handle_t *handle, const char *prop_name, 2207*a399b765Szf162725 scf_type_t type, const char *val, scf_transaction_t *tx) 2208*a399b765Szf162725 { 2209*a399b765Szf162725 scf_value_t *value = NULL; 2210*a399b765Szf162725 scf_transaction_entry_t *entry = NULL; 2211*a399b765Szf162725 2212*a399b765Szf162725 entry = scf_entry_create(handle); 2213*a399b765Szf162725 if (entry == NULL) 2214*a399b765Szf162725 goto out; 2215*a399b765Szf162725 2216*a399b765Szf162725 value = scf_value_create(handle); 2217*a399b765Szf162725 if (value == NULL) 2218*a399b765Szf162725 goto out; 2219*a399b765Szf162725 2220*a399b765Szf162725 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) 2221*a399b765Szf162725 goto out; 2222*a399b765Szf162725 2223*a399b765Szf162725 if (scf_value_set_from_string(value, type, val) != 0) 2224*a399b765Szf162725 goto out; 2225*a399b765Szf162725 2226*a399b765Szf162725 if (scf_entry_add_value(entry, value) != 0) 2227*a399b765Szf162725 goto out; 2228*a399b765Szf162725 2229*a399b765Szf162725 return (DLADM_WLAN_SVC_SUCCESS); 2230*a399b765Szf162725 2231*a399b765Szf162725 out: 2232*a399b765Szf162725 if (value != NULL) 2233*a399b765Szf162725 scf_value_destroy(value); 2234*a399b765Szf162725 if (entry != NULL) 2235*a399b765Szf162725 scf_entry_destroy(entry); 2236*a399b765Szf162725 2237*a399b765Szf162725 return (DLADM_WLAN_SVC_FAILURE); 2238*a399b765Szf162725 } 2239*a399b765Szf162725 2240*a399b765Szf162725 /* 2241*a399b765Szf162725 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 2242*a399b765Szf162725 */ 2243*a399b765Szf162725 static int 2244*a399b765Szf162725 add_pg_method(scf_handle_t *handle, scf_instance_t *instance, 2245*a399b765Szf162725 const char *pg_name, const char *flags) 2246*a399b765Szf162725 { 2247*a399b765Szf162725 int rv, size; 2248*a399b765Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2249*a399b765Szf162725 char *command = NULL; 2250*a399b765Szf162725 scf_transaction_t *tran = NULL; 2251*a399b765Szf162725 scf_propertygroup_t *pg; 2252*a399b765Szf162725 2253*a399b765Szf162725 pg = add_property_group_to_instance(handle, instance, 2254*a399b765Szf162725 pg_name, SCF_GROUP_METHOD); 2255*a399b765Szf162725 if (pg == NULL) 2256*a399b765Szf162725 goto out; 2257*a399b765Szf162725 2258*a399b765Szf162725 tran = scf_transaction_create(handle); 2259*a399b765Szf162725 if (tran == NULL) 2260*a399b765Szf162725 goto out; 2261*a399b765Szf162725 2262*a399b765Szf162725 size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; 2263*a399b765Szf162725 command = malloc(size); 2264*a399b765Szf162725 if (command == NULL) { 2265*a399b765Szf162725 status = DLADM_WLAN_SVC_APP_FAILURE; 2266*a399b765Szf162725 goto out; 2267*a399b765Szf162725 } 2268*a399b765Szf162725 (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); 2269*a399b765Szf162725 2270*a399b765Szf162725 do { 2271*a399b765Szf162725 if (scf_transaction_start(tran, pg) != 0) 2272*a399b765Szf162725 goto out; 2273*a399b765Szf162725 2274*a399b765Szf162725 if (add_new_property(handle, SCF_PROPERTY_EXEC, 2275*a399b765Szf162725 SCF_TYPE_ASTRING, command, tran) != 2276*a399b765Szf162725 DLADM_WLAN_SVC_SUCCESS) { 2277*a399b765Szf162725 goto out; 2278*a399b765Szf162725 } 2279*a399b765Szf162725 2280*a399b765Szf162725 rv = scf_transaction_commit(tran); 2281*a399b765Szf162725 switch (rv) { 2282*a399b765Szf162725 case 1: 2283*a399b765Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2284*a399b765Szf162725 goto out; 2285*a399b765Szf162725 case 0: 2286*a399b765Szf162725 scf_transaction_destroy_children(tran); 2287*a399b765Szf162725 if (scf_pg_update(pg) == -1) { 2288*a399b765Szf162725 goto out; 2289*a399b765Szf162725 } 2290*a399b765Szf162725 break; 2291*a399b765Szf162725 case -1: 2292*a399b765Szf162725 default: 2293*a399b765Szf162725 goto out; 2294*a399b765Szf162725 } 2295*a399b765Szf162725 } while (rv == 0); 2296*a399b765Szf162725 2297*a399b765Szf162725 out: 2298*a399b765Szf162725 if (tran != NULL) { 2299*a399b765Szf162725 scf_transaction_destroy_children(tran); 2300*a399b765Szf162725 scf_transaction_destroy(tran); 2301*a399b765Szf162725 } 2302*a399b765Szf162725 2303*a399b765Szf162725 if (pg != NULL) 2304*a399b765Szf162725 scf_pg_destroy(pg); 2305*a399b765Szf162725 2306*a399b765Szf162725 if (command != NULL) 2307*a399b765Szf162725 free(command); 2308*a399b765Szf162725 2309*a399b765Szf162725 return (status); 2310*a399b765Szf162725 } 2311*a399b765Szf162725 2312*a399b765Szf162725 static int 2313*a399b765Szf162725 do_create_instance(scf_handle_t *handle, scf_service_t *svc, 2314*a399b765Szf162725 const char *instance_name, const char *command) 2315*a399b765Szf162725 { 2316*a399b765Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2317*a399b765Szf162725 char *buf; 2318*a399b765Szf162725 ssize_t max_fmri_len; 2319*a399b765Szf162725 scf_instance_t *instance; 2320*a399b765Szf162725 2321*a399b765Szf162725 instance = scf_instance_create(handle); 2322*a399b765Szf162725 if (instance == NULL) 2323*a399b765Szf162725 goto out; 2324*a399b765Szf162725 2325*a399b765Szf162725 if (scf_service_add_instance(svc, instance_name, instance) != 0) { 2326*a399b765Szf162725 if (scf_error() == SCF_ERROR_EXISTS) 2327*a399b765Szf162725 /* Let the caller deal with the duplicate instance */ 2328*a399b765Szf162725 status = DLADM_WLAN_SVC_INSTANCE_EXISTS; 2329*a399b765Szf162725 goto out; 2330*a399b765Szf162725 } 2331*a399b765Szf162725 2332*a399b765Szf162725 if (add_pg_method(handle, instance, "start", 2333*a399b765Szf162725 command) != DLADM_WLAN_SVC_SUCCESS) { 2334*a399b765Szf162725 goto out; 2335*a399b765Szf162725 } 2336*a399b765Szf162725 2337*a399b765Szf162725 /* enabling the instance */ 2338*a399b765Szf162725 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 2339*a399b765Szf162725 if ((buf = malloc(max_fmri_len + 1)) == NULL) 2340*a399b765Szf162725 goto out; 2341*a399b765Szf162725 2342*a399b765Szf162725 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 2343*a399b765Szf162725 if ((smf_disable_instance(buf, 0) != 0) || 2344*a399b765Szf162725 (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { 2345*a399b765Szf162725 goto out; 2346*a399b765Szf162725 } 2347*a399b765Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2348*a399b765Szf162725 } 2349*a399b765Szf162725 2350*a399b765Szf162725 out: 2351*a399b765Szf162725 if (instance != NULL) 2352*a399b765Szf162725 scf_instance_destroy(instance); 2353*a399b765Szf162725 return (status); 2354*a399b765Szf162725 } 2355*a399b765Szf162725 2356*a399b765Szf162725 static int 2357*a399b765Szf162725 create_instance(const char *instance_name, const char *command) 2358*a399b765Szf162725 { 2359*a399b765Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2360*a399b765Szf162725 scf_service_t *svc = NULL; 2361*a399b765Szf162725 scf_handle_t *handle = NULL; 2362*a399b765Szf162725 2363*a399b765Szf162725 handle = scf_handle_create(SCF_VERSION); 2364*a399b765Szf162725 if (handle == NULL) 2365*a399b765Szf162725 goto out; 2366*a399b765Szf162725 2367*a399b765Szf162725 if (scf_handle_bind(handle) == -1) 2368*a399b765Szf162725 goto out; 2369*a399b765Szf162725 2370*a399b765Szf162725 if ((svc = scf_service_create(handle)) == NULL) 2371*a399b765Szf162725 goto out; 2372*a399b765Szf162725 2373*a399b765Szf162725 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc, 2374*a399b765Szf162725 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 2375*a399b765Szf162725 goto out; 2376*a399b765Szf162725 2377*a399b765Szf162725 status = do_create_instance(handle, svc, instance_name, command); 2378*a399b765Szf162725 2379*a399b765Szf162725 out: 2380*a399b765Szf162725 if (svc != NULL) 2381*a399b765Szf162725 scf_service_destroy(svc); 2382*a399b765Szf162725 2383*a399b765Szf162725 if (handle != NULL) { 2384*a399b765Szf162725 (void) scf_handle_unbind(handle); 2385*a399b765Szf162725 scf_handle_destroy(handle); 2386*a399b765Szf162725 } 2387*a399b765Szf162725 2388*a399b765Szf162725 return (status); 2389*a399b765Szf162725 } 2390*a399b765Szf162725 2391*a399b765Szf162725 /* 2392*a399b765Szf162725 * routines of delete instance 2393*a399b765Szf162725 */ 2394*a399b765Szf162725 #define DEFAULT_TIMEOUT 60000000 2395*a399b765Szf162725 #define INIT_WAIT_USECS 50000 2396*a399b765Szf162725 2397*a399b765Szf162725 static void 2398*a399b765Szf162725 wait_until_disabled(scf_handle_t *handle, char *fmri) 2399*a399b765Szf162725 { 2400*a399b765Szf162725 char *state; 2401*a399b765Szf162725 useconds_t max; 2402*a399b765Szf162725 useconds_t usecs; 2403*a399b765Szf162725 uint64_t *cp = NULL; 2404*a399b765Szf162725 scf_simple_prop_t *sp = NULL; 2405*a399b765Szf162725 2406*a399b765Szf162725 max = DEFAULT_TIMEOUT; 2407*a399b765Szf162725 2408*a399b765Szf162725 if (((sp = scf_simple_prop_get(handle, fmri, "stop", 2409*a399b765Szf162725 SCF_PROPERTY_TIMEOUT)) != NULL) && 2410*a399b765Szf162725 ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0)) 2411*a399b765Szf162725 max = (*cp) * 1000000; /* convert to usecs */ 2412*a399b765Szf162725 2413*a399b765Szf162725 if (sp != NULL) 2414*a399b765Szf162725 scf_simple_prop_free(sp); 2415*a399b765Szf162725 2416*a399b765Szf162725 for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) { 2417*a399b765Szf162725 /* incremental wait */ 2418*a399b765Szf162725 usecs *= 2; 2419*a399b765Szf162725 usecs = (usecs > max) ? max : usecs; 2420*a399b765Szf162725 2421*a399b765Szf162725 (void) usleep(usecs); 2422*a399b765Szf162725 2423*a399b765Szf162725 /* Check state after the wait */ 2424*a399b765Szf162725 if ((state = smf_get_state(fmri)) != NULL) { 2425*a399b765Szf162725 if (strcmp(state, "disabled") == 0) 2426*a399b765Szf162725 return; 2427*a399b765Szf162725 } 2428*a399b765Szf162725 } 2429*a399b765Szf162725 } 2430*a399b765Szf162725 2431*a399b765Szf162725 static int 2432*a399b765Szf162725 delete_instance(const char *instance_name) 2433*a399b765Szf162725 { 2434*a399b765Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2435*a399b765Szf162725 char *buf; 2436*a399b765Szf162725 ssize_t max_fmri_len; 2437*a399b765Szf162725 scf_scope_t *scope = NULL; 2438*a399b765Szf162725 scf_service_t *svc = NULL; 2439*a399b765Szf162725 scf_handle_t *handle = NULL; 2440*a399b765Szf162725 scf_instance_t *instance; 2441*a399b765Szf162725 2442*a399b765Szf162725 handle = scf_handle_create(SCF_VERSION); 2443*a399b765Szf162725 if (handle == NULL) 2444*a399b765Szf162725 goto out; 2445*a399b765Szf162725 2446*a399b765Szf162725 if (scf_handle_bind(handle) == -1) 2447*a399b765Szf162725 goto out; 2448*a399b765Szf162725 2449*a399b765Szf162725 if ((scope = scf_scope_create(handle)) == NULL) 2450*a399b765Szf162725 goto out; 2451*a399b765Szf162725 2452*a399b765Szf162725 if ((svc = scf_service_create(handle)) == NULL) 2453*a399b765Szf162725 goto out; 2454*a399b765Szf162725 2455*a399b765Szf162725 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1) 2456*a399b765Szf162725 goto out; 2457*a399b765Szf162725 2458*a399b765Szf162725 if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0) 2459*a399b765Szf162725 goto out; 2460*a399b765Szf162725 2461*a399b765Szf162725 instance = scf_instance_create(handle); 2462*a399b765Szf162725 if (instance == NULL) 2463*a399b765Szf162725 goto out; 2464*a399b765Szf162725 2465*a399b765Szf162725 if (scf_service_get_instance(svc, instance_name, instance) != 0) { 2466*a399b765Szf162725 scf_error_t scf_errnum = scf_error(); 2467*a399b765Szf162725 2468*a399b765Szf162725 if (scf_errnum == SCF_ERROR_NOT_FOUND) 2469*a399b765Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2470*a399b765Szf162725 2471*a399b765Szf162725 scf_instance_destroy(instance); 2472*a399b765Szf162725 goto out; 2473*a399b765Szf162725 } 2474*a399b765Szf162725 2475*a399b765Szf162725 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 2476*a399b765Szf162725 if ((buf = malloc(max_fmri_len + 1)) == NULL) { 2477*a399b765Szf162725 scf_instance_destroy(instance); 2478*a399b765Szf162725 goto out; 2479*a399b765Szf162725 } 2480*a399b765Szf162725 2481*a399b765Szf162725 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 2482*a399b765Szf162725 char *state; 2483*a399b765Szf162725 2484*a399b765Szf162725 state = smf_get_state(buf); 2485*a399b765Szf162725 if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 || 2486*a399b765Szf162725 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) { 2487*a399b765Szf162725 if (smf_disable_instance(buf, 0) == 0) { 2488*a399b765Szf162725 /* 2489*a399b765Szf162725 * Wait for some time till timeout to avoid 2490*a399b765Szf162725 * a race with scf_instance_delete() below. 2491*a399b765Szf162725 */ 2492*a399b765Szf162725 wait_until_disabled(handle, buf); 2493*a399b765Szf162725 } 2494*a399b765Szf162725 } 2495*a399b765Szf162725 } 2496*a399b765Szf162725 2497*a399b765Szf162725 if (scf_instance_delete(instance) != 0) { 2498*a399b765Szf162725 scf_instance_destroy(instance); 2499*a399b765Szf162725 goto out; 2500*a399b765Szf162725 } 2501*a399b765Szf162725 2502*a399b765Szf162725 scf_instance_destroy(instance); 2503*a399b765Szf162725 2504*a399b765Szf162725 status = DLADM_WLAN_SVC_SUCCESS; 2505*a399b765Szf162725 2506*a399b765Szf162725 out: 2507*a399b765Szf162725 if (svc != NULL) 2508*a399b765Szf162725 scf_service_destroy(svc); 2509*a399b765Szf162725 2510*a399b765Szf162725 if (scope != NULL) 2511*a399b765Szf162725 scf_scope_destroy(scope); 2512*a399b765Szf162725 2513*a399b765Szf162725 if (handle != NULL) { 2514*a399b765Szf162725 (void) scf_handle_unbind(handle); 2515*a399b765Szf162725 scf_handle_destroy(handle); 2516*a399b765Szf162725 } 2517*a399b765Szf162725 2518*a399b765Szf162725 return (status); 2519*a399b765Szf162725 } 2520*a399b765Szf162725 2521*a399b765Szf162725 /* 2522*a399b765Szf162725 * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. 2523*a399b765Szf162725 */ 2524*a399b765Szf162725 static int 2525*a399b765Szf162725 wpa_instance_create(const char *instance_name, void *key) 2526*a399b765Szf162725 { 2527*a399b765Szf162725 int status = DLADM_WLAN_SVC_FAILURE; 2528*a399b765Szf162725 char *command = NULL; 2529*a399b765Szf162725 char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; 2530*a399b765Szf162725 int size; 2531*a399b765Szf162725 2532*a399b765Szf162725 size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; 2533*a399b765Szf162725 command = malloc(size); 2534*a399b765Szf162725 if (command == NULL) { 2535*a399b765Szf162725 status = DLADM_WLAN_SVC_APP_FAILURE; 2536*a399b765Szf162725 goto out; 2537*a399b765Szf162725 } 2538*a399b765Szf162725 (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); 2539*a399b765Szf162725 2540*a399b765Szf162725 status = create_instance(instance_name, command); 2541*a399b765Szf162725 if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) { 2542*a399b765Szf162725 /* 2543*a399b765Szf162725 * Delete the existing instance and create a new instance 2544*a399b765Szf162725 * with the supplied arguments. 2545*a399b765Szf162725 */ 2546*a399b765Szf162725 if ((status = delete_instance(instance_name)) == 2547*a399b765Szf162725 DLADM_WLAN_SVC_SUCCESS) { 2548*a399b765Szf162725 status = create_instance(instance_name, command); 2549*a399b765Szf162725 } 2550*a399b765Szf162725 } 2551*a399b765Szf162725 2552*a399b765Szf162725 out: 2553*a399b765Szf162725 if (command != NULL) 2554*a399b765Szf162725 free(command); 2555*a399b765Szf162725 2556*a399b765Szf162725 return (status); 2557*a399b765Szf162725 } 2558*a399b765Szf162725 2559*a399b765Szf162725 static int 2560*a399b765Szf162725 wpa_instance_delete(const char *instance_name) 2561*a399b765Szf162725 { 2562*a399b765Szf162725 int status; 2563*a399b765Szf162725 2564*a399b765Szf162725 status = delete_instance(instance_name); 2565*a399b765Szf162725 2566*a399b765Szf162725 return (status); 2567*a399b765Szf162725 } 2568