1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Driver interaction with generic Linux Wireless Extensions 3e5b75505Sopenharmony_ci * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci * 8e5b75505Sopenharmony_ci * This file implements a driver interface for the Linux Wireless Extensions. 9e5b75505Sopenharmony_ci * When used with WE-18 or newer, this interface can be used as-is with number 10e5b75505Sopenharmony_ci * of drivers. In addition to this, some of the common functions in this file 11e5b75505Sopenharmony_ci * can be used by other driver interface implementations that use generic WE 12e5b75505Sopenharmony_ci * ioctls, but require private ioctls for some of the functionality. 13e5b75505Sopenharmony_ci */ 14e5b75505Sopenharmony_ci 15e5b75505Sopenharmony_ci#include "includes.h" 16e5b75505Sopenharmony_ci#include <sys/ioctl.h> 17e5b75505Sopenharmony_ci#include <sys/types.h> 18e5b75505Sopenharmony_ci#include <sys/stat.h> 19e5b75505Sopenharmony_ci#include <fcntl.h> 20e5b75505Sopenharmony_ci#include <net/if_arp.h> 21e5b75505Sopenharmony_ci#include <dirent.h> 22e5b75505Sopenharmony_ci 23e5b75505Sopenharmony_ci#include "linux_wext.h" 24e5b75505Sopenharmony_ci#include "common.h" 25e5b75505Sopenharmony_ci#include "eloop.h" 26e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 27e5b75505Sopenharmony_ci#include "common/wpa_common.h" 28e5b75505Sopenharmony_ci#include "priv_netlink.h" 29e5b75505Sopenharmony_ci#include "netlink.h" 30e5b75505Sopenharmony_ci#include "linux_ioctl.h" 31e5b75505Sopenharmony_ci#include "rfkill.h" 32e5b75505Sopenharmony_ci#include "driver.h" 33e5b75505Sopenharmony_ci#include "driver_wext.h" 34e5b75505Sopenharmony_ci 35e5b75505Sopenharmony_cistatic int wpa_driver_wext_flush_pmkid(void *priv); 36e5b75505Sopenharmony_cistatic int wpa_driver_wext_get_range(void *priv); 37e5b75505Sopenharmony_cistatic int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); 38e5b75505Sopenharmony_cistatic void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv); 39e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg); 40e5b75505Sopenharmony_ci 41e5b75505Sopenharmony_ci 42e5b75505Sopenharmony_ciint wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, 43e5b75505Sopenharmony_ci int idx, u32 value) 44e5b75505Sopenharmony_ci{ 45e5b75505Sopenharmony_ci struct iwreq iwr; 46e5b75505Sopenharmony_ci int ret = 0; 47e5b75505Sopenharmony_ci 48e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 49e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 50e5b75505Sopenharmony_ci iwr.u.param.flags = idx & IW_AUTH_INDEX; 51e5b75505Sopenharmony_ci iwr.u.param.value = value; 52e5b75505Sopenharmony_ci 53e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { 54e5b75505Sopenharmony_ci if (errno != EOPNOTSUPP) { 55e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d " 56e5b75505Sopenharmony_ci "value 0x%x) failed: %s)", 57e5b75505Sopenharmony_ci idx, value, strerror(errno)); 58e5b75505Sopenharmony_ci } 59e5b75505Sopenharmony_ci ret = errno == EOPNOTSUPP ? -2 : -1; 60e5b75505Sopenharmony_ci } 61e5b75505Sopenharmony_ci 62e5b75505Sopenharmony_ci return ret; 63e5b75505Sopenharmony_ci} 64e5b75505Sopenharmony_ci 65e5b75505Sopenharmony_ci 66e5b75505Sopenharmony_ci/** 67e5b75505Sopenharmony_ci * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP 68e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 69e5b75505Sopenharmony_ci * @bssid: Buffer for BSSID 70e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 71e5b75505Sopenharmony_ci */ 72e5b75505Sopenharmony_ciint wpa_driver_wext_get_bssid(void *priv, u8 *bssid) 73e5b75505Sopenharmony_ci{ 74e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 75e5b75505Sopenharmony_ci struct iwreq iwr; 76e5b75505Sopenharmony_ci int ret = 0; 77e5b75505Sopenharmony_ci 78e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 79e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 80e5b75505Sopenharmony_ci 81e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { 82e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno)); 83e5b75505Sopenharmony_ci ret = -1; 84e5b75505Sopenharmony_ci } 85e5b75505Sopenharmony_ci os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); 86e5b75505Sopenharmony_ci 87e5b75505Sopenharmony_ci return ret; 88e5b75505Sopenharmony_ci} 89e5b75505Sopenharmony_ci 90e5b75505Sopenharmony_ci 91e5b75505Sopenharmony_ci/** 92e5b75505Sopenharmony_ci * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP 93e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 94e5b75505Sopenharmony_ci * @bssid: BSSID 95e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 96e5b75505Sopenharmony_ci */ 97e5b75505Sopenharmony_ciint wpa_driver_wext_set_bssid(void *priv, const u8 *bssid) 98e5b75505Sopenharmony_ci{ 99e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 100e5b75505Sopenharmony_ci struct iwreq iwr; 101e5b75505Sopenharmony_ci int ret = 0; 102e5b75505Sopenharmony_ci 103e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 104e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 105e5b75505Sopenharmony_ci iwr.u.ap_addr.sa_family = ARPHRD_ETHER; 106e5b75505Sopenharmony_ci if (bssid) 107e5b75505Sopenharmony_ci os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); 108e5b75505Sopenharmony_ci else 109e5b75505Sopenharmony_ci os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); 110e5b75505Sopenharmony_ci 111e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { 112e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno)); 113e5b75505Sopenharmony_ci ret = -1; 114e5b75505Sopenharmony_ci } 115e5b75505Sopenharmony_ci 116e5b75505Sopenharmony_ci return ret; 117e5b75505Sopenharmony_ci} 118e5b75505Sopenharmony_ci 119e5b75505Sopenharmony_ci 120e5b75505Sopenharmony_ci/** 121e5b75505Sopenharmony_ci * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID 122e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 123e5b75505Sopenharmony_ci * @ssid: Buffer for the SSID; must be at least 32 bytes long 124e5b75505Sopenharmony_ci * Returns: SSID length on success, -1 on failure 125e5b75505Sopenharmony_ci */ 126e5b75505Sopenharmony_ciint wpa_driver_wext_get_ssid(void *priv, u8 *ssid) 127e5b75505Sopenharmony_ci{ 128e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 129e5b75505Sopenharmony_ci struct iwreq iwr; 130e5b75505Sopenharmony_ci int ret = 0; 131e5b75505Sopenharmony_ci 132e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 133e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 134e5b75505Sopenharmony_ci iwr.u.essid.pointer = (caddr_t) ssid; 135e5b75505Sopenharmony_ci iwr.u.essid.length = SSID_MAX_LEN; 136e5b75505Sopenharmony_ci 137e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { 138e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", 139e5b75505Sopenharmony_ci strerror(errno)); 140e5b75505Sopenharmony_ci ret = -1; 141e5b75505Sopenharmony_ci } else { 142e5b75505Sopenharmony_ci ret = iwr.u.essid.length; 143e5b75505Sopenharmony_ci if (ret > SSID_MAX_LEN) 144e5b75505Sopenharmony_ci ret = SSID_MAX_LEN; 145e5b75505Sopenharmony_ci /* Some drivers include nul termination in the SSID, so let's 146e5b75505Sopenharmony_ci * remove it here before further processing. WE-21 changes this 147e5b75505Sopenharmony_ci * to explicitly require the length _not_ to include nul 148e5b75505Sopenharmony_ci * termination. */ 149e5b75505Sopenharmony_ci if (ret > 0 && ssid[ret - 1] == '\0' && 150e5b75505Sopenharmony_ci drv->we_version_compiled < 21) 151e5b75505Sopenharmony_ci ret--; 152e5b75505Sopenharmony_ci } 153e5b75505Sopenharmony_ci 154e5b75505Sopenharmony_ci return ret; 155e5b75505Sopenharmony_ci} 156e5b75505Sopenharmony_ci 157e5b75505Sopenharmony_ci 158e5b75505Sopenharmony_ci/** 159e5b75505Sopenharmony_ci * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID 160e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 161e5b75505Sopenharmony_ci * @ssid: SSID 162e5b75505Sopenharmony_ci * @ssid_len: Length of SSID (0..32) 163e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 164e5b75505Sopenharmony_ci */ 165e5b75505Sopenharmony_ciint wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) 166e5b75505Sopenharmony_ci{ 167e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 168e5b75505Sopenharmony_ci struct iwreq iwr; 169e5b75505Sopenharmony_ci int ret = 0; 170e5b75505Sopenharmony_ci char buf[33]; 171e5b75505Sopenharmony_ci 172e5b75505Sopenharmony_ci if (ssid_len > SSID_MAX_LEN) 173e5b75505Sopenharmony_ci return -1; 174e5b75505Sopenharmony_ci 175e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 176e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 177e5b75505Sopenharmony_ci /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ 178e5b75505Sopenharmony_ci iwr.u.essid.flags = (ssid_len != 0); 179e5b75505Sopenharmony_ci os_memset(buf, 0, sizeof(buf)); 180e5b75505Sopenharmony_ci os_memcpy(buf, ssid, ssid_len); 181e5b75505Sopenharmony_ci iwr.u.essid.pointer = (caddr_t) buf; 182e5b75505Sopenharmony_ci if (drv->we_version_compiled < 21) { 183e5b75505Sopenharmony_ci /* For historic reasons, set SSID length to include one extra 184e5b75505Sopenharmony_ci * character, C string nul termination, even though SSID is 185e5b75505Sopenharmony_ci * really an octet string that should not be presented as a C 186e5b75505Sopenharmony_ci * string. Some Linux drivers decrement the length by one and 187e5b75505Sopenharmony_ci * can thus end up missing the last octet of the SSID if the 188e5b75505Sopenharmony_ci * length is not incremented here. WE-21 changes this to 189e5b75505Sopenharmony_ci * explicitly require the length _not_ to include nul 190e5b75505Sopenharmony_ci * termination. */ 191e5b75505Sopenharmony_ci if (ssid_len) 192e5b75505Sopenharmony_ci ssid_len++; 193e5b75505Sopenharmony_ci } 194e5b75505Sopenharmony_ci iwr.u.essid.length = ssid_len; 195e5b75505Sopenharmony_ci 196e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { 197e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s", 198e5b75505Sopenharmony_ci strerror(errno)); 199e5b75505Sopenharmony_ci ret = -1; 200e5b75505Sopenharmony_ci } 201e5b75505Sopenharmony_ci 202e5b75505Sopenharmony_ci return ret; 203e5b75505Sopenharmony_ci} 204e5b75505Sopenharmony_ci 205e5b75505Sopenharmony_ci 206e5b75505Sopenharmony_ci/** 207e5b75505Sopenharmony_ci * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ 208e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 209e5b75505Sopenharmony_ci * @freq: Frequency in MHz 210e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 211e5b75505Sopenharmony_ci */ 212e5b75505Sopenharmony_ciint wpa_driver_wext_set_freq(void *priv, int freq) 213e5b75505Sopenharmony_ci{ 214e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 215e5b75505Sopenharmony_ci struct iwreq iwr; 216e5b75505Sopenharmony_ci int ret = 0; 217e5b75505Sopenharmony_ci 218e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 219e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 220e5b75505Sopenharmony_ci iwr.u.freq.m = freq * 100000; 221e5b75505Sopenharmony_ci iwr.u.freq.e = 1; 222e5b75505Sopenharmony_ci 223e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { 224e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s", 225e5b75505Sopenharmony_ci strerror(errno)); 226e5b75505Sopenharmony_ci ret = -1; 227e5b75505Sopenharmony_ci } 228e5b75505Sopenharmony_ci 229e5b75505Sopenharmony_ci return ret; 230e5b75505Sopenharmony_ci} 231e5b75505Sopenharmony_ci 232e5b75505Sopenharmony_ci 233e5b75505Sopenharmony_cistatic void 234e5b75505Sopenharmony_ciwpa_driver_wext_event_wireless_custom(void *ctx, char *custom) 235e5b75505Sopenharmony_ci{ 236e5b75505Sopenharmony_ci union wpa_event_data data; 237e5b75505Sopenharmony_ci 238e5b75505Sopenharmony_ci wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", 239e5b75505Sopenharmony_ci custom); 240e5b75505Sopenharmony_ci 241e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 242e5b75505Sopenharmony_ci /* Host AP driver */ 243e5b75505Sopenharmony_ci if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { 244e5b75505Sopenharmony_ci data.michael_mic_failure.unicast = 245e5b75505Sopenharmony_ci os_strstr(custom, " unicast ") != NULL; 246e5b75505Sopenharmony_ci /* TODO: parse parameters(?) */ 247e5b75505Sopenharmony_ci wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); 248e5b75505Sopenharmony_ci } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { 249e5b75505Sopenharmony_ci char *spos; 250e5b75505Sopenharmony_ci int bytes; 251e5b75505Sopenharmony_ci u8 *req_ies = NULL, *resp_ies = NULL; 252e5b75505Sopenharmony_ci 253e5b75505Sopenharmony_ci spos = custom + 17; 254e5b75505Sopenharmony_ci 255e5b75505Sopenharmony_ci bytes = strspn(spos, "0123456789abcdefABCDEF"); 256e5b75505Sopenharmony_ci if (!bytes || (bytes & 1)) 257e5b75505Sopenharmony_ci return; 258e5b75505Sopenharmony_ci bytes /= 2; 259e5b75505Sopenharmony_ci 260e5b75505Sopenharmony_ci req_ies = os_malloc(bytes); 261e5b75505Sopenharmony_ci if (req_ies == NULL || 262e5b75505Sopenharmony_ci hexstr2bin(spos, req_ies, bytes) < 0) 263e5b75505Sopenharmony_ci goto done; 264e5b75505Sopenharmony_ci data.assoc_info.req_ies = req_ies; 265e5b75505Sopenharmony_ci data.assoc_info.req_ies_len = bytes; 266e5b75505Sopenharmony_ci 267e5b75505Sopenharmony_ci spos += bytes * 2; 268e5b75505Sopenharmony_ci 269e5b75505Sopenharmony_ci data.assoc_info.resp_ies = NULL; 270e5b75505Sopenharmony_ci data.assoc_info.resp_ies_len = 0; 271e5b75505Sopenharmony_ci 272e5b75505Sopenharmony_ci if (os_strncmp(spos, " RespIEs=", 9) == 0) { 273e5b75505Sopenharmony_ci spos += 9; 274e5b75505Sopenharmony_ci 275e5b75505Sopenharmony_ci bytes = strspn(spos, "0123456789abcdefABCDEF"); 276e5b75505Sopenharmony_ci if (!bytes || (bytes & 1)) 277e5b75505Sopenharmony_ci goto done; 278e5b75505Sopenharmony_ci bytes /= 2; 279e5b75505Sopenharmony_ci 280e5b75505Sopenharmony_ci resp_ies = os_malloc(bytes); 281e5b75505Sopenharmony_ci if (resp_ies == NULL || 282e5b75505Sopenharmony_ci hexstr2bin(spos, resp_ies, bytes) < 0) 283e5b75505Sopenharmony_ci goto done; 284e5b75505Sopenharmony_ci data.assoc_info.resp_ies = resp_ies; 285e5b75505Sopenharmony_ci data.assoc_info.resp_ies_len = bytes; 286e5b75505Sopenharmony_ci } 287e5b75505Sopenharmony_ci 288e5b75505Sopenharmony_ci wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); 289e5b75505Sopenharmony_ci 290e5b75505Sopenharmony_ci done: 291e5b75505Sopenharmony_ci os_free(resp_ies); 292e5b75505Sopenharmony_ci os_free(req_ies); 293e5b75505Sopenharmony_ci } 294e5b75505Sopenharmony_ci} 295e5b75505Sopenharmony_ci 296e5b75505Sopenharmony_ci 297e5b75505Sopenharmony_cistatic int wpa_driver_wext_event_wireless_michaelmicfailure( 298e5b75505Sopenharmony_ci void *ctx, const char *ev, size_t len) 299e5b75505Sopenharmony_ci{ 300e5b75505Sopenharmony_ci const struct iw_michaelmicfailure *mic; 301e5b75505Sopenharmony_ci union wpa_event_data data; 302e5b75505Sopenharmony_ci 303e5b75505Sopenharmony_ci if (len < sizeof(*mic)) 304e5b75505Sopenharmony_ci return -1; 305e5b75505Sopenharmony_ci 306e5b75505Sopenharmony_ci mic = (const struct iw_michaelmicfailure *) ev; 307e5b75505Sopenharmony_ci 308e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " 309e5b75505Sopenharmony_ci "flags=0x%x src_addr=" MACSTR, mic->flags, 310e5b75505Sopenharmony_ci MAC2STR(mic->src_addr.sa_data)); 311e5b75505Sopenharmony_ci 312e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 313e5b75505Sopenharmony_ci data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); 314e5b75505Sopenharmony_ci wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); 315e5b75505Sopenharmony_ci 316e5b75505Sopenharmony_ci return 0; 317e5b75505Sopenharmony_ci} 318e5b75505Sopenharmony_ci 319e5b75505Sopenharmony_ci 320e5b75505Sopenharmony_cistatic int wpa_driver_wext_event_wireless_pmkidcand( 321e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv, const char *ev, size_t len) 322e5b75505Sopenharmony_ci{ 323e5b75505Sopenharmony_ci const struct iw_pmkid_cand *cand; 324e5b75505Sopenharmony_ci union wpa_event_data data; 325e5b75505Sopenharmony_ci const u8 *addr; 326e5b75505Sopenharmony_ci 327e5b75505Sopenharmony_ci if (len < sizeof(*cand)) 328e5b75505Sopenharmony_ci return -1; 329e5b75505Sopenharmony_ci 330e5b75505Sopenharmony_ci cand = (const struct iw_pmkid_cand *) ev; 331e5b75505Sopenharmony_ci addr = (const u8 *) cand->bssid.sa_data; 332e5b75505Sopenharmony_ci 333e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " 334e5b75505Sopenharmony_ci "flags=0x%x index=%d bssid=" MACSTR, cand->flags, 335e5b75505Sopenharmony_ci cand->index, MAC2STR(addr)); 336e5b75505Sopenharmony_ci 337e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 338e5b75505Sopenharmony_ci os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); 339e5b75505Sopenharmony_ci data.pmkid_candidate.index = cand->index; 340e5b75505Sopenharmony_ci data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; 341e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); 342e5b75505Sopenharmony_ci 343e5b75505Sopenharmony_ci return 0; 344e5b75505Sopenharmony_ci} 345e5b75505Sopenharmony_ci 346e5b75505Sopenharmony_ci 347e5b75505Sopenharmony_cistatic int wpa_driver_wext_event_wireless_assocreqie( 348e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv, const char *ev, int len) 349e5b75505Sopenharmony_ci{ 350e5b75505Sopenharmony_ci if (len < 0) 351e5b75505Sopenharmony_ci return -1; 352e5b75505Sopenharmony_ci 353e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, 354e5b75505Sopenharmony_ci len); 355e5b75505Sopenharmony_ci os_free(drv->assoc_req_ies); 356e5b75505Sopenharmony_ci drv->assoc_req_ies = os_memdup(ev, len); 357e5b75505Sopenharmony_ci if (drv->assoc_req_ies == NULL) { 358e5b75505Sopenharmony_ci drv->assoc_req_ies_len = 0; 359e5b75505Sopenharmony_ci return -1; 360e5b75505Sopenharmony_ci } 361e5b75505Sopenharmony_ci drv->assoc_req_ies_len = len; 362e5b75505Sopenharmony_ci 363e5b75505Sopenharmony_ci return 0; 364e5b75505Sopenharmony_ci} 365e5b75505Sopenharmony_ci 366e5b75505Sopenharmony_ci 367e5b75505Sopenharmony_cistatic int wpa_driver_wext_event_wireless_assocrespie( 368e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv, const char *ev, int len) 369e5b75505Sopenharmony_ci{ 370e5b75505Sopenharmony_ci if (len < 0) 371e5b75505Sopenharmony_ci return -1; 372e5b75505Sopenharmony_ci 373e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, 374e5b75505Sopenharmony_ci len); 375e5b75505Sopenharmony_ci os_free(drv->assoc_resp_ies); 376e5b75505Sopenharmony_ci drv->assoc_resp_ies = os_memdup(ev, len); 377e5b75505Sopenharmony_ci if (drv->assoc_resp_ies == NULL) { 378e5b75505Sopenharmony_ci drv->assoc_resp_ies_len = 0; 379e5b75505Sopenharmony_ci return -1; 380e5b75505Sopenharmony_ci } 381e5b75505Sopenharmony_ci drv->assoc_resp_ies_len = len; 382e5b75505Sopenharmony_ci 383e5b75505Sopenharmony_ci return 0; 384e5b75505Sopenharmony_ci} 385e5b75505Sopenharmony_ci 386e5b75505Sopenharmony_ci 387e5b75505Sopenharmony_cistatic void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) 388e5b75505Sopenharmony_ci{ 389e5b75505Sopenharmony_ci union wpa_event_data data; 390e5b75505Sopenharmony_ci 391e5b75505Sopenharmony_ci if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) 392e5b75505Sopenharmony_ci return; 393e5b75505Sopenharmony_ci 394e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 395e5b75505Sopenharmony_ci if (drv->assoc_req_ies) { 396e5b75505Sopenharmony_ci data.assoc_info.req_ies = drv->assoc_req_ies; 397e5b75505Sopenharmony_ci data.assoc_info.req_ies_len = drv->assoc_req_ies_len; 398e5b75505Sopenharmony_ci } 399e5b75505Sopenharmony_ci if (drv->assoc_resp_ies) { 400e5b75505Sopenharmony_ci data.assoc_info.resp_ies = drv->assoc_resp_ies; 401e5b75505Sopenharmony_ci data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; 402e5b75505Sopenharmony_ci } 403e5b75505Sopenharmony_ci 404e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); 405e5b75505Sopenharmony_ci 406e5b75505Sopenharmony_ci os_free(drv->assoc_req_ies); 407e5b75505Sopenharmony_ci drv->assoc_req_ies = NULL; 408e5b75505Sopenharmony_ci os_free(drv->assoc_resp_ies); 409e5b75505Sopenharmony_ci drv->assoc_resp_ies = NULL; 410e5b75505Sopenharmony_ci} 411e5b75505Sopenharmony_ci 412e5b75505Sopenharmony_ci 413e5b75505Sopenharmony_cistatic void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, 414e5b75505Sopenharmony_ci char *data, unsigned int len) 415e5b75505Sopenharmony_ci{ 416e5b75505Sopenharmony_ci struct iw_event iwe_buf, *iwe = &iwe_buf; 417e5b75505Sopenharmony_ci char *pos, *end, *custom, *buf; 418e5b75505Sopenharmony_ci 419e5b75505Sopenharmony_ci pos = data; 420e5b75505Sopenharmony_ci end = data + len; 421e5b75505Sopenharmony_ci 422e5b75505Sopenharmony_ci while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { 423e5b75505Sopenharmony_ci /* Event data may be unaligned, so make a local, aligned copy 424e5b75505Sopenharmony_ci * before processing. */ 425e5b75505Sopenharmony_ci os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); 426e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", 427e5b75505Sopenharmony_ci iwe->cmd, iwe->len); 428e5b75505Sopenharmony_ci if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) 429e5b75505Sopenharmony_ci return; 430e5b75505Sopenharmony_ci 431e5b75505Sopenharmony_ci custom = pos + IW_EV_POINT_LEN; 432e5b75505Sopenharmony_ci if (drv->we_version_compiled > 18 && 433e5b75505Sopenharmony_ci (iwe->cmd == IWEVMICHAELMICFAILURE || 434e5b75505Sopenharmony_ci iwe->cmd == IWEVCUSTOM || 435e5b75505Sopenharmony_ci iwe->cmd == IWEVASSOCREQIE || 436e5b75505Sopenharmony_ci iwe->cmd == IWEVASSOCRESPIE || 437e5b75505Sopenharmony_ci iwe->cmd == IWEVPMKIDCAND)) { 438e5b75505Sopenharmony_ci /* WE-19 removed the pointer from struct iw_point */ 439e5b75505Sopenharmony_ci char *dpos = (char *) &iwe_buf.u.data.length; 440e5b75505Sopenharmony_ci int dlen = dpos - (char *) &iwe_buf; 441e5b75505Sopenharmony_ci os_memcpy(dpos, pos + IW_EV_LCP_LEN, 442e5b75505Sopenharmony_ci sizeof(struct iw_event) - dlen); 443e5b75505Sopenharmony_ci } else { 444e5b75505Sopenharmony_ci os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); 445e5b75505Sopenharmony_ci custom += IW_EV_POINT_OFF; 446e5b75505Sopenharmony_ci } 447e5b75505Sopenharmony_ci 448e5b75505Sopenharmony_ci switch (iwe->cmd) { 449e5b75505Sopenharmony_ci case SIOCGIWAP: 450e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Wireless event: new AP: " 451e5b75505Sopenharmony_ci MACSTR, 452e5b75505Sopenharmony_ci MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); 453e5b75505Sopenharmony_ci if (is_zero_ether_addr( 454e5b75505Sopenharmony_ci (const u8 *) iwe->u.ap_addr.sa_data) || 455e5b75505Sopenharmony_ci os_memcmp(iwe->u.ap_addr.sa_data, 456e5b75505Sopenharmony_ci "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 457e5b75505Sopenharmony_ci 0) { 458e5b75505Sopenharmony_ci os_free(drv->assoc_req_ies); 459e5b75505Sopenharmony_ci drv->assoc_req_ies = NULL; 460e5b75505Sopenharmony_ci os_free(drv->assoc_resp_ies); 461e5b75505Sopenharmony_ci drv->assoc_resp_ies = NULL; 462e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, 463e5b75505Sopenharmony_ci NULL); 464e5b75505Sopenharmony_ci 465e5b75505Sopenharmony_ci } else { 466e5b75505Sopenharmony_ci wpa_driver_wext_event_assoc_ies(drv); 467e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_ASSOC, 468e5b75505Sopenharmony_ci NULL); 469e5b75505Sopenharmony_ci } 470e5b75505Sopenharmony_ci break; 471e5b75505Sopenharmony_ci case IWEVMICHAELMICFAILURE: 472e5b75505Sopenharmony_ci if (iwe->u.data.length > end - custom) { 473e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Invalid " 474e5b75505Sopenharmony_ci "IWEVMICHAELMICFAILURE length"); 475e5b75505Sopenharmony_ci return; 476e5b75505Sopenharmony_ci } 477e5b75505Sopenharmony_ci wpa_driver_wext_event_wireless_michaelmicfailure( 478e5b75505Sopenharmony_ci drv->ctx, custom, iwe->u.data.length); 479e5b75505Sopenharmony_ci break; 480e5b75505Sopenharmony_ci case IWEVCUSTOM: 481e5b75505Sopenharmony_ci if (iwe->u.data.length > end - custom) { 482e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Invalid " 483e5b75505Sopenharmony_ci "IWEVCUSTOM length"); 484e5b75505Sopenharmony_ci return; 485e5b75505Sopenharmony_ci } 486e5b75505Sopenharmony_ci buf = dup_binstr(custom, iwe->u.data.length); 487e5b75505Sopenharmony_ci if (buf == NULL) 488e5b75505Sopenharmony_ci return; 489e5b75505Sopenharmony_ci wpa_driver_wext_event_wireless_custom(drv->ctx, buf); 490e5b75505Sopenharmony_ci os_free(buf); 491e5b75505Sopenharmony_ci break; 492e5b75505Sopenharmony_ci case SIOCGIWSCAN: 493e5b75505Sopenharmony_ci drv->scan_complete_events = 1; 494e5b75505Sopenharmony_ci eloop_cancel_timeout(wpa_driver_wext_scan_timeout, 495e5b75505Sopenharmony_ci drv, drv->ctx); 496e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, 497e5b75505Sopenharmony_ci NULL); 498e5b75505Sopenharmony_ci break; 499e5b75505Sopenharmony_ci case IWEVASSOCREQIE: 500e5b75505Sopenharmony_ci if (iwe->u.data.length > end - custom) { 501e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Invalid " 502e5b75505Sopenharmony_ci "IWEVASSOCREQIE length"); 503e5b75505Sopenharmony_ci return; 504e5b75505Sopenharmony_ci } 505e5b75505Sopenharmony_ci wpa_driver_wext_event_wireless_assocreqie( 506e5b75505Sopenharmony_ci drv, custom, iwe->u.data.length); 507e5b75505Sopenharmony_ci break; 508e5b75505Sopenharmony_ci case IWEVASSOCRESPIE: 509e5b75505Sopenharmony_ci if (iwe->u.data.length > end - custom) { 510e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Invalid " 511e5b75505Sopenharmony_ci "IWEVASSOCRESPIE length"); 512e5b75505Sopenharmony_ci return; 513e5b75505Sopenharmony_ci } 514e5b75505Sopenharmony_ci wpa_driver_wext_event_wireless_assocrespie( 515e5b75505Sopenharmony_ci drv, custom, iwe->u.data.length); 516e5b75505Sopenharmony_ci break; 517e5b75505Sopenharmony_ci case IWEVPMKIDCAND: 518e5b75505Sopenharmony_ci if (iwe->u.data.length > end - custom) { 519e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Invalid " 520e5b75505Sopenharmony_ci "IWEVPMKIDCAND length"); 521e5b75505Sopenharmony_ci return; 522e5b75505Sopenharmony_ci } 523e5b75505Sopenharmony_ci wpa_driver_wext_event_wireless_pmkidcand( 524e5b75505Sopenharmony_ci drv, custom, iwe->u.data.length); 525e5b75505Sopenharmony_ci break; 526e5b75505Sopenharmony_ci } 527e5b75505Sopenharmony_ci 528e5b75505Sopenharmony_ci pos += iwe->len; 529e5b75505Sopenharmony_ci } 530e5b75505Sopenharmony_ci} 531e5b75505Sopenharmony_ci 532e5b75505Sopenharmony_ci 533e5b75505Sopenharmony_cistatic void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, 534e5b75505Sopenharmony_ci char *buf, size_t len, int del) 535e5b75505Sopenharmony_ci{ 536e5b75505Sopenharmony_ci union wpa_event_data event; 537e5b75505Sopenharmony_ci 538e5b75505Sopenharmony_ci os_memset(&event, 0, sizeof(event)); 539e5b75505Sopenharmony_ci if (len > sizeof(event.interface_status.ifname)) 540e5b75505Sopenharmony_ci len = sizeof(event.interface_status.ifname) - 1; 541e5b75505Sopenharmony_ci os_memcpy(event.interface_status.ifname, buf, len); 542e5b75505Sopenharmony_ci event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : 543e5b75505Sopenharmony_ci EVENT_INTERFACE_ADDED; 544e5b75505Sopenharmony_ci 545e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", 546e5b75505Sopenharmony_ci del ? "DEL" : "NEW", 547e5b75505Sopenharmony_ci event.interface_status.ifname, 548e5b75505Sopenharmony_ci del ? "removed" : "added"); 549e5b75505Sopenharmony_ci 550e5b75505Sopenharmony_ci if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) { 551e5b75505Sopenharmony_ci if (del) { 552e5b75505Sopenharmony_ci if (drv->if_removed) { 553e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: if_removed " 554e5b75505Sopenharmony_ci "already set - ignore event"); 555e5b75505Sopenharmony_ci return; 556e5b75505Sopenharmony_ci } 557e5b75505Sopenharmony_ci drv->if_removed = 1; 558e5b75505Sopenharmony_ci } else { 559e5b75505Sopenharmony_ci if (if_nametoindex(drv->ifname) == 0) { 560e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Interface %s " 561e5b75505Sopenharmony_ci "does not exist - ignore " 562e5b75505Sopenharmony_ci "RTM_NEWLINK", 563e5b75505Sopenharmony_ci drv->ifname); 564e5b75505Sopenharmony_ci return; 565e5b75505Sopenharmony_ci } 566e5b75505Sopenharmony_ci if (!drv->if_removed) { 567e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: if_removed " 568e5b75505Sopenharmony_ci "already cleared - ignore event"); 569e5b75505Sopenharmony_ci return; 570e5b75505Sopenharmony_ci } 571e5b75505Sopenharmony_ci drv->if_removed = 0; 572e5b75505Sopenharmony_ci } 573e5b75505Sopenharmony_ci } 574e5b75505Sopenharmony_ci 575e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); 576e5b75505Sopenharmony_ci} 577e5b75505Sopenharmony_ci 578e5b75505Sopenharmony_ci 579e5b75505Sopenharmony_cistatic int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, 580e5b75505Sopenharmony_ci u8 *buf, size_t len) 581e5b75505Sopenharmony_ci{ 582e5b75505Sopenharmony_ci int attrlen, rta_len; 583e5b75505Sopenharmony_ci struct rtattr *attr; 584e5b75505Sopenharmony_ci 585e5b75505Sopenharmony_ci attrlen = len; 586e5b75505Sopenharmony_ci attr = (struct rtattr *) buf; 587e5b75505Sopenharmony_ci 588e5b75505Sopenharmony_ci rta_len = RTA_ALIGN(sizeof(struct rtattr)); 589e5b75505Sopenharmony_ci while (RTA_OK(attr, attrlen)) { 590e5b75505Sopenharmony_ci if (attr->rta_type == IFLA_IFNAME) { 591e5b75505Sopenharmony_ci if (os_strcmp(((char *) attr) + rta_len, drv->ifname) 592e5b75505Sopenharmony_ci == 0) 593e5b75505Sopenharmony_ci return 1; 594e5b75505Sopenharmony_ci else 595e5b75505Sopenharmony_ci break; 596e5b75505Sopenharmony_ci } 597e5b75505Sopenharmony_ci attr = RTA_NEXT(attr, attrlen); 598e5b75505Sopenharmony_ci } 599e5b75505Sopenharmony_ci 600e5b75505Sopenharmony_ci return 0; 601e5b75505Sopenharmony_ci} 602e5b75505Sopenharmony_ci 603e5b75505Sopenharmony_ci 604e5b75505Sopenharmony_cistatic int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, 605e5b75505Sopenharmony_ci int ifindex, u8 *buf, size_t len) 606e5b75505Sopenharmony_ci{ 607e5b75505Sopenharmony_ci if (drv->ifindex == ifindex || drv->ifindex2 == ifindex) 608e5b75505Sopenharmony_ci return 1; 609e5b75505Sopenharmony_ci 610e5b75505Sopenharmony_ci if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) { 611e5b75505Sopenharmony_ci drv->ifindex = if_nametoindex(drv->ifname); 612e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed " 613e5b75505Sopenharmony_ci "interface"); 614e5b75505Sopenharmony_ci wpa_driver_wext_finish_drv_init(drv); 615e5b75505Sopenharmony_ci return 1; 616e5b75505Sopenharmony_ci } 617e5b75505Sopenharmony_ci 618e5b75505Sopenharmony_ci return 0; 619e5b75505Sopenharmony_ci} 620e5b75505Sopenharmony_ci 621e5b75505Sopenharmony_ci 622e5b75505Sopenharmony_cistatic void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, 623e5b75505Sopenharmony_ci u8 *buf, size_t len) 624e5b75505Sopenharmony_ci{ 625e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = ctx; 626e5b75505Sopenharmony_ci int attrlen, rta_len; 627e5b75505Sopenharmony_ci struct rtattr *attr; 628e5b75505Sopenharmony_ci char namebuf[IFNAMSIZ]; 629e5b75505Sopenharmony_ci 630e5b75505Sopenharmony_ci if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) { 631e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", 632e5b75505Sopenharmony_ci ifi->ifi_index); 633e5b75505Sopenharmony_ci return; 634e5b75505Sopenharmony_ci } 635e5b75505Sopenharmony_ci 636e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " 637e5b75505Sopenharmony_ci "(%s%s%s%s)", 638e5b75505Sopenharmony_ci drv->operstate, ifi->ifi_flags, 639e5b75505Sopenharmony_ci (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", 640e5b75505Sopenharmony_ci (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", 641e5b75505Sopenharmony_ci (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", 642e5b75505Sopenharmony_ci (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); 643e5b75505Sopenharmony_ci 644e5b75505Sopenharmony_ci if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { 645e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Interface down"); 646e5b75505Sopenharmony_ci drv->if_disabled = 1; 647e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); 648e5b75505Sopenharmony_ci } 649e5b75505Sopenharmony_ci 650e5b75505Sopenharmony_ci if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { 651e5b75505Sopenharmony_ci if (if_indextoname(ifi->ifi_index, namebuf) && 652e5b75505Sopenharmony_ci linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) { 653e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " 654e5b75505Sopenharmony_ci "event since interface %s is down", 655e5b75505Sopenharmony_ci namebuf); 656e5b75505Sopenharmony_ci } else if (if_nametoindex(drv->ifname) == 0) { 657e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " 658e5b75505Sopenharmony_ci "event since interface %s does not exist", 659e5b75505Sopenharmony_ci drv->ifname); 660e5b75505Sopenharmony_ci } else if (drv->if_removed) { 661e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " 662e5b75505Sopenharmony_ci "event since interface %s is marked " 663e5b75505Sopenharmony_ci "removed", drv->ifname); 664e5b75505Sopenharmony_ci } else { 665e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Interface up"); 666e5b75505Sopenharmony_ci drv->if_disabled = 0; 667e5b75505Sopenharmony_ci wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, 668e5b75505Sopenharmony_ci NULL); 669e5b75505Sopenharmony_ci } 670e5b75505Sopenharmony_ci } 671e5b75505Sopenharmony_ci 672e5b75505Sopenharmony_ci /* 673e5b75505Sopenharmony_ci * Some drivers send the association event before the operup event--in 674e5b75505Sopenharmony_ci * this case, lifting operstate in wpa_driver_wext_set_operstate() 675e5b75505Sopenharmony_ci * fails. This will hit us when wpa_supplicant does not need to do 676e5b75505Sopenharmony_ci * IEEE 802.1X authentication 677e5b75505Sopenharmony_ci */ 678e5b75505Sopenharmony_ci if (drv->operstate == 1 && 679e5b75505Sopenharmony_ci (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && 680e5b75505Sopenharmony_ci !(ifi->ifi_flags & IFF_RUNNING)) 681e5b75505Sopenharmony_ci netlink_send_oper_ifla(drv->netlink, drv->ifindex, 682e5b75505Sopenharmony_ci -1, IF_OPER_UP); 683e5b75505Sopenharmony_ci 684e5b75505Sopenharmony_ci attrlen = len; 685e5b75505Sopenharmony_ci attr = (struct rtattr *) buf; 686e5b75505Sopenharmony_ci 687e5b75505Sopenharmony_ci rta_len = RTA_ALIGN(sizeof(struct rtattr)); 688e5b75505Sopenharmony_ci while (RTA_OK(attr, attrlen)) { 689e5b75505Sopenharmony_ci if (attr->rta_type == IFLA_WIRELESS) { 690e5b75505Sopenharmony_ci wpa_driver_wext_event_wireless( 691e5b75505Sopenharmony_ci drv, ((char *) attr) + rta_len, 692e5b75505Sopenharmony_ci attr->rta_len - rta_len); 693e5b75505Sopenharmony_ci } else if (attr->rta_type == IFLA_IFNAME) { 694e5b75505Sopenharmony_ci wpa_driver_wext_event_link(drv, 695e5b75505Sopenharmony_ci ((char *) attr) + rta_len, 696e5b75505Sopenharmony_ci attr->rta_len - rta_len, 0); 697e5b75505Sopenharmony_ci } 698e5b75505Sopenharmony_ci attr = RTA_NEXT(attr, attrlen); 699e5b75505Sopenharmony_ci } 700e5b75505Sopenharmony_ci} 701e5b75505Sopenharmony_ci 702e5b75505Sopenharmony_ci 703e5b75505Sopenharmony_cistatic void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, 704e5b75505Sopenharmony_ci u8 *buf, size_t len) 705e5b75505Sopenharmony_ci{ 706e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = ctx; 707e5b75505Sopenharmony_ci int attrlen, rta_len; 708e5b75505Sopenharmony_ci struct rtattr *attr; 709e5b75505Sopenharmony_ci 710e5b75505Sopenharmony_ci attrlen = len; 711e5b75505Sopenharmony_ci attr = (struct rtattr *) buf; 712e5b75505Sopenharmony_ci 713e5b75505Sopenharmony_ci rta_len = RTA_ALIGN(sizeof(struct rtattr)); 714e5b75505Sopenharmony_ci while (RTA_OK(attr, attrlen)) { 715e5b75505Sopenharmony_ci if (attr->rta_type == IFLA_IFNAME) { 716e5b75505Sopenharmony_ci wpa_driver_wext_event_link(drv, 717e5b75505Sopenharmony_ci ((char *) attr) + rta_len, 718e5b75505Sopenharmony_ci attr->rta_len - rta_len, 1); 719e5b75505Sopenharmony_ci } 720e5b75505Sopenharmony_ci attr = RTA_NEXT(attr, attrlen); 721e5b75505Sopenharmony_ci } 722e5b75505Sopenharmony_ci} 723e5b75505Sopenharmony_ci 724e5b75505Sopenharmony_ci 725e5b75505Sopenharmony_cistatic void wpa_driver_wext_rfkill_blocked(void *ctx) 726e5b75505Sopenharmony_ci{ 727e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); 728e5b75505Sopenharmony_ci /* 729e5b75505Sopenharmony_ci * This may be for any interface; use ifdown event to disable 730e5b75505Sopenharmony_ci * interface. 731e5b75505Sopenharmony_ci */ 732e5b75505Sopenharmony_ci} 733e5b75505Sopenharmony_ci 734e5b75505Sopenharmony_ci 735e5b75505Sopenharmony_cistatic void wpa_driver_wext_rfkill_unblocked(void *ctx) 736e5b75505Sopenharmony_ci{ 737e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = ctx; 738e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked"); 739e5b75505Sopenharmony_ci if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) { 740e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP " 741e5b75505Sopenharmony_ci "after rfkill unblock"); 742e5b75505Sopenharmony_ci return; 743e5b75505Sopenharmony_ci } 744e5b75505Sopenharmony_ci /* rtnetlink ifup handler will report interface as enabled */ 745e5b75505Sopenharmony_ci} 746e5b75505Sopenharmony_ci 747e5b75505Sopenharmony_ci 748e5b75505Sopenharmony_cistatic void wext_get_phy_name(struct wpa_driver_wext_data *drv) 749e5b75505Sopenharmony_ci{ 750e5b75505Sopenharmony_ci /* Find phy (radio) to which this interface belongs */ 751e5b75505Sopenharmony_ci char buf[90], *pos; 752e5b75505Sopenharmony_ci int f, rv; 753e5b75505Sopenharmony_ci 754e5b75505Sopenharmony_ci drv->phyname[0] = '\0'; 755e5b75505Sopenharmony_ci snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", 756e5b75505Sopenharmony_ci drv->ifname); 757e5b75505Sopenharmony_ci f = open(buf, O_RDONLY); 758e5b75505Sopenharmony_ci if (f < 0) { 759e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not open file %s: %s", 760e5b75505Sopenharmony_ci buf, strerror(errno)); 761e5b75505Sopenharmony_ci return; 762e5b75505Sopenharmony_ci } 763e5b75505Sopenharmony_ci 764e5b75505Sopenharmony_ci rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); 765e5b75505Sopenharmony_ci close(f); 766e5b75505Sopenharmony_ci if (rv < 0) { 767e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not read file %s: %s", 768e5b75505Sopenharmony_ci buf, strerror(errno)); 769e5b75505Sopenharmony_ci return; 770e5b75505Sopenharmony_ci } 771e5b75505Sopenharmony_ci 772e5b75505Sopenharmony_ci drv->phyname[rv] = '\0'; 773e5b75505Sopenharmony_ci pos = os_strchr(drv->phyname, '\n'); 774e5b75505Sopenharmony_ci if (pos) 775e5b75505Sopenharmony_ci *pos = '\0'; 776e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s", 777e5b75505Sopenharmony_ci drv->ifname, drv->phyname); 778e5b75505Sopenharmony_ci} 779e5b75505Sopenharmony_ci 780e5b75505Sopenharmony_ci 781e5b75505Sopenharmony_ci/** 782e5b75505Sopenharmony_ci * wpa_driver_wext_init - Initialize WE driver interface 783e5b75505Sopenharmony_ci * @ctx: context to be used when calling wpa_supplicant functions, 784e5b75505Sopenharmony_ci * e.g., wpa_supplicant_event() 785e5b75505Sopenharmony_ci * @ifname: interface name, e.g., wlan0 786e5b75505Sopenharmony_ci * Returns: Pointer to private data, %NULL on failure 787e5b75505Sopenharmony_ci */ 788e5b75505Sopenharmony_civoid * wpa_driver_wext_init(void *ctx, const char *ifname) 789e5b75505Sopenharmony_ci{ 790e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv; 791e5b75505Sopenharmony_ci struct netlink_config *cfg; 792e5b75505Sopenharmony_ci struct rfkill_config *rcfg; 793e5b75505Sopenharmony_ci char path[128]; 794e5b75505Sopenharmony_ci struct stat buf; 795e5b75505Sopenharmony_ci 796e5b75505Sopenharmony_ci drv = os_zalloc(sizeof(*drv)); 797e5b75505Sopenharmony_ci if (drv == NULL) 798e5b75505Sopenharmony_ci return NULL; 799e5b75505Sopenharmony_ci drv->ctx = ctx; 800e5b75505Sopenharmony_ci os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 801e5b75505Sopenharmony_ci 802e5b75505Sopenharmony_ci os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); 803e5b75505Sopenharmony_ci if (stat(path, &buf) == 0) { 804e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected"); 805e5b75505Sopenharmony_ci drv->cfg80211 = 1; 806e5b75505Sopenharmony_ci wext_get_phy_name(drv); 807e5b75505Sopenharmony_ci } 808e5b75505Sopenharmony_ci 809e5b75505Sopenharmony_ci drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); 810e5b75505Sopenharmony_ci if (drv->ioctl_sock < 0) { 811e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s", 812e5b75505Sopenharmony_ci strerror(errno)); 813e5b75505Sopenharmony_ci goto err1; 814e5b75505Sopenharmony_ci } 815e5b75505Sopenharmony_ci 816e5b75505Sopenharmony_ci cfg = os_zalloc(sizeof(*cfg)); 817e5b75505Sopenharmony_ci if (cfg == NULL) 818e5b75505Sopenharmony_ci goto err1; 819e5b75505Sopenharmony_ci cfg->ctx = drv; 820e5b75505Sopenharmony_ci cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; 821e5b75505Sopenharmony_ci cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; 822e5b75505Sopenharmony_ci drv->netlink = netlink_init(cfg); 823e5b75505Sopenharmony_ci if (drv->netlink == NULL) { 824e5b75505Sopenharmony_ci os_free(cfg); 825e5b75505Sopenharmony_ci goto err2; 826e5b75505Sopenharmony_ci } 827e5b75505Sopenharmony_ci 828e5b75505Sopenharmony_ci rcfg = os_zalloc(sizeof(*rcfg)); 829e5b75505Sopenharmony_ci if (rcfg == NULL) 830e5b75505Sopenharmony_ci goto err3; 831e5b75505Sopenharmony_ci rcfg->ctx = drv; 832e5b75505Sopenharmony_ci os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); 833e5b75505Sopenharmony_ci rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; 834e5b75505Sopenharmony_ci rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; 835e5b75505Sopenharmony_ci drv->rfkill = rfkill_init(rcfg); 836e5b75505Sopenharmony_ci if (drv->rfkill == NULL) { 837e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); 838e5b75505Sopenharmony_ci os_free(rcfg); 839e5b75505Sopenharmony_ci } 840e5b75505Sopenharmony_ci 841e5b75505Sopenharmony_ci drv->mlme_sock = -1; 842e5b75505Sopenharmony_ci 843e5b75505Sopenharmony_ci if (wpa_driver_wext_finish_drv_init(drv) < 0) 844e5b75505Sopenharmony_ci goto err3; 845e5b75505Sopenharmony_ci 846e5b75505Sopenharmony_ci wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); 847e5b75505Sopenharmony_ci 848e5b75505Sopenharmony_ci return drv; 849e5b75505Sopenharmony_ci 850e5b75505Sopenharmony_cierr3: 851e5b75505Sopenharmony_ci rfkill_deinit(drv->rfkill); 852e5b75505Sopenharmony_ci netlink_deinit(drv->netlink); 853e5b75505Sopenharmony_cierr2: 854e5b75505Sopenharmony_ci close(drv->ioctl_sock); 855e5b75505Sopenharmony_cierr1: 856e5b75505Sopenharmony_ci os_free(drv); 857e5b75505Sopenharmony_ci return NULL; 858e5b75505Sopenharmony_ci} 859e5b75505Sopenharmony_ci 860e5b75505Sopenharmony_ci 861e5b75505Sopenharmony_cistatic void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) 862e5b75505Sopenharmony_ci{ 863e5b75505Sopenharmony_ci wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); 864e5b75505Sopenharmony_ci} 865e5b75505Sopenharmony_ci 866e5b75505Sopenharmony_ci 867e5b75505Sopenharmony_cistatic int wext_hostap_ifname(struct wpa_driver_wext_data *drv, 868e5b75505Sopenharmony_ci const char *ifname) 869e5b75505Sopenharmony_ci{ 870e5b75505Sopenharmony_ci char buf[200], *res; 871e5b75505Sopenharmony_ci int type, ret; 872e5b75505Sopenharmony_ci FILE *f; 873e5b75505Sopenharmony_ci 874e5b75505Sopenharmony_ci if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0) 875e5b75505Sopenharmony_ci return -1; 876e5b75505Sopenharmony_ci 877e5b75505Sopenharmony_ci ret = snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type", 878e5b75505Sopenharmony_ci drv->ifname, ifname); 879e5b75505Sopenharmony_ci if (os_snprintf_error(sizeof(buf), ret)) 880e5b75505Sopenharmony_ci return -1; 881e5b75505Sopenharmony_ci 882e5b75505Sopenharmony_ci f = fopen(buf, "r"); 883e5b75505Sopenharmony_ci if (!f) 884e5b75505Sopenharmony_ci return -1; 885e5b75505Sopenharmony_ci res = fgets(buf, sizeof(buf), f); 886e5b75505Sopenharmony_ci fclose(f); 887e5b75505Sopenharmony_ci 888e5b75505Sopenharmony_ci type = res ? atoi(res) : -1; 889e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type); 890e5b75505Sopenharmony_ci 891e5b75505Sopenharmony_ci if (type == ARPHRD_IEEE80211) { 892e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 893e5b75505Sopenharmony_ci "WEXT: Found hostap driver wifi# interface (%s)", 894e5b75505Sopenharmony_ci ifname); 895e5b75505Sopenharmony_ci wpa_driver_wext_alternative_ifindex(drv, ifname); 896e5b75505Sopenharmony_ci return 0; 897e5b75505Sopenharmony_ci } 898e5b75505Sopenharmony_ci return -1; 899e5b75505Sopenharmony_ci} 900e5b75505Sopenharmony_ci 901e5b75505Sopenharmony_ci 902e5b75505Sopenharmony_cistatic int wext_add_hostap(struct wpa_driver_wext_data *drv) 903e5b75505Sopenharmony_ci{ 904e5b75505Sopenharmony_ci char buf[200]; 905e5b75505Sopenharmony_ci int n; 906e5b75505Sopenharmony_ci struct dirent **names; 907e5b75505Sopenharmony_ci int ret = -1; 908e5b75505Sopenharmony_ci 909e5b75505Sopenharmony_ci snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname); 910e5b75505Sopenharmony_ci n = scandir(buf, &names, NULL, alphasort); 911e5b75505Sopenharmony_ci if (n < 0) 912e5b75505Sopenharmony_ci return -1; 913e5b75505Sopenharmony_ci 914e5b75505Sopenharmony_ci while (n--) { 915e5b75505Sopenharmony_ci if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0) 916e5b75505Sopenharmony_ci ret = 0; 917e5b75505Sopenharmony_ci free(names[n]); 918e5b75505Sopenharmony_ci } 919e5b75505Sopenharmony_ci free(names); 920e5b75505Sopenharmony_ci 921e5b75505Sopenharmony_ci return ret; 922e5b75505Sopenharmony_ci} 923e5b75505Sopenharmony_ci 924e5b75505Sopenharmony_ci 925e5b75505Sopenharmony_cistatic void wext_check_hostap(struct wpa_driver_wext_data *drv) 926e5b75505Sopenharmony_ci{ 927e5b75505Sopenharmony_ci char path[200], buf[200], *pos; 928e5b75505Sopenharmony_ci ssize_t res; 929e5b75505Sopenharmony_ci 930e5b75505Sopenharmony_ci /* 931e5b75505Sopenharmony_ci * Host AP driver may use both wlan# and wifi# interface in wireless 932e5b75505Sopenharmony_ci * events. Since some of the versions included WE-18 support, let's add 933e5b75505Sopenharmony_ci * the alternative ifindex also from driver_wext.c for the time being. 934e5b75505Sopenharmony_ci * This may be removed at some point once it is believed that old 935e5b75505Sopenharmony_ci * versions of the driver are not in use anymore. However, it looks like 936e5b75505Sopenharmony_ci * the wifi# interface is still used in the current kernel tree, so it 937e5b75505Sopenharmony_ci * may not really be possible to remove this before the Host AP driver 938e5b75505Sopenharmony_ci * gets removed from the kernel. 939e5b75505Sopenharmony_ci */ 940e5b75505Sopenharmony_ci 941e5b75505Sopenharmony_ci /* First, try to see if driver information is available from sysfs */ 942e5b75505Sopenharmony_ci snprintf(path, sizeof(path), "/sys/class/net/%s/device/driver", 943e5b75505Sopenharmony_ci drv->ifname); 944e5b75505Sopenharmony_ci res = readlink(path, buf, sizeof(buf) - 1); 945e5b75505Sopenharmony_ci if (res > 0) { 946e5b75505Sopenharmony_ci buf[res] = '\0'; 947e5b75505Sopenharmony_ci pos = strrchr(buf, '/'); 948e5b75505Sopenharmony_ci if (pos) 949e5b75505Sopenharmony_ci pos++; 950e5b75505Sopenharmony_ci else 951e5b75505Sopenharmony_ci pos = buf; 952e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos); 953e5b75505Sopenharmony_ci if (os_strncmp(pos, "hostap", 6) == 0 && 954e5b75505Sopenharmony_ci wext_add_hostap(drv) == 0) 955e5b75505Sopenharmony_ci return; 956e5b75505Sopenharmony_ci } 957e5b75505Sopenharmony_ci 958e5b75505Sopenharmony_ci /* Second, use the old design with hardcoded ifname */ 959e5b75505Sopenharmony_ci if (os_strncmp(drv->ifname, "wlan", 4) == 0) { 960e5b75505Sopenharmony_ci char ifname2[IFNAMSIZ + 1]; 961e5b75505Sopenharmony_ci os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); 962e5b75505Sopenharmony_ci os_memcpy(ifname2, "wifi", 4); 963e5b75505Sopenharmony_ci wpa_driver_wext_alternative_ifindex(drv, ifname2); 964e5b75505Sopenharmony_ci } 965e5b75505Sopenharmony_ci} 966e5b75505Sopenharmony_ci 967e5b75505Sopenharmony_ci 968e5b75505Sopenharmony_cistatic int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) 969e5b75505Sopenharmony_ci{ 970e5b75505Sopenharmony_ci int send_rfkill_event = 0; 971e5b75505Sopenharmony_ci 972e5b75505Sopenharmony_ci if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { 973e5b75505Sopenharmony_ci if (rfkill_is_blocked(drv->rfkill)) { 974e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " 975e5b75505Sopenharmony_ci "interface '%s' due to rfkill", 976e5b75505Sopenharmony_ci drv->ifname); 977e5b75505Sopenharmony_ci drv->if_disabled = 1; 978e5b75505Sopenharmony_ci send_rfkill_event = 1; 979e5b75505Sopenharmony_ci } else { 980e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WEXT: Could not set " 981e5b75505Sopenharmony_ci "interface '%s' UP", drv->ifname); 982e5b75505Sopenharmony_ci return -1; 983e5b75505Sopenharmony_ci } 984e5b75505Sopenharmony_ci } 985e5b75505Sopenharmony_ci 986e5b75505Sopenharmony_ci /* 987e5b75505Sopenharmony_ci * Make sure that the driver does not have any obsolete PMKID entries. 988e5b75505Sopenharmony_ci */ 989e5b75505Sopenharmony_ci wpa_driver_wext_flush_pmkid(drv); 990e5b75505Sopenharmony_ci 991e5b75505Sopenharmony_ci if (wpa_driver_wext_set_mode(drv, 0) < 0) { 992e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not configure driver to use " 993e5b75505Sopenharmony_ci "managed mode"); 994e5b75505Sopenharmony_ci /* Try to use it anyway */ 995e5b75505Sopenharmony_ci } 996e5b75505Sopenharmony_ci 997e5b75505Sopenharmony_ci wpa_driver_wext_get_range(drv); 998e5b75505Sopenharmony_ci 999e5b75505Sopenharmony_ci /* 1000e5b75505Sopenharmony_ci * Unlock the driver's BSSID and force to a random SSID to clear any 1001e5b75505Sopenharmony_ci * previous association the driver might have when the supplicant 1002e5b75505Sopenharmony_ci * starts up. 1003e5b75505Sopenharmony_ci */ 1004e5b75505Sopenharmony_ci wpa_driver_wext_disconnect(drv); 1005e5b75505Sopenharmony_ci 1006e5b75505Sopenharmony_ci drv->ifindex = if_nametoindex(drv->ifname); 1007e5b75505Sopenharmony_ci 1008e5b75505Sopenharmony_ci wext_check_hostap(drv); 1009e5b75505Sopenharmony_ci 1010e5b75505Sopenharmony_ci netlink_send_oper_ifla(drv->netlink, drv->ifindex, 1011e5b75505Sopenharmony_ci 1, IF_OPER_DORMANT); 1012e5b75505Sopenharmony_ci 1013e5b75505Sopenharmony_ci if (send_rfkill_event) { 1014e5b75505Sopenharmony_ci eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, 1015e5b75505Sopenharmony_ci drv, drv->ctx); 1016e5b75505Sopenharmony_ci } 1017e5b75505Sopenharmony_ci 1018e5b75505Sopenharmony_ci return 0; 1019e5b75505Sopenharmony_ci} 1020e5b75505Sopenharmony_ci 1021e5b75505Sopenharmony_ci 1022e5b75505Sopenharmony_ci/** 1023e5b75505Sopenharmony_ci * wpa_driver_wext_deinit - Deinitialize WE driver interface 1024e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 1025e5b75505Sopenharmony_ci * 1026e5b75505Sopenharmony_ci * Shut down driver interface and processing of driver events. Free 1027e5b75505Sopenharmony_ci * private data buffer if one was allocated in wpa_driver_wext_init(). 1028e5b75505Sopenharmony_ci */ 1029e5b75505Sopenharmony_civoid wpa_driver_wext_deinit(void *priv) 1030e5b75505Sopenharmony_ci{ 1031e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1032e5b75505Sopenharmony_ci 1033e5b75505Sopenharmony_ci wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0); 1034e5b75505Sopenharmony_ci 1035e5b75505Sopenharmony_ci eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); 1036e5b75505Sopenharmony_ci eloop_cancel_timeout(wpa_driver_wext_send_rfkill, drv, drv->ctx); 1037e5b75505Sopenharmony_ci 1038e5b75505Sopenharmony_ci /* 1039e5b75505Sopenharmony_ci * Clear possibly configured driver parameters in order to make it 1040e5b75505Sopenharmony_ci * easier to use the driver after wpa_supplicant has been terminated. 1041e5b75505Sopenharmony_ci */ 1042e5b75505Sopenharmony_ci wpa_driver_wext_disconnect(drv); 1043e5b75505Sopenharmony_ci 1044e5b75505Sopenharmony_ci netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); 1045e5b75505Sopenharmony_ci netlink_deinit(drv->netlink); 1046e5b75505Sopenharmony_ci rfkill_deinit(drv->rfkill); 1047e5b75505Sopenharmony_ci 1048e5b75505Sopenharmony_ci if (drv->mlme_sock >= 0) 1049e5b75505Sopenharmony_ci eloop_unregister_read_sock(drv->mlme_sock); 1050e5b75505Sopenharmony_ci 1051e5b75505Sopenharmony_ci (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); 1052e5b75505Sopenharmony_ci 1053e5b75505Sopenharmony_ci close(drv->ioctl_sock); 1054e5b75505Sopenharmony_ci if (drv->mlme_sock >= 0) 1055e5b75505Sopenharmony_ci close(drv->mlme_sock); 1056e5b75505Sopenharmony_ci os_free(drv->assoc_req_ies); 1057e5b75505Sopenharmony_ci os_free(drv->assoc_resp_ies); 1058e5b75505Sopenharmony_ci os_free(drv); 1059e5b75505Sopenharmony_ci} 1060e5b75505Sopenharmony_ci 1061e5b75505Sopenharmony_ci 1062e5b75505Sopenharmony_ci/** 1063e5b75505Sopenharmony_ci * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion 1064e5b75505Sopenharmony_ci * @eloop_ctx: Unused 1065e5b75505Sopenharmony_ci * @timeout_ctx: ctx argument given to wpa_driver_wext_init() 1066e5b75505Sopenharmony_ci * 1067e5b75505Sopenharmony_ci * This function can be used as registered timeout when starting a scan to 1068e5b75505Sopenharmony_ci * generate a scan completed event if the driver does not report this. 1069e5b75505Sopenharmony_ci */ 1070e5b75505Sopenharmony_civoid wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) 1071e5b75505Sopenharmony_ci{ 1072e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); 1073e5b75505Sopenharmony_ci wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); 1074e5b75505Sopenharmony_ci} 1075e5b75505Sopenharmony_ci 1076e5b75505Sopenharmony_ci 1077e5b75505Sopenharmony_ci/** 1078e5b75505Sopenharmony_ci * wpa_driver_wext_scan - Request the driver to initiate scan 1079e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 1080e5b75505Sopenharmony_ci * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) 1081e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 1082e5b75505Sopenharmony_ci */ 1083e5b75505Sopenharmony_ciint wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) 1084e5b75505Sopenharmony_ci{ 1085e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1086e5b75505Sopenharmony_ci struct iwreq iwr; 1087e5b75505Sopenharmony_ci int ret = 0, timeout; 1088e5b75505Sopenharmony_ci struct iw_scan_req req; 1089e5b75505Sopenharmony_ci const u8 *ssid = params->ssids[0].ssid; 1090e5b75505Sopenharmony_ci size_t ssid_len = params->ssids[0].ssid_len; 1091e5b75505Sopenharmony_ci 1092e5b75505Sopenharmony_ci if (ssid_len > IW_ESSID_MAX_SIZE) { 1093e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", 1094e5b75505Sopenharmony_ci __FUNCTION__, (unsigned long) ssid_len); 1095e5b75505Sopenharmony_ci return -1; 1096e5b75505Sopenharmony_ci } 1097e5b75505Sopenharmony_ci 1098e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1099e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1100e5b75505Sopenharmony_ci 1101e5b75505Sopenharmony_ci if (ssid && ssid_len) { 1102e5b75505Sopenharmony_ci os_memset(&req, 0, sizeof(req)); 1103e5b75505Sopenharmony_ci req.essid_len = ssid_len; 1104e5b75505Sopenharmony_ci req.bssid.sa_family = ARPHRD_ETHER; 1105e5b75505Sopenharmony_ci os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); 1106e5b75505Sopenharmony_ci os_memcpy(req.essid, ssid, ssid_len); 1107e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) &req; 1108e5b75505Sopenharmony_ci iwr.u.data.length = sizeof(req); 1109e5b75505Sopenharmony_ci iwr.u.data.flags = IW_SCAN_THIS_ESSID; 1110e5b75505Sopenharmony_ci } 1111e5b75505Sopenharmony_ci 1112e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { 1113e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s", 1114e5b75505Sopenharmony_ci strerror(errno)); 1115e5b75505Sopenharmony_ci ret = -1; 1116e5b75505Sopenharmony_ci } 1117e5b75505Sopenharmony_ci 1118e5b75505Sopenharmony_ci /* Not all drivers generate "scan completed" wireless event, so try to 1119e5b75505Sopenharmony_ci * read results after a timeout. */ 1120e5b75505Sopenharmony_ci timeout = 10; 1121e5b75505Sopenharmony_ci if (drv->scan_complete_events) { 1122e5b75505Sopenharmony_ci /* 1123e5b75505Sopenharmony_ci * The driver seems to deliver SIOCGIWSCAN events to notify 1124e5b75505Sopenharmony_ci * when scan is complete, so use longer timeout to avoid race 1125e5b75505Sopenharmony_ci * conditions with scanning and following association request. 1126e5b75505Sopenharmony_ci */ 1127e5b75505Sopenharmony_ci timeout = 30; 1128e5b75505Sopenharmony_ci } 1129e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " 1130e5b75505Sopenharmony_ci "seconds", ret, timeout); 1131e5b75505Sopenharmony_ci eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); 1132e5b75505Sopenharmony_ci eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, 1133e5b75505Sopenharmony_ci drv->ctx); 1134e5b75505Sopenharmony_ci 1135e5b75505Sopenharmony_ci return ret; 1136e5b75505Sopenharmony_ci} 1137e5b75505Sopenharmony_ci 1138e5b75505Sopenharmony_ci 1139e5b75505Sopenharmony_cistatic u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv, 1140e5b75505Sopenharmony_ci size_t *len) 1141e5b75505Sopenharmony_ci{ 1142e5b75505Sopenharmony_ci struct iwreq iwr; 1143e5b75505Sopenharmony_ci u8 *res_buf; 1144e5b75505Sopenharmony_ci size_t res_buf_len; 1145e5b75505Sopenharmony_ci 1146e5b75505Sopenharmony_ci res_buf_len = IW_SCAN_MAX_DATA; 1147e5b75505Sopenharmony_ci for (;;) { 1148e5b75505Sopenharmony_ci res_buf = os_malloc(res_buf_len); 1149e5b75505Sopenharmony_ci if (res_buf == NULL) 1150e5b75505Sopenharmony_ci return NULL; 1151e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1152e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1153e5b75505Sopenharmony_ci iwr.u.data.pointer = res_buf; 1154e5b75505Sopenharmony_ci iwr.u.data.length = res_buf_len; 1155e5b75505Sopenharmony_ci 1156e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) 1157e5b75505Sopenharmony_ci break; 1158e5b75505Sopenharmony_ci 1159e5b75505Sopenharmony_ci if (errno == E2BIG && res_buf_len < 65535) { 1160e5b75505Sopenharmony_ci os_free(res_buf); 1161e5b75505Sopenharmony_ci res_buf = NULL; 1162e5b75505Sopenharmony_ci res_buf_len *= 2; 1163e5b75505Sopenharmony_ci if (res_buf_len > 65535) 1164e5b75505Sopenharmony_ci res_buf_len = 65535; /* 16-bit length field */ 1165e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Scan results did not fit - " 1166e5b75505Sopenharmony_ci "trying larger buffer (%lu bytes)", 1167e5b75505Sopenharmony_ci (unsigned long) res_buf_len); 1168e5b75505Sopenharmony_ci } else { 1169e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s", 1170e5b75505Sopenharmony_ci strerror(errno)); 1171e5b75505Sopenharmony_ci os_free(res_buf); 1172e5b75505Sopenharmony_ci return NULL; 1173e5b75505Sopenharmony_ci } 1174e5b75505Sopenharmony_ci } 1175e5b75505Sopenharmony_ci 1176e5b75505Sopenharmony_ci if (iwr.u.data.length > res_buf_len) { 1177e5b75505Sopenharmony_ci os_free(res_buf); 1178e5b75505Sopenharmony_ci return NULL; 1179e5b75505Sopenharmony_ci } 1180e5b75505Sopenharmony_ci *len = iwr.u.data.length; 1181e5b75505Sopenharmony_ci 1182e5b75505Sopenharmony_ci return res_buf; 1183e5b75505Sopenharmony_ci} 1184e5b75505Sopenharmony_ci 1185e5b75505Sopenharmony_ci 1186e5b75505Sopenharmony_ci/* 1187e5b75505Sopenharmony_ci * Data structure for collecting WEXT scan results. This is needed to allow 1188e5b75505Sopenharmony_ci * the various methods of reporting IEs to be combined into a single IE buffer. 1189e5b75505Sopenharmony_ci */ 1190e5b75505Sopenharmony_cistruct wext_scan_data { 1191e5b75505Sopenharmony_ci struct wpa_scan_res res; 1192e5b75505Sopenharmony_ci u8 *ie; 1193e5b75505Sopenharmony_ci size_t ie_len; 1194e5b75505Sopenharmony_ci u8 ssid[SSID_MAX_LEN]; 1195e5b75505Sopenharmony_ci size_t ssid_len; 1196e5b75505Sopenharmony_ci int maxrate; 1197e5b75505Sopenharmony_ci}; 1198e5b75505Sopenharmony_ci 1199e5b75505Sopenharmony_ci 1200e5b75505Sopenharmony_cistatic void wext_get_scan_mode(struct iw_event *iwe, 1201e5b75505Sopenharmony_ci struct wext_scan_data *res) 1202e5b75505Sopenharmony_ci{ 1203e5b75505Sopenharmony_ci if (iwe->u.mode == IW_MODE_ADHOC) 1204e5b75505Sopenharmony_ci res->res.caps |= IEEE80211_CAP_IBSS; 1205e5b75505Sopenharmony_ci else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) 1206e5b75505Sopenharmony_ci res->res.caps |= IEEE80211_CAP_ESS; 1207e5b75505Sopenharmony_ci} 1208e5b75505Sopenharmony_ci 1209e5b75505Sopenharmony_ci 1210e5b75505Sopenharmony_cistatic void wext_get_scan_ssid(struct iw_event *iwe, 1211e5b75505Sopenharmony_ci struct wext_scan_data *res, char *custom, 1212e5b75505Sopenharmony_ci char *end) 1213e5b75505Sopenharmony_ci{ 1214e5b75505Sopenharmony_ci int ssid_len = iwe->u.essid.length; 1215e5b75505Sopenharmony_ci if (ssid_len > end - custom) 1216e5b75505Sopenharmony_ci return; 1217e5b75505Sopenharmony_ci if (iwe->u.essid.flags && 1218e5b75505Sopenharmony_ci ssid_len > 0 && 1219e5b75505Sopenharmony_ci ssid_len <= IW_ESSID_MAX_SIZE) { 1220e5b75505Sopenharmony_ci os_memcpy(res->ssid, custom, ssid_len); 1221e5b75505Sopenharmony_ci res->ssid_len = ssid_len; 1222e5b75505Sopenharmony_ci } 1223e5b75505Sopenharmony_ci} 1224e5b75505Sopenharmony_ci 1225e5b75505Sopenharmony_ci 1226e5b75505Sopenharmony_cistatic void wext_get_scan_freq(struct iw_event *iwe, 1227e5b75505Sopenharmony_ci struct wext_scan_data *res) 1228e5b75505Sopenharmony_ci{ 1229e5b75505Sopenharmony_ci int divi = 1000000, i; 1230e5b75505Sopenharmony_ci 1231e5b75505Sopenharmony_ci if (iwe->u.freq.e == 0) { 1232e5b75505Sopenharmony_ci /* 1233e5b75505Sopenharmony_ci * Some drivers do not report frequency, but a channel. 1234e5b75505Sopenharmony_ci * Try to map this to frequency by assuming they are using 1235e5b75505Sopenharmony_ci * IEEE 802.11b/g. But don't overwrite a previously parsed 1236e5b75505Sopenharmony_ci * frequency if the driver sends both frequency and channel, 1237e5b75505Sopenharmony_ci * since the driver may be sending an A-band channel that we 1238e5b75505Sopenharmony_ci * don't handle here. 1239e5b75505Sopenharmony_ci */ 1240e5b75505Sopenharmony_ci 1241e5b75505Sopenharmony_ci if (res->res.freq) 1242e5b75505Sopenharmony_ci return; 1243e5b75505Sopenharmony_ci 1244e5b75505Sopenharmony_ci if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { 1245e5b75505Sopenharmony_ci res->res.freq = 2407 + 5 * iwe->u.freq.m; 1246e5b75505Sopenharmony_ci return; 1247e5b75505Sopenharmony_ci } else if (iwe->u.freq.m == 14) { 1248e5b75505Sopenharmony_ci res->res.freq = 2484; 1249e5b75505Sopenharmony_ci return; 1250e5b75505Sopenharmony_ci } 1251e5b75505Sopenharmony_ci } 1252e5b75505Sopenharmony_ci 1253e5b75505Sopenharmony_ci if (iwe->u.freq.e > 6) { 1254e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID=" 1255e5b75505Sopenharmony_ci MACSTR " m=%d e=%d)", 1256e5b75505Sopenharmony_ci MAC2STR(res->res.bssid), iwe->u.freq.m, 1257e5b75505Sopenharmony_ci iwe->u.freq.e); 1258e5b75505Sopenharmony_ci return; 1259e5b75505Sopenharmony_ci } 1260e5b75505Sopenharmony_ci 1261e5b75505Sopenharmony_ci for (i = 0; i < iwe->u.freq.e; i++) 1262e5b75505Sopenharmony_ci divi /= 10; 1263e5b75505Sopenharmony_ci res->res.freq = iwe->u.freq.m / divi; 1264e5b75505Sopenharmony_ci} 1265e5b75505Sopenharmony_ci 1266e5b75505Sopenharmony_ci 1267e5b75505Sopenharmony_cistatic void wext_get_scan_qual(struct wpa_driver_wext_data *drv, 1268e5b75505Sopenharmony_ci struct iw_event *iwe, 1269e5b75505Sopenharmony_ci struct wext_scan_data *res) 1270e5b75505Sopenharmony_ci{ 1271e5b75505Sopenharmony_ci res->res.qual = iwe->u.qual.qual; 1272e5b75505Sopenharmony_ci res->res.noise = iwe->u.qual.noise; 1273e5b75505Sopenharmony_ci res->res.level = iwe->u.qual.level; 1274e5b75505Sopenharmony_ci if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID) 1275e5b75505Sopenharmony_ci res->res.flags |= WPA_SCAN_QUAL_INVALID; 1276e5b75505Sopenharmony_ci if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID) 1277e5b75505Sopenharmony_ci res->res.flags |= WPA_SCAN_LEVEL_INVALID; 1278e5b75505Sopenharmony_ci if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID) 1279e5b75505Sopenharmony_ci res->res.flags |= WPA_SCAN_NOISE_INVALID; 1280e5b75505Sopenharmony_ci if (iwe->u.qual.updated & IW_QUAL_DBM) 1281e5b75505Sopenharmony_ci res->res.flags |= WPA_SCAN_LEVEL_DBM; 1282e5b75505Sopenharmony_ci if ((iwe->u.qual.updated & IW_QUAL_DBM) || 1283e5b75505Sopenharmony_ci ((iwe->u.qual.level != 0) && 1284e5b75505Sopenharmony_ci (iwe->u.qual.level > drv->max_level))) { 1285e5b75505Sopenharmony_ci if (iwe->u.qual.level >= 64) 1286e5b75505Sopenharmony_ci res->res.level -= 0x100; 1287e5b75505Sopenharmony_ci if (iwe->u.qual.noise >= 64) 1288e5b75505Sopenharmony_ci res->res.noise -= 0x100; 1289e5b75505Sopenharmony_ci } 1290e5b75505Sopenharmony_ci} 1291e5b75505Sopenharmony_ci 1292e5b75505Sopenharmony_ci 1293e5b75505Sopenharmony_cistatic void wext_get_scan_encode(struct iw_event *iwe, 1294e5b75505Sopenharmony_ci struct wext_scan_data *res) 1295e5b75505Sopenharmony_ci{ 1296e5b75505Sopenharmony_ci if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) 1297e5b75505Sopenharmony_ci res->res.caps |= IEEE80211_CAP_PRIVACY; 1298e5b75505Sopenharmony_ci} 1299e5b75505Sopenharmony_ci 1300e5b75505Sopenharmony_ci 1301e5b75505Sopenharmony_cistatic void wext_get_scan_rate(struct iw_event *iwe, 1302e5b75505Sopenharmony_ci struct wext_scan_data *res, char *pos, 1303e5b75505Sopenharmony_ci char *end) 1304e5b75505Sopenharmony_ci{ 1305e5b75505Sopenharmony_ci int maxrate; 1306e5b75505Sopenharmony_ci char *custom = pos + IW_EV_LCP_LEN; 1307e5b75505Sopenharmony_ci struct iw_param p; 1308e5b75505Sopenharmony_ci size_t clen; 1309e5b75505Sopenharmony_ci 1310e5b75505Sopenharmony_ci clen = iwe->len; 1311e5b75505Sopenharmony_ci if (clen > (size_t) (end - custom)) 1312e5b75505Sopenharmony_ci return; 1313e5b75505Sopenharmony_ci maxrate = 0; 1314e5b75505Sopenharmony_ci while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) { 1315e5b75505Sopenharmony_ci /* Note: may be misaligned, make a local, aligned copy */ 1316e5b75505Sopenharmony_ci os_memcpy(&p, custom, sizeof(struct iw_param)); 1317e5b75505Sopenharmony_ci if (p.value > maxrate) 1318e5b75505Sopenharmony_ci maxrate = p.value; 1319e5b75505Sopenharmony_ci clen -= sizeof(struct iw_param); 1320e5b75505Sopenharmony_ci custom += sizeof(struct iw_param); 1321e5b75505Sopenharmony_ci } 1322e5b75505Sopenharmony_ci 1323e5b75505Sopenharmony_ci /* Convert the maxrate from WE-style (b/s units) to 1324e5b75505Sopenharmony_ci * 802.11 rates (500000 b/s units). 1325e5b75505Sopenharmony_ci */ 1326e5b75505Sopenharmony_ci res->maxrate = maxrate / 500000; 1327e5b75505Sopenharmony_ci} 1328e5b75505Sopenharmony_ci 1329e5b75505Sopenharmony_ci 1330e5b75505Sopenharmony_cistatic void wext_get_scan_iwevgenie(struct iw_event *iwe, 1331e5b75505Sopenharmony_ci struct wext_scan_data *res, char *custom, 1332e5b75505Sopenharmony_ci char *end) 1333e5b75505Sopenharmony_ci{ 1334e5b75505Sopenharmony_ci char *genie, *gpos, *gend; 1335e5b75505Sopenharmony_ci u8 *tmp; 1336e5b75505Sopenharmony_ci 1337e5b75505Sopenharmony_ci if (iwe->u.data.length == 0) 1338e5b75505Sopenharmony_ci return; 1339e5b75505Sopenharmony_ci 1340e5b75505Sopenharmony_ci gpos = genie = custom; 1341e5b75505Sopenharmony_ci gend = genie + iwe->u.data.length; 1342e5b75505Sopenharmony_ci if (gend > end) { 1343e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IWEVGENIE overflow"); 1344e5b75505Sopenharmony_ci return; 1345e5b75505Sopenharmony_ci } 1346e5b75505Sopenharmony_ci 1347e5b75505Sopenharmony_ci tmp = os_realloc(res->ie, res->ie_len + gend - gpos); 1348e5b75505Sopenharmony_ci if (tmp == NULL) 1349e5b75505Sopenharmony_ci return; 1350e5b75505Sopenharmony_ci os_memcpy(tmp + res->ie_len, gpos, gend - gpos); 1351e5b75505Sopenharmony_ci res->ie = tmp; 1352e5b75505Sopenharmony_ci res->ie_len += gend - gpos; 1353e5b75505Sopenharmony_ci} 1354e5b75505Sopenharmony_ci 1355e5b75505Sopenharmony_ci 1356e5b75505Sopenharmony_cistatic void wext_get_scan_custom(struct iw_event *iwe, 1357e5b75505Sopenharmony_ci struct wext_scan_data *res, char *custom, 1358e5b75505Sopenharmony_ci char *end) 1359e5b75505Sopenharmony_ci{ 1360e5b75505Sopenharmony_ci size_t clen; 1361e5b75505Sopenharmony_ci u8 *tmp; 1362e5b75505Sopenharmony_ci 1363e5b75505Sopenharmony_ci clen = iwe->u.data.length; 1364e5b75505Sopenharmony_ci if (clen > (size_t) (end - custom)) 1365e5b75505Sopenharmony_ci return; 1366e5b75505Sopenharmony_ci 1367e5b75505Sopenharmony_ci if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) { 1368e5b75505Sopenharmony_ci char *spos; 1369e5b75505Sopenharmony_ci int bytes; 1370e5b75505Sopenharmony_ci spos = custom + 7; 1371e5b75505Sopenharmony_ci bytes = custom + clen - spos; 1372e5b75505Sopenharmony_ci if (bytes & 1 || bytes == 0) 1373e5b75505Sopenharmony_ci return; 1374e5b75505Sopenharmony_ci bytes /= 2; 1375e5b75505Sopenharmony_ci tmp = os_realloc(res->ie, res->ie_len + bytes); 1376e5b75505Sopenharmony_ci if (tmp == NULL) 1377e5b75505Sopenharmony_ci return; 1378e5b75505Sopenharmony_ci res->ie = tmp; 1379e5b75505Sopenharmony_ci if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) 1380e5b75505Sopenharmony_ci return; 1381e5b75505Sopenharmony_ci res->ie_len += bytes; 1382e5b75505Sopenharmony_ci } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { 1383e5b75505Sopenharmony_ci char *spos; 1384e5b75505Sopenharmony_ci int bytes; 1385e5b75505Sopenharmony_ci spos = custom + 7; 1386e5b75505Sopenharmony_ci bytes = custom + clen - spos; 1387e5b75505Sopenharmony_ci if (bytes & 1 || bytes == 0) 1388e5b75505Sopenharmony_ci return; 1389e5b75505Sopenharmony_ci bytes /= 2; 1390e5b75505Sopenharmony_ci tmp = os_realloc(res->ie, res->ie_len + bytes); 1391e5b75505Sopenharmony_ci if (tmp == NULL) 1392e5b75505Sopenharmony_ci return; 1393e5b75505Sopenharmony_ci res->ie = tmp; 1394e5b75505Sopenharmony_ci if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) 1395e5b75505Sopenharmony_ci return; 1396e5b75505Sopenharmony_ci res->ie_len += bytes; 1397e5b75505Sopenharmony_ci } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { 1398e5b75505Sopenharmony_ci char *spos; 1399e5b75505Sopenharmony_ci int bytes; 1400e5b75505Sopenharmony_ci u8 bin[8]; 1401e5b75505Sopenharmony_ci spos = custom + 4; 1402e5b75505Sopenharmony_ci bytes = custom + clen - spos; 1403e5b75505Sopenharmony_ci if (bytes != 16) { 1404e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes); 1405e5b75505Sopenharmony_ci return; 1406e5b75505Sopenharmony_ci } 1407e5b75505Sopenharmony_ci bytes /= 2; 1408e5b75505Sopenharmony_ci if (hexstr2bin(spos, bin, bytes) < 0) { 1409e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value"); 1410e5b75505Sopenharmony_ci return; 1411e5b75505Sopenharmony_ci } 1412e5b75505Sopenharmony_ci res->res.tsf += WPA_GET_BE64(bin); 1413e5b75505Sopenharmony_ci } 1414e5b75505Sopenharmony_ci} 1415e5b75505Sopenharmony_ci 1416e5b75505Sopenharmony_ci 1417e5b75505Sopenharmony_cistatic int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd) 1418e5b75505Sopenharmony_ci{ 1419e5b75505Sopenharmony_ci return drv->we_version_compiled > 18 && 1420e5b75505Sopenharmony_ci (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE || 1421e5b75505Sopenharmony_ci cmd == IWEVGENIE || cmd == IWEVCUSTOM); 1422e5b75505Sopenharmony_ci} 1423e5b75505Sopenharmony_ci 1424e5b75505Sopenharmony_ci 1425e5b75505Sopenharmony_cistatic void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, 1426e5b75505Sopenharmony_ci struct wext_scan_data *data) 1427e5b75505Sopenharmony_ci{ 1428e5b75505Sopenharmony_ci struct wpa_scan_res **tmp; 1429e5b75505Sopenharmony_ci struct wpa_scan_res *r; 1430e5b75505Sopenharmony_ci size_t extra_len; 1431e5b75505Sopenharmony_ci u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL; 1432e5b75505Sopenharmony_ci 1433e5b75505Sopenharmony_ci /* Figure out whether we need to fake any IEs */ 1434e5b75505Sopenharmony_ci pos = data->ie; 1435e5b75505Sopenharmony_ci end = pos + data->ie_len; 1436e5b75505Sopenharmony_ci while (pos && end - pos > 1) { 1437e5b75505Sopenharmony_ci if (2 + pos[1] > end - pos) 1438e5b75505Sopenharmony_ci break; 1439e5b75505Sopenharmony_ci if (pos[0] == WLAN_EID_SSID) 1440e5b75505Sopenharmony_ci ssid_ie = pos; 1441e5b75505Sopenharmony_ci else if (pos[0] == WLAN_EID_SUPP_RATES) 1442e5b75505Sopenharmony_ci rate_ie = pos; 1443e5b75505Sopenharmony_ci else if (pos[0] == WLAN_EID_EXT_SUPP_RATES) 1444e5b75505Sopenharmony_ci rate_ie = pos; 1445e5b75505Sopenharmony_ci pos += 2 + pos[1]; 1446e5b75505Sopenharmony_ci } 1447e5b75505Sopenharmony_ci 1448e5b75505Sopenharmony_ci extra_len = 0; 1449e5b75505Sopenharmony_ci if (ssid_ie == NULL) 1450e5b75505Sopenharmony_ci extra_len += 2 + data->ssid_len; 1451e5b75505Sopenharmony_ci if (rate_ie == NULL && data->maxrate) 1452e5b75505Sopenharmony_ci extra_len += 3; 1453e5b75505Sopenharmony_ci 1454e5b75505Sopenharmony_ci r = os_zalloc(sizeof(*r) + extra_len + data->ie_len); 1455e5b75505Sopenharmony_ci if (r == NULL) 1456e5b75505Sopenharmony_ci return; 1457e5b75505Sopenharmony_ci os_memcpy(r, &data->res, sizeof(*r)); 1458e5b75505Sopenharmony_ci r->ie_len = extra_len + data->ie_len; 1459e5b75505Sopenharmony_ci pos = (u8 *) (r + 1); 1460e5b75505Sopenharmony_ci if (ssid_ie == NULL) { 1461e5b75505Sopenharmony_ci /* 1462e5b75505Sopenharmony_ci * Generate a fake SSID IE since the driver did not report 1463e5b75505Sopenharmony_ci * a full IE list. 1464e5b75505Sopenharmony_ci */ 1465e5b75505Sopenharmony_ci *pos++ = WLAN_EID_SSID; 1466e5b75505Sopenharmony_ci *pos++ = data->ssid_len; 1467e5b75505Sopenharmony_ci os_memcpy(pos, data->ssid, data->ssid_len); 1468e5b75505Sopenharmony_ci pos += data->ssid_len; 1469e5b75505Sopenharmony_ci } 1470e5b75505Sopenharmony_ci if (rate_ie == NULL && data->maxrate) { 1471e5b75505Sopenharmony_ci /* 1472e5b75505Sopenharmony_ci * Generate a fake Supported Rates IE since the driver did not 1473e5b75505Sopenharmony_ci * report a full IE list. 1474e5b75505Sopenharmony_ci */ 1475e5b75505Sopenharmony_ci *pos++ = WLAN_EID_SUPP_RATES; 1476e5b75505Sopenharmony_ci *pos++ = 1; 1477e5b75505Sopenharmony_ci *pos++ = data->maxrate; 1478e5b75505Sopenharmony_ci } 1479e5b75505Sopenharmony_ci if (data->ie) 1480e5b75505Sopenharmony_ci os_memcpy(pos, data->ie, data->ie_len); 1481e5b75505Sopenharmony_ci 1482e5b75505Sopenharmony_ci tmp = os_realloc_array(res->res, res->num + 1, 1483e5b75505Sopenharmony_ci sizeof(struct wpa_scan_res *)); 1484e5b75505Sopenharmony_ci if (tmp == NULL) { 1485e5b75505Sopenharmony_ci os_free(r); 1486e5b75505Sopenharmony_ci return; 1487e5b75505Sopenharmony_ci } 1488e5b75505Sopenharmony_ci tmp[res->num++] = r; 1489e5b75505Sopenharmony_ci res->res = tmp; 1490e5b75505Sopenharmony_ci} 1491e5b75505Sopenharmony_ci 1492e5b75505Sopenharmony_ci 1493e5b75505Sopenharmony_ci/** 1494e5b75505Sopenharmony_ci * wpa_driver_wext_get_scan_results - Fetch the latest scan results 1495e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 1496e5b75505Sopenharmony_ci * Returns: Scan results on success, -1 on failure 1497e5b75505Sopenharmony_ci */ 1498e5b75505Sopenharmony_cistruct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) 1499e5b75505Sopenharmony_ci{ 1500e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1501e5b75505Sopenharmony_ci size_t len; 1502e5b75505Sopenharmony_ci int first; 1503e5b75505Sopenharmony_ci u8 *res_buf; 1504e5b75505Sopenharmony_ci struct iw_event iwe_buf, *iwe = &iwe_buf; 1505e5b75505Sopenharmony_ci char *pos, *end, *custom; 1506e5b75505Sopenharmony_ci struct wpa_scan_results *res; 1507e5b75505Sopenharmony_ci struct wext_scan_data data; 1508e5b75505Sopenharmony_ci 1509e5b75505Sopenharmony_ci res_buf = wpa_driver_wext_giwscan(drv, &len); 1510e5b75505Sopenharmony_ci if (res_buf == NULL) 1511e5b75505Sopenharmony_ci return NULL; 1512e5b75505Sopenharmony_ci 1513e5b75505Sopenharmony_ci first = 1; 1514e5b75505Sopenharmony_ci 1515e5b75505Sopenharmony_ci res = os_zalloc(sizeof(*res)); 1516e5b75505Sopenharmony_ci if (res == NULL) { 1517e5b75505Sopenharmony_ci os_free(res_buf); 1518e5b75505Sopenharmony_ci return NULL; 1519e5b75505Sopenharmony_ci } 1520e5b75505Sopenharmony_ci 1521e5b75505Sopenharmony_ci pos = (char *) res_buf; 1522e5b75505Sopenharmony_ci end = (char *) res_buf + len; 1523e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 1524e5b75505Sopenharmony_ci 1525e5b75505Sopenharmony_ci while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { 1526e5b75505Sopenharmony_ci /* Event data may be unaligned, so make a local, aligned copy 1527e5b75505Sopenharmony_ci * before processing. */ 1528e5b75505Sopenharmony_ci os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); 1529e5b75505Sopenharmony_ci if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) 1530e5b75505Sopenharmony_ci break; 1531e5b75505Sopenharmony_ci 1532e5b75505Sopenharmony_ci custom = pos + IW_EV_POINT_LEN; 1533e5b75505Sopenharmony_ci if (wext_19_iw_point(drv, iwe->cmd)) { 1534e5b75505Sopenharmony_ci /* WE-19 removed the pointer from struct iw_point */ 1535e5b75505Sopenharmony_ci char *dpos = (char *) &iwe_buf.u.data.length; 1536e5b75505Sopenharmony_ci int dlen = dpos - (char *) &iwe_buf; 1537e5b75505Sopenharmony_ci os_memcpy(dpos, pos + IW_EV_LCP_LEN, 1538e5b75505Sopenharmony_ci sizeof(struct iw_event) - dlen); 1539e5b75505Sopenharmony_ci } else { 1540e5b75505Sopenharmony_ci os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); 1541e5b75505Sopenharmony_ci custom += IW_EV_POINT_OFF; 1542e5b75505Sopenharmony_ci } 1543e5b75505Sopenharmony_ci 1544e5b75505Sopenharmony_ci switch (iwe->cmd) { 1545e5b75505Sopenharmony_ci case SIOCGIWAP: 1546e5b75505Sopenharmony_ci if (!first) 1547e5b75505Sopenharmony_ci wpa_driver_wext_add_scan_entry(res, &data); 1548e5b75505Sopenharmony_ci first = 0; 1549e5b75505Sopenharmony_ci os_free(data.ie); 1550e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 1551e5b75505Sopenharmony_ci os_memcpy(data.res.bssid, 1552e5b75505Sopenharmony_ci iwe->u.ap_addr.sa_data, ETH_ALEN); 1553e5b75505Sopenharmony_ci break; 1554e5b75505Sopenharmony_ci case SIOCGIWMODE: 1555e5b75505Sopenharmony_ci wext_get_scan_mode(iwe, &data); 1556e5b75505Sopenharmony_ci break; 1557e5b75505Sopenharmony_ci case SIOCGIWESSID: 1558e5b75505Sopenharmony_ci wext_get_scan_ssid(iwe, &data, custom, end); 1559e5b75505Sopenharmony_ci break; 1560e5b75505Sopenharmony_ci case SIOCGIWFREQ: 1561e5b75505Sopenharmony_ci wext_get_scan_freq(iwe, &data); 1562e5b75505Sopenharmony_ci break; 1563e5b75505Sopenharmony_ci case IWEVQUAL: 1564e5b75505Sopenharmony_ci wext_get_scan_qual(drv, iwe, &data); 1565e5b75505Sopenharmony_ci break; 1566e5b75505Sopenharmony_ci case SIOCGIWENCODE: 1567e5b75505Sopenharmony_ci wext_get_scan_encode(iwe, &data); 1568e5b75505Sopenharmony_ci break; 1569e5b75505Sopenharmony_ci case SIOCGIWRATE: 1570e5b75505Sopenharmony_ci wext_get_scan_rate(iwe, &data, pos, end); 1571e5b75505Sopenharmony_ci break; 1572e5b75505Sopenharmony_ci case IWEVGENIE: 1573e5b75505Sopenharmony_ci wext_get_scan_iwevgenie(iwe, &data, custom, end); 1574e5b75505Sopenharmony_ci break; 1575e5b75505Sopenharmony_ci case IWEVCUSTOM: 1576e5b75505Sopenharmony_ci wext_get_scan_custom(iwe, &data, custom, end); 1577e5b75505Sopenharmony_ci break; 1578e5b75505Sopenharmony_ci } 1579e5b75505Sopenharmony_ci 1580e5b75505Sopenharmony_ci pos += iwe->len; 1581e5b75505Sopenharmony_ci } 1582e5b75505Sopenharmony_ci os_free(res_buf); 1583e5b75505Sopenharmony_ci res_buf = NULL; 1584e5b75505Sopenharmony_ci if (!first) 1585e5b75505Sopenharmony_ci wpa_driver_wext_add_scan_entry(res, &data); 1586e5b75505Sopenharmony_ci os_free(data.ie); 1587e5b75505Sopenharmony_ci 1588e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", 1589e5b75505Sopenharmony_ci (unsigned long) len, (unsigned long) res->num); 1590e5b75505Sopenharmony_ci 1591e5b75505Sopenharmony_ci return res; 1592e5b75505Sopenharmony_ci} 1593e5b75505Sopenharmony_ci 1594e5b75505Sopenharmony_ci 1595e5b75505Sopenharmony_cistatic int wpa_driver_wext_get_range(void *priv) 1596e5b75505Sopenharmony_ci{ 1597e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1598e5b75505Sopenharmony_ci struct iw_range *range; 1599e5b75505Sopenharmony_ci struct iwreq iwr; 1600e5b75505Sopenharmony_ci int minlen; 1601e5b75505Sopenharmony_ci size_t buflen; 1602e5b75505Sopenharmony_ci 1603e5b75505Sopenharmony_ci /* 1604e5b75505Sopenharmony_ci * Use larger buffer than struct iw_range in order to allow the 1605e5b75505Sopenharmony_ci * structure to grow in the future. 1606e5b75505Sopenharmony_ci */ 1607e5b75505Sopenharmony_ci buflen = sizeof(struct iw_range) + 500; 1608e5b75505Sopenharmony_ci range = os_zalloc(buflen); 1609e5b75505Sopenharmony_ci if (range == NULL) 1610e5b75505Sopenharmony_ci return -1; 1611e5b75505Sopenharmony_ci 1612e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1613e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1614e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) range; 1615e5b75505Sopenharmony_ci iwr.u.data.length = buflen; 1616e5b75505Sopenharmony_ci 1617e5b75505Sopenharmony_ci minlen = ((char *) &range->enc_capa) - (char *) range + 1618e5b75505Sopenharmony_ci sizeof(range->enc_capa); 1619e5b75505Sopenharmony_ci 1620e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { 1621e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", 1622e5b75505Sopenharmony_ci strerror(errno)); 1623e5b75505Sopenharmony_ci os_free(range); 1624e5b75505Sopenharmony_ci return -1; 1625e5b75505Sopenharmony_ci } else if (iwr.u.data.length >= minlen && 1626e5b75505Sopenharmony_ci range->we_version_compiled >= 18) { 1627e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " 1628e5b75505Sopenharmony_ci "WE(source)=%d enc_capa=0x%x", 1629e5b75505Sopenharmony_ci range->we_version_compiled, 1630e5b75505Sopenharmony_ci range->we_version_source, 1631e5b75505Sopenharmony_ci range->enc_capa); 1632e5b75505Sopenharmony_ci drv->has_capability = 1; 1633e5b75505Sopenharmony_ci drv->we_version_compiled = range->we_version_compiled; 1634e5b75505Sopenharmony_ci if (range->enc_capa & IW_ENC_CAPA_WPA) { 1635e5b75505Sopenharmony_ci drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1636e5b75505Sopenharmony_ci WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; 1637e5b75505Sopenharmony_ci } 1638e5b75505Sopenharmony_ci if (range->enc_capa & IW_ENC_CAPA_WPA2) { 1639e5b75505Sopenharmony_ci drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1640e5b75505Sopenharmony_ci WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; 1641e5b75505Sopenharmony_ci } 1642e5b75505Sopenharmony_ci drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | 1643e5b75505Sopenharmony_ci WPA_DRIVER_CAPA_ENC_WEP104; 1644e5b75505Sopenharmony_ci drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128; 1645e5b75505Sopenharmony_ci if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) 1646e5b75505Sopenharmony_ci drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; 1647e5b75505Sopenharmony_ci if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) 1648e5b75505Sopenharmony_ci drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; 1649e5b75505Sopenharmony_ci if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE) 1650e5b75505Sopenharmony_ci drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK | 1651e5b75505Sopenharmony_ci WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X; 1652e5b75505Sopenharmony_ci drv->capa.auth = WPA_DRIVER_AUTH_OPEN | 1653e5b75505Sopenharmony_ci WPA_DRIVER_AUTH_SHARED | 1654e5b75505Sopenharmony_ci WPA_DRIVER_AUTH_LEAP; 1655e5b75505Sopenharmony_ci drv->capa.max_scan_ssids = 1; 1656e5b75505Sopenharmony_ci 1657e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " 1658e5b75505Sopenharmony_ci "flags 0x%llx", 1659e5b75505Sopenharmony_ci drv->capa.key_mgmt, drv->capa.enc, 1660e5b75505Sopenharmony_ci (unsigned long long) drv->capa.flags); 1661e5b75505Sopenharmony_ci } else { 1662e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " 1663e5b75505Sopenharmony_ci "assuming WPA is not supported"); 1664e5b75505Sopenharmony_ci } 1665e5b75505Sopenharmony_ci 1666e5b75505Sopenharmony_ci drv->max_level = range->max_qual.level; 1667e5b75505Sopenharmony_ci 1668e5b75505Sopenharmony_ci os_free(range); 1669e5b75505Sopenharmony_ci return 0; 1670e5b75505Sopenharmony_ci} 1671e5b75505Sopenharmony_ci 1672e5b75505Sopenharmony_ci 1673e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, 1674e5b75505Sopenharmony_ci const u8 *psk) 1675e5b75505Sopenharmony_ci{ 1676e5b75505Sopenharmony_ci struct iw_encode_ext *ext; 1677e5b75505Sopenharmony_ci struct iwreq iwr; 1678e5b75505Sopenharmony_ci int ret; 1679e5b75505Sopenharmony_ci 1680e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 1681e5b75505Sopenharmony_ci 1682e5b75505Sopenharmony_ci if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) 1683e5b75505Sopenharmony_ci return 0; 1684e5b75505Sopenharmony_ci 1685e5b75505Sopenharmony_ci if (!psk) 1686e5b75505Sopenharmony_ci return 0; 1687e5b75505Sopenharmony_ci 1688e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1689e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1690e5b75505Sopenharmony_ci 1691e5b75505Sopenharmony_ci ext = os_zalloc(sizeof(*ext) + PMK_LEN); 1692e5b75505Sopenharmony_ci if (ext == NULL) 1693e5b75505Sopenharmony_ci return -1; 1694e5b75505Sopenharmony_ci 1695e5b75505Sopenharmony_ci iwr.u.encoding.pointer = (caddr_t) ext; 1696e5b75505Sopenharmony_ci iwr.u.encoding.length = sizeof(*ext) + PMK_LEN; 1697e5b75505Sopenharmony_ci ext->key_len = PMK_LEN; 1698e5b75505Sopenharmony_ci os_memcpy(&ext->key, psk, ext->key_len); 1699e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_PMK; 1700e5b75505Sopenharmony_ci 1701e5b75505Sopenharmony_ci ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr); 1702e5b75505Sopenharmony_ci if (ret < 0) 1703e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s", 1704e5b75505Sopenharmony_ci strerror(errno)); 1705e5b75505Sopenharmony_ci os_free(ext); 1706e5b75505Sopenharmony_ci 1707e5b75505Sopenharmony_ci return ret; 1708e5b75505Sopenharmony_ci} 1709e5b75505Sopenharmony_ci 1710e5b75505Sopenharmony_ci 1711e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, 1712e5b75505Sopenharmony_ci const u8 *addr, int key_idx, 1713e5b75505Sopenharmony_ci int set_tx, const u8 *seq, 1714e5b75505Sopenharmony_ci size_t seq_len, 1715e5b75505Sopenharmony_ci const u8 *key, size_t key_len) 1716e5b75505Sopenharmony_ci{ 1717e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1718e5b75505Sopenharmony_ci struct iwreq iwr; 1719e5b75505Sopenharmony_ci int ret = 0; 1720e5b75505Sopenharmony_ci struct iw_encode_ext *ext; 1721e5b75505Sopenharmony_ci 1722e5b75505Sopenharmony_ci if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) { 1723e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu", 1724e5b75505Sopenharmony_ci __FUNCTION__, (unsigned long) seq_len); 1725e5b75505Sopenharmony_ci return -1; 1726e5b75505Sopenharmony_ci } 1727e5b75505Sopenharmony_ci 1728e5b75505Sopenharmony_ci ext = os_zalloc(sizeof(*ext) + key_len); 1729e5b75505Sopenharmony_ci if (ext == NULL) 1730e5b75505Sopenharmony_ci return -1; 1731e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1732e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1733e5b75505Sopenharmony_ci iwr.u.encoding.flags = key_idx + 1; 1734e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_TEMP; 1735e5b75505Sopenharmony_ci if (alg == WPA_ALG_NONE) 1736e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_DISABLED; 1737e5b75505Sopenharmony_ci iwr.u.encoding.pointer = (caddr_t) ext; 1738e5b75505Sopenharmony_ci iwr.u.encoding.length = sizeof(*ext) + key_len; 1739e5b75505Sopenharmony_ci 1740e5b75505Sopenharmony_ci if (addr == NULL || is_broadcast_ether_addr(addr)) 1741e5b75505Sopenharmony_ci ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY; 1742e5b75505Sopenharmony_ci if (set_tx) 1743e5b75505Sopenharmony_ci ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; 1744e5b75505Sopenharmony_ci 1745e5b75505Sopenharmony_ci ext->addr.sa_family = ARPHRD_ETHER; 1746e5b75505Sopenharmony_ci if (addr) 1747e5b75505Sopenharmony_ci os_memcpy(ext->addr.sa_data, addr, ETH_ALEN); 1748e5b75505Sopenharmony_ci else 1749e5b75505Sopenharmony_ci os_memset(ext->addr.sa_data, 0xff, ETH_ALEN); 1750e5b75505Sopenharmony_ci if (key && key_len) { 1751e5b75505Sopenharmony_ci os_memcpy(ext + 1, key, key_len); 1752e5b75505Sopenharmony_ci ext->key_len = key_len; 1753e5b75505Sopenharmony_ci } 1754e5b75505Sopenharmony_ci switch (alg) { 1755e5b75505Sopenharmony_ci case WPA_ALG_NONE: 1756e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_NONE; 1757e5b75505Sopenharmony_ci break; 1758e5b75505Sopenharmony_ci case WPA_ALG_WEP: 1759e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_WEP; 1760e5b75505Sopenharmony_ci break; 1761e5b75505Sopenharmony_ci case WPA_ALG_TKIP: 1762e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_TKIP; 1763e5b75505Sopenharmony_ci break; 1764e5b75505Sopenharmony_ci case WPA_ALG_CCMP: 1765e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_CCMP; 1766e5b75505Sopenharmony_ci break; 1767e5b75505Sopenharmony_ci case WPA_ALG_PMK: 1768e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_PMK; 1769e5b75505Sopenharmony_ci break; 1770e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 1771e5b75505Sopenharmony_ci case WPA_ALG_IGTK: 1772e5b75505Sopenharmony_ci ext->alg = IW_ENCODE_ALG_AES_CMAC; 1773e5b75505Sopenharmony_ci break; 1774e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 1775e5b75505Sopenharmony_ci default: 1776e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", 1777e5b75505Sopenharmony_ci __FUNCTION__, alg); 1778e5b75505Sopenharmony_ci os_free(ext); 1779e5b75505Sopenharmony_ci return -1; 1780e5b75505Sopenharmony_ci } 1781e5b75505Sopenharmony_ci 1782e5b75505Sopenharmony_ci if (seq && seq_len) { 1783e5b75505Sopenharmony_ci ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID; 1784e5b75505Sopenharmony_ci os_memcpy(ext->rx_seq, seq, seq_len); 1785e5b75505Sopenharmony_ci } 1786e5b75505Sopenharmony_ci 1787e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) { 1788e5b75505Sopenharmony_ci ret = errno == EOPNOTSUPP ? -2 : -1; 1789e5b75505Sopenharmony_ci if (errno == ENODEV) { 1790e5b75505Sopenharmony_ci /* 1791e5b75505Sopenharmony_ci * ndiswrapper seems to be returning incorrect error 1792e5b75505Sopenharmony_ci * code.. */ 1793e5b75505Sopenharmony_ci ret = -2; 1794e5b75505Sopenharmony_ci } 1795e5b75505Sopenharmony_ci 1796e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s", 1797e5b75505Sopenharmony_ci strerror(errno)); 1798e5b75505Sopenharmony_ci } 1799e5b75505Sopenharmony_ci 1800e5b75505Sopenharmony_ci os_free(ext); 1801e5b75505Sopenharmony_ci return ret; 1802e5b75505Sopenharmony_ci} 1803e5b75505Sopenharmony_ci 1804e5b75505Sopenharmony_ci 1805e5b75505Sopenharmony_ci/** 1806e5b75505Sopenharmony_ci * wpa_driver_wext_set_key - Configure encryption key 1807e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 1808e5b75505Sopenharmony_ci * @priv: Private driver interface data 1809e5b75505Sopenharmony_ci * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, 1810e5b75505Sopenharmony_ci * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. 1811e5b75505Sopenharmony_ci * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for 1812e5b75505Sopenharmony_ci * broadcast/default keys 1813e5b75505Sopenharmony_ci * @key_idx: key index (0..3), usually 0 for unicast keys 1814e5b75505Sopenharmony_ci * @set_tx: Configure this key as the default Tx key (only used when 1815e5b75505Sopenharmony_ci * driver does not support separate unicast/individual key 1816e5b75505Sopenharmony_ci * @seq: Sequence number/packet number, seq_len octets, the next 1817e5b75505Sopenharmony_ci * packet number to be used for in replay protection; configured 1818e5b75505Sopenharmony_ci * for Rx keys (in most cases, this is only used with broadcast 1819e5b75505Sopenharmony_ci * keys and set to zero for unicast keys) 1820e5b75505Sopenharmony_ci * @seq_len: Length of the seq, depends on the algorithm: 1821e5b75505Sopenharmony_ci * TKIP: 6 octets, CCMP: 6 octets 1822e5b75505Sopenharmony_ci * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, 1823e5b75505Sopenharmony_ci * 8-byte Rx Mic Key 1824e5b75505Sopenharmony_ci * @key_len: Length of the key buffer in octets (WEP: 5 or 13, 1825e5b75505Sopenharmony_ci * TKIP: 32, CCMP: 16) 1826e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 1827e5b75505Sopenharmony_ci * 1828e5b75505Sopenharmony_ci * This function uses SIOCSIWENCODEEXT by default, but tries to use 1829e5b75505Sopenharmony_ci * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. 1830e5b75505Sopenharmony_ci */ 1831e5b75505Sopenharmony_ciint wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, 1832e5b75505Sopenharmony_ci const u8 *addr, int key_idx, 1833e5b75505Sopenharmony_ci int set_tx, const u8 *seq, size_t seq_len, 1834e5b75505Sopenharmony_ci const u8 *key, size_t key_len) 1835e5b75505Sopenharmony_ci{ 1836e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1837e5b75505Sopenharmony_ci struct iwreq iwr; 1838e5b75505Sopenharmony_ci int ret = 0; 1839e5b75505Sopenharmony_ci 1840e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " 1841e5b75505Sopenharmony_ci "key_len=%lu", 1842e5b75505Sopenharmony_ci __FUNCTION__, alg, key_idx, set_tx, 1843e5b75505Sopenharmony_ci (unsigned long) seq_len, (unsigned long) key_len); 1844e5b75505Sopenharmony_ci 1845e5b75505Sopenharmony_ci ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx, 1846e5b75505Sopenharmony_ci seq, seq_len, key, key_len); 1847e5b75505Sopenharmony_ci if (ret == 0) 1848e5b75505Sopenharmony_ci return 0; 1849e5b75505Sopenharmony_ci 1850e5b75505Sopenharmony_ci if (ret == -2 && 1851e5b75505Sopenharmony_ci (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) { 1852e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Driver did not support " 1853e5b75505Sopenharmony_ci "SIOCSIWENCODEEXT, trying SIOCSIWENCODE"); 1854e5b75505Sopenharmony_ci ret = 0; 1855e5b75505Sopenharmony_ci } else { 1856e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Driver did not support " 1857e5b75505Sopenharmony_ci "SIOCSIWENCODEEXT"); 1858e5b75505Sopenharmony_ci return ret; 1859e5b75505Sopenharmony_ci } 1860e5b75505Sopenharmony_ci 1861e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1862e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1863e5b75505Sopenharmony_ci iwr.u.encoding.flags = key_idx + 1; 1864e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_TEMP; 1865e5b75505Sopenharmony_ci if (alg == WPA_ALG_NONE) 1866e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_DISABLED; 1867e5b75505Sopenharmony_ci iwr.u.encoding.pointer = (caddr_t) key; 1868e5b75505Sopenharmony_ci iwr.u.encoding.length = key_len; 1869e5b75505Sopenharmony_ci 1870e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { 1871e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s", 1872e5b75505Sopenharmony_ci strerror(errno)); 1873e5b75505Sopenharmony_ci ret = -1; 1874e5b75505Sopenharmony_ci } 1875e5b75505Sopenharmony_ci 1876e5b75505Sopenharmony_ci if (set_tx && alg != WPA_ALG_NONE) { 1877e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1878e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1879e5b75505Sopenharmony_ci iwr.u.encoding.flags = key_idx + 1; 1880e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_TEMP; 1881e5b75505Sopenharmony_ci iwr.u.encoding.pointer = (caddr_t) NULL; 1882e5b75505Sopenharmony_ci iwr.u.encoding.length = 0; 1883e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { 1884e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1885e5b75505Sopenharmony_ci "ioctl[SIOCSIWENCODE] (set_tx): %s", 1886e5b75505Sopenharmony_ci strerror(errno)); 1887e5b75505Sopenharmony_ci ret = -1; 1888e5b75505Sopenharmony_ci } 1889e5b75505Sopenharmony_ci } 1890e5b75505Sopenharmony_ci 1891e5b75505Sopenharmony_ci return ret; 1892e5b75505Sopenharmony_ci} 1893e5b75505Sopenharmony_ci 1894e5b75505Sopenharmony_ci 1895e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_countermeasures(void *priv, 1896e5b75505Sopenharmony_ci int enabled) 1897e5b75505Sopenharmony_ci{ 1898e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1899e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 1900e5b75505Sopenharmony_ci return wpa_driver_wext_set_auth_param(drv, 1901e5b75505Sopenharmony_ci IW_AUTH_TKIP_COUNTERMEASURES, 1902e5b75505Sopenharmony_ci enabled); 1903e5b75505Sopenharmony_ci} 1904e5b75505Sopenharmony_ci 1905e5b75505Sopenharmony_ci 1906e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_drop_unencrypted(void *priv, 1907e5b75505Sopenharmony_ci int enabled) 1908e5b75505Sopenharmony_ci{ 1909e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 1910e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 1911e5b75505Sopenharmony_ci drv->use_crypt = enabled; 1912e5b75505Sopenharmony_ci return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, 1913e5b75505Sopenharmony_ci enabled); 1914e5b75505Sopenharmony_ci} 1915e5b75505Sopenharmony_ci 1916e5b75505Sopenharmony_ci 1917e5b75505Sopenharmony_cistatic int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv, 1918e5b75505Sopenharmony_ci const u8 *addr, int cmd, u16 reason_code) 1919e5b75505Sopenharmony_ci{ 1920e5b75505Sopenharmony_ci struct iwreq iwr; 1921e5b75505Sopenharmony_ci struct iw_mlme mlme; 1922e5b75505Sopenharmony_ci int ret = 0; 1923e5b75505Sopenharmony_ci 1924e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1925e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1926e5b75505Sopenharmony_ci os_memset(&mlme, 0, sizeof(mlme)); 1927e5b75505Sopenharmony_ci mlme.cmd = cmd; 1928e5b75505Sopenharmony_ci mlme.reason_code = reason_code; 1929e5b75505Sopenharmony_ci mlme.addr.sa_family = ARPHRD_ETHER; 1930e5b75505Sopenharmony_ci os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); 1931e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) &mlme; 1932e5b75505Sopenharmony_ci iwr.u.data.length = sizeof(mlme); 1933e5b75505Sopenharmony_ci 1934e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { 1935e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s", 1936e5b75505Sopenharmony_ci strerror(errno)); 1937e5b75505Sopenharmony_ci ret = -1; 1938e5b75505Sopenharmony_ci } 1939e5b75505Sopenharmony_ci 1940e5b75505Sopenharmony_ci return ret; 1941e5b75505Sopenharmony_ci} 1942e5b75505Sopenharmony_ci 1943e5b75505Sopenharmony_ci 1944e5b75505Sopenharmony_cistatic void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) 1945e5b75505Sopenharmony_ci{ 1946e5b75505Sopenharmony_ci struct iwreq iwr; 1947e5b75505Sopenharmony_ci const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 1948e5b75505Sopenharmony_ci u8 ssid[SSID_MAX_LEN]; 1949e5b75505Sopenharmony_ci int i; 1950e5b75505Sopenharmony_ci 1951e5b75505Sopenharmony_ci /* 1952e5b75505Sopenharmony_ci * Only force-disconnect when the card is in infrastructure mode, 1953e5b75505Sopenharmony_ci * otherwise the driver might interpret the cleared BSSID and random 1954e5b75505Sopenharmony_ci * SSID as an attempt to create a new ad-hoc network. 1955e5b75505Sopenharmony_ci */ 1956e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1957e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 1958e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { 1959e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s", 1960e5b75505Sopenharmony_ci strerror(errno)); 1961e5b75505Sopenharmony_ci iwr.u.mode = IW_MODE_INFRA; 1962e5b75505Sopenharmony_ci } 1963e5b75505Sopenharmony_ci 1964e5b75505Sopenharmony_ci if (iwr.u.mode == IW_MODE_INFRA) { 1965e5b75505Sopenharmony_ci /* Clear the BSSID selection */ 1966e5b75505Sopenharmony_ci if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) { 1967e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID " 1968e5b75505Sopenharmony_ci "selection on disconnect"); 1969e5b75505Sopenharmony_ci } 1970e5b75505Sopenharmony_ci 1971e5b75505Sopenharmony_ci if (drv->cfg80211) { 1972e5b75505Sopenharmony_ci /* 1973e5b75505Sopenharmony_ci * cfg80211 supports SIOCSIWMLME commands, so there is 1974e5b75505Sopenharmony_ci * no need for the random SSID hack, but clear the 1975e5b75505Sopenharmony_ci * SSID. 1976e5b75505Sopenharmony_ci */ 1977e5b75505Sopenharmony_ci if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { 1978e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " 1979e5b75505Sopenharmony_ci "SSID on disconnect"); 1980e5b75505Sopenharmony_ci } 1981e5b75505Sopenharmony_ci return; 1982e5b75505Sopenharmony_ci } 1983e5b75505Sopenharmony_ci 1984e5b75505Sopenharmony_ci /* 1985e5b75505Sopenharmony_ci * Set a random SSID to make sure the driver will not be trying 1986e5b75505Sopenharmony_ci * to associate with something even if it does not understand 1987e5b75505Sopenharmony_ci * SIOCSIWMLME commands (or tries to associate automatically 1988e5b75505Sopenharmony_ci * after deauth/disassoc). 1989e5b75505Sopenharmony_ci */ 1990e5b75505Sopenharmony_ci for (i = 0; i < SSID_MAX_LEN; i++) 1991e5b75505Sopenharmony_ci ssid[i] = rand() & 0xFF; 1992e5b75505Sopenharmony_ci if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) { 1993e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " 1994e5b75505Sopenharmony_ci "SSID to disconnect"); 1995e5b75505Sopenharmony_ci } 1996e5b75505Sopenharmony_ci } 1997e5b75505Sopenharmony_ci} 1998e5b75505Sopenharmony_ci 1999e5b75505Sopenharmony_ci 2000e5b75505Sopenharmony_cistatic int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr, 2001e5b75505Sopenharmony_ci u16 reason_code) 2002e5b75505Sopenharmony_ci{ 2003e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2004e5b75505Sopenharmony_ci int ret; 2005e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 2006e5b75505Sopenharmony_ci ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code); 2007e5b75505Sopenharmony_ci wpa_driver_wext_disconnect(drv); 2008e5b75505Sopenharmony_ci return ret; 2009e5b75505Sopenharmony_ci} 2010e5b75505Sopenharmony_ci 2011e5b75505Sopenharmony_ci 2012e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, 2013e5b75505Sopenharmony_ci size_t ie_len) 2014e5b75505Sopenharmony_ci{ 2015e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2016e5b75505Sopenharmony_ci struct iwreq iwr; 2017e5b75505Sopenharmony_ci int ret = 0; 2018e5b75505Sopenharmony_ci 2019e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 2020e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 2021e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) ie; 2022e5b75505Sopenharmony_ci iwr.u.data.length = ie_len; 2023e5b75505Sopenharmony_ci 2024e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { 2025e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s", 2026e5b75505Sopenharmony_ci strerror(errno)); 2027e5b75505Sopenharmony_ci ret = -1; 2028e5b75505Sopenharmony_ci } 2029e5b75505Sopenharmony_ci 2030e5b75505Sopenharmony_ci return ret; 2031e5b75505Sopenharmony_ci} 2032e5b75505Sopenharmony_ci 2033e5b75505Sopenharmony_ci 2034e5b75505Sopenharmony_ciint wpa_driver_wext_cipher2wext(int cipher) 2035e5b75505Sopenharmony_ci{ 2036e5b75505Sopenharmony_ci switch (cipher) { 2037e5b75505Sopenharmony_ci case WPA_CIPHER_NONE: 2038e5b75505Sopenharmony_ci return IW_AUTH_CIPHER_NONE; 2039e5b75505Sopenharmony_ci case WPA_CIPHER_WEP40: 2040e5b75505Sopenharmony_ci return IW_AUTH_CIPHER_WEP40; 2041e5b75505Sopenharmony_ci case WPA_CIPHER_TKIP: 2042e5b75505Sopenharmony_ci return IW_AUTH_CIPHER_TKIP; 2043e5b75505Sopenharmony_ci case WPA_CIPHER_CCMP: 2044e5b75505Sopenharmony_ci return IW_AUTH_CIPHER_CCMP; 2045e5b75505Sopenharmony_ci case WPA_CIPHER_WEP104: 2046e5b75505Sopenharmony_ci return IW_AUTH_CIPHER_WEP104; 2047e5b75505Sopenharmony_ci default: 2048e5b75505Sopenharmony_ci return 0; 2049e5b75505Sopenharmony_ci } 2050e5b75505Sopenharmony_ci} 2051e5b75505Sopenharmony_ci 2052e5b75505Sopenharmony_ci 2053e5b75505Sopenharmony_ciint wpa_driver_wext_keymgmt2wext(int keymgmt) 2054e5b75505Sopenharmony_ci{ 2055e5b75505Sopenharmony_ci switch (keymgmt) { 2056e5b75505Sopenharmony_ci case WPA_KEY_MGMT_IEEE8021X: 2057e5b75505Sopenharmony_ci case WPA_KEY_MGMT_IEEE8021X_NO_WPA: 2058e5b75505Sopenharmony_ci return IW_AUTH_KEY_MGMT_802_1X; 2059e5b75505Sopenharmony_ci case WPA_KEY_MGMT_PSK: 2060e5b75505Sopenharmony_ci return IW_AUTH_KEY_MGMT_PSK; 2061e5b75505Sopenharmony_ci default: 2062e5b75505Sopenharmony_ci return 0; 2063e5b75505Sopenharmony_ci } 2064e5b75505Sopenharmony_ci} 2065e5b75505Sopenharmony_ci 2066e5b75505Sopenharmony_ci 2067e5b75505Sopenharmony_cistatic int 2068e5b75505Sopenharmony_ciwpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv, 2069e5b75505Sopenharmony_ci struct wpa_driver_associate_params *params) 2070e5b75505Sopenharmony_ci{ 2071e5b75505Sopenharmony_ci struct iwreq iwr; 2072e5b75505Sopenharmony_ci int ret = 0; 2073e5b75505Sopenharmony_ci 2074e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " 2075e5b75505Sopenharmony_ci "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); 2076e5b75505Sopenharmony_ci 2077e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 2078e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 2079e5b75505Sopenharmony_ci /* Just changing mode, not actual keys */ 2080e5b75505Sopenharmony_ci iwr.u.encoding.flags = 0; 2081e5b75505Sopenharmony_ci iwr.u.encoding.pointer = (caddr_t) NULL; 2082e5b75505Sopenharmony_ci iwr.u.encoding.length = 0; 2083e5b75505Sopenharmony_ci 2084e5b75505Sopenharmony_ci /* 2085e5b75505Sopenharmony_ci * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two 2086e5b75505Sopenharmony_ci * different things. Here they are used to indicate Open System vs. 2087e5b75505Sopenharmony_ci * Shared Key authentication algorithm. However, some drivers may use 2088e5b75505Sopenharmony_ci * them to select between open/restricted WEP encrypted (open = allow 2089e5b75505Sopenharmony_ci * both unencrypted and encrypted frames; restricted = only allow 2090e5b75505Sopenharmony_ci * encrypted frames). 2091e5b75505Sopenharmony_ci */ 2092e5b75505Sopenharmony_ci 2093e5b75505Sopenharmony_ci if (!drv->use_crypt) { 2094e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_DISABLED; 2095e5b75505Sopenharmony_ci } else { 2096e5b75505Sopenharmony_ci if (params->auth_alg & WPA_AUTH_ALG_OPEN) 2097e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_OPEN; 2098e5b75505Sopenharmony_ci if (params->auth_alg & WPA_AUTH_ALG_SHARED) 2099e5b75505Sopenharmony_ci iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; 2100e5b75505Sopenharmony_ci } 2101e5b75505Sopenharmony_ci 2102e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { 2103e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s", 2104e5b75505Sopenharmony_ci strerror(errno)); 2105e5b75505Sopenharmony_ci ret = -1; 2106e5b75505Sopenharmony_ci } 2107e5b75505Sopenharmony_ci 2108e5b75505Sopenharmony_ci return ret; 2109e5b75505Sopenharmony_ci} 2110e5b75505Sopenharmony_ci 2111e5b75505Sopenharmony_ci 2112e5b75505Sopenharmony_ciint wpa_driver_wext_associate(void *priv, 2113e5b75505Sopenharmony_ci struct wpa_driver_associate_params *params) 2114e5b75505Sopenharmony_ci{ 2115e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2116e5b75505Sopenharmony_ci int ret = 0; 2117e5b75505Sopenharmony_ci int allow_unencrypted_eapol; 2118e5b75505Sopenharmony_ci int value; 2119e5b75505Sopenharmony_ci 2120e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 2121e5b75505Sopenharmony_ci 2122e5b75505Sopenharmony_ci if (drv->cfg80211) { 2123e5b75505Sopenharmony_ci /* 2124e5b75505Sopenharmony_ci * Stop cfg80211 from trying to associate before we are done 2125e5b75505Sopenharmony_ci * with all parameters. 2126e5b75505Sopenharmony_ci */ 2127e5b75505Sopenharmony_ci if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { 2128e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2129e5b75505Sopenharmony_ci "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)"); 2130e5b75505Sopenharmony_ci /* continue anyway */ 2131e5b75505Sopenharmony_ci } 2132e5b75505Sopenharmony_ci } 2133e5b75505Sopenharmony_ci 2134e5b75505Sopenharmony_ci if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) 2135e5b75505Sopenharmony_ci < 0) 2136e5b75505Sopenharmony_ci ret = -1; 2137e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0) 2138e5b75505Sopenharmony_ci ret = -1; 2139e5b75505Sopenharmony_ci if (wpa_driver_wext_set_mode(drv, params->mode) < 0) 2140e5b75505Sopenharmony_ci ret = -1; 2141e5b75505Sopenharmony_ci 2142e5b75505Sopenharmony_ci /* 2143e5b75505Sopenharmony_ci * If the driver did not support SIOCSIWAUTH, fallback to 2144e5b75505Sopenharmony_ci * SIOCSIWENCODE here. 2145e5b75505Sopenharmony_ci */ 2146e5b75505Sopenharmony_ci if (drv->auth_alg_fallback && 2147e5b75505Sopenharmony_ci wpa_driver_wext_auth_alg_fallback(drv, params) < 0) 2148e5b75505Sopenharmony_ci ret = -1; 2149e5b75505Sopenharmony_ci 2150e5b75505Sopenharmony_ci if (!params->bssid && 2151e5b75505Sopenharmony_ci wpa_driver_wext_set_bssid(drv, NULL) < 0) 2152e5b75505Sopenharmony_ci ret = -1; 2153e5b75505Sopenharmony_ci 2154e5b75505Sopenharmony_ci /* TODO: should consider getting wpa version and cipher/key_mgmt suites 2155e5b75505Sopenharmony_ci * from configuration, not from here, where only the selected suite is 2156e5b75505Sopenharmony_ci * available */ 2157e5b75505Sopenharmony_ci if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) 2158e5b75505Sopenharmony_ci < 0) 2159e5b75505Sopenharmony_ci ret = -1; 2160e5b75505Sopenharmony_ci if (params->wpa_proto & WPA_PROTO_RSN) 2161e5b75505Sopenharmony_ci value = IW_AUTH_WPA_VERSION_WPA2; 2162e5b75505Sopenharmony_ci else if (params->wpa_proto & WPA_PROTO_WPA) 2163e5b75505Sopenharmony_ci value = IW_AUTH_WPA_VERSION_WPA; 2164e5b75505Sopenharmony_ci else 2165e5b75505Sopenharmony_ci value = IW_AUTH_WPA_VERSION_DISABLED; 2166e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, 2167e5b75505Sopenharmony_ci IW_AUTH_WPA_VERSION, value) < 0) 2168e5b75505Sopenharmony_ci ret = -1; 2169e5b75505Sopenharmony_ci value = wpa_driver_wext_cipher2wext(params->pairwise_suite); 2170e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, 2171e5b75505Sopenharmony_ci IW_AUTH_CIPHER_PAIRWISE, value) < 0) 2172e5b75505Sopenharmony_ci ret = -1; 2173e5b75505Sopenharmony_ci value = wpa_driver_wext_cipher2wext(params->group_suite); 2174e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, 2175e5b75505Sopenharmony_ci IW_AUTH_CIPHER_GROUP, value) < 0) 2176e5b75505Sopenharmony_ci ret = -1; 2177e5b75505Sopenharmony_ci value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite); 2178e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, 2179e5b75505Sopenharmony_ci IW_AUTH_KEY_MGMT, value) < 0) 2180e5b75505Sopenharmony_ci ret = -1; 2181e5b75505Sopenharmony_ci value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE || 2182e5b75505Sopenharmony_ci params->pairwise_suite != WPA_CIPHER_NONE || 2183e5b75505Sopenharmony_ci params->group_suite != WPA_CIPHER_NONE || 2184e5b75505Sopenharmony_ci (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)); 2185e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, 2186e5b75505Sopenharmony_ci IW_AUTH_PRIVACY_INVOKED, value) < 0) 2187e5b75505Sopenharmony_ci ret = -1; 2188e5b75505Sopenharmony_ci 2189e5b75505Sopenharmony_ci /* Allow unencrypted EAPOL messages even if pairwise keys are set when 2190e5b75505Sopenharmony_ci * not using WPA. IEEE 802.1X specifies that these frames are not 2191e5b75505Sopenharmony_ci * encrypted, but WPA encrypts them when pairwise keys are in use. */ 2192e5b75505Sopenharmony_ci if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || 2193e5b75505Sopenharmony_ci params->key_mgmt_suite == WPA_KEY_MGMT_PSK) 2194e5b75505Sopenharmony_ci allow_unencrypted_eapol = 0; 2195e5b75505Sopenharmony_ci else 2196e5b75505Sopenharmony_ci allow_unencrypted_eapol = 1; 2197e5b75505Sopenharmony_ci 2198e5b75505Sopenharmony_ci if (wpa_driver_wext_set_psk(drv, params->psk) < 0) 2199e5b75505Sopenharmony_ci ret = -1; 2200e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, 2201e5b75505Sopenharmony_ci IW_AUTH_RX_UNENCRYPTED_EAPOL, 2202e5b75505Sopenharmony_ci allow_unencrypted_eapol) < 0) 2203e5b75505Sopenharmony_ci ret = -1; 2204e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 2205e5b75505Sopenharmony_ci switch (params->mgmt_frame_protection) { 2206e5b75505Sopenharmony_ci case NO_MGMT_FRAME_PROTECTION: 2207e5b75505Sopenharmony_ci value = IW_AUTH_MFP_DISABLED; 2208e5b75505Sopenharmony_ci break; 2209e5b75505Sopenharmony_ci case MGMT_FRAME_PROTECTION_OPTIONAL: 2210e5b75505Sopenharmony_ci value = IW_AUTH_MFP_OPTIONAL; 2211e5b75505Sopenharmony_ci break; 2212e5b75505Sopenharmony_ci case MGMT_FRAME_PROTECTION_REQUIRED: 2213e5b75505Sopenharmony_ci value = IW_AUTH_MFP_REQUIRED; 2214e5b75505Sopenharmony_ci break; 2215e5b75505Sopenharmony_ci }; 2216e5b75505Sopenharmony_ci if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0) 2217e5b75505Sopenharmony_ci ret = -1; 2218e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 2219e5b75505Sopenharmony_ci if (params->freq.freq && 2220e5b75505Sopenharmony_ci wpa_driver_wext_set_freq(drv, params->freq.freq) < 0) 2221e5b75505Sopenharmony_ci ret = -1; 2222e5b75505Sopenharmony_ci if (!drv->cfg80211 && 2223e5b75505Sopenharmony_ci wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) 2224e5b75505Sopenharmony_ci ret = -1; 2225e5b75505Sopenharmony_ci if (params->bssid && 2226e5b75505Sopenharmony_ci wpa_driver_wext_set_bssid(drv, params->bssid) < 0) 2227e5b75505Sopenharmony_ci ret = -1; 2228e5b75505Sopenharmony_ci if (drv->cfg80211 && 2229e5b75505Sopenharmony_ci wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) 2230e5b75505Sopenharmony_ci ret = -1; 2231e5b75505Sopenharmony_ci 2232e5b75505Sopenharmony_ci return ret; 2233e5b75505Sopenharmony_ci} 2234e5b75505Sopenharmony_ci 2235e5b75505Sopenharmony_ci 2236e5b75505Sopenharmony_cistatic int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg) 2237e5b75505Sopenharmony_ci{ 2238e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2239e5b75505Sopenharmony_ci int algs = 0, res; 2240e5b75505Sopenharmony_ci 2241e5b75505Sopenharmony_ci if (auth_alg & WPA_AUTH_ALG_OPEN) 2242e5b75505Sopenharmony_ci algs |= IW_AUTH_ALG_OPEN_SYSTEM; 2243e5b75505Sopenharmony_ci if (auth_alg & WPA_AUTH_ALG_SHARED) 2244e5b75505Sopenharmony_ci algs |= IW_AUTH_ALG_SHARED_KEY; 2245e5b75505Sopenharmony_ci if (auth_alg & WPA_AUTH_ALG_LEAP) 2246e5b75505Sopenharmony_ci algs |= IW_AUTH_ALG_LEAP; 2247e5b75505Sopenharmony_ci if (algs == 0) { 2248e5b75505Sopenharmony_ci /* at least one algorithm should be set */ 2249e5b75505Sopenharmony_ci algs = IW_AUTH_ALG_OPEN_SYSTEM; 2250e5b75505Sopenharmony_ci } 2251e5b75505Sopenharmony_ci 2252e5b75505Sopenharmony_ci res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, 2253e5b75505Sopenharmony_ci algs); 2254e5b75505Sopenharmony_ci drv->auth_alg_fallback = res == -2; 2255e5b75505Sopenharmony_ci return res; 2256e5b75505Sopenharmony_ci} 2257e5b75505Sopenharmony_ci 2258e5b75505Sopenharmony_ci 2259e5b75505Sopenharmony_ci/** 2260e5b75505Sopenharmony_ci * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE 2261e5b75505Sopenharmony_ci * @priv: Pointer to private wext data from wpa_driver_wext_init() 2262e5b75505Sopenharmony_ci * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS 2263e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 2264e5b75505Sopenharmony_ci */ 2265e5b75505Sopenharmony_ciint wpa_driver_wext_set_mode(void *priv, int mode) 2266e5b75505Sopenharmony_ci{ 2267e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2268e5b75505Sopenharmony_ci struct iwreq iwr; 2269e5b75505Sopenharmony_ci int ret = -1; 2270e5b75505Sopenharmony_ci unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA; 2271e5b75505Sopenharmony_ci 2272e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 2273e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 2274e5b75505Sopenharmony_ci iwr.u.mode = new_mode; 2275e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) { 2276e5b75505Sopenharmony_ci ret = 0; 2277e5b75505Sopenharmony_ci goto done; 2278e5b75505Sopenharmony_ci } 2279e5b75505Sopenharmony_ci 2280e5b75505Sopenharmony_ci if (errno != EBUSY) { 2281e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s", 2282e5b75505Sopenharmony_ci strerror(errno)); 2283e5b75505Sopenharmony_ci goto done; 2284e5b75505Sopenharmony_ci } 2285e5b75505Sopenharmony_ci 2286e5b75505Sopenharmony_ci /* mac80211 doesn't allow mode changes while the device is up, so if 2287e5b75505Sopenharmony_ci * the device isn't in the mode we're about to change to, take device 2288e5b75505Sopenharmony_ci * down, try to set the mode again, and bring it back up. 2289e5b75505Sopenharmony_ci */ 2290e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { 2291e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s", 2292e5b75505Sopenharmony_ci strerror(errno)); 2293e5b75505Sopenharmony_ci goto done; 2294e5b75505Sopenharmony_ci } 2295e5b75505Sopenharmony_ci 2296e5b75505Sopenharmony_ci if (iwr.u.mode == new_mode) { 2297e5b75505Sopenharmony_ci ret = 0; 2298e5b75505Sopenharmony_ci goto done; 2299e5b75505Sopenharmony_ci } 2300e5b75505Sopenharmony_ci 2301e5b75505Sopenharmony_ci if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) { 2302e5b75505Sopenharmony_ci /* Try to set the mode again while the interface is down */ 2303e5b75505Sopenharmony_ci iwr.u.mode = new_mode; 2304e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) 2305e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s", 2306e5b75505Sopenharmony_ci strerror(errno)); 2307e5b75505Sopenharmony_ci else 2308e5b75505Sopenharmony_ci ret = 0; 2309e5b75505Sopenharmony_ci 2310e5b75505Sopenharmony_ci (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); 2311e5b75505Sopenharmony_ci } 2312e5b75505Sopenharmony_ci 2313e5b75505Sopenharmony_cidone: 2314e5b75505Sopenharmony_ci return ret; 2315e5b75505Sopenharmony_ci} 2316e5b75505Sopenharmony_ci 2317e5b75505Sopenharmony_ci 2318e5b75505Sopenharmony_cistatic int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv, 2319e5b75505Sopenharmony_ci u32 cmd, const u8 *bssid, const u8 *pmkid) 2320e5b75505Sopenharmony_ci{ 2321e5b75505Sopenharmony_ci struct iwreq iwr; 2322e5b75505Sopenharmony_ci struct iw_pmksa pmksa; 2323e5b75505Sopenharmony_ci int ret = 0; 2324e5b75505Sopenharmony_ci 2325e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 2326e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 2327e5b75505Sopenharmony_ci os_memset(&pmksa, 0, sizeof(pmksa)); 2328e5b75505Sopenharmony_ci pmksa.cmd = cmd; 2329e5b75505Sopenharmony_ci pmksa.bssid.sa_family = ARPHRD_ETHER; 2330e5b75505Sopenharmony_ci if (bssid) 2331e5b75505Sopenharmony_ci os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); 2332e5b75505Sopenharmony_ci if (pmkid) 2333e5b75505Sopenharmony_ci os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); 2334e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) &pmksa; 2335e5b75505Sopenharmony_ci iwr.u.data.length = sizeof(pmksa); 2336e5b75505Sopenharmony_ci 2337e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { 2338e5b75505Sopenharmony_ci if (errno != EOPNOTSUPP) 2339e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s", 2340e5b75505Sopenharmony_ci strerror(errno)); 2341e5b75505Sopenharmony_ci ret = -1; 2342e5b75505Sopenharmony_ci } 2343e5b75505Sopenharmony_ci 2344e5b75505Sopenharmony_ci return ret; 2345e5b75505Sopenharmony_ci} 2346e5b75505Sopenharmony_ci 2347e5b75505Sopenharmony_ci 2348e5b75505Sopenharmony_cistatic int wpa_driver_wext_add_pmkid(void *priv, 2349e5b75505Sopenharmony_ci struct wpa_pmkid_params *params) 2350e5b75505Sopenharmony_ci{ 2351e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2352e5b75505Sopenharmony_ci return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, params->bssid, 2353e5b75505Sopenharmony_ci params->pmkid); 2354e5b75505Sopenharmony_ci} 2355e5b75505Sopenharmony_ci 2356e5b75505Sopenharmony_ci 2357e5b75505Sopenharmony_cistatic int wpa_driver_wext_remove_pmkid(void *priv, 2358e5b75505Sopenharmony_ci struct wpa_pmkid_params *params) 2359e5b75505Sopenharmony_ci{ 2360e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2361e5b75505Sopenharmony_ci return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, params->bssid, 2362e5b75505Sopenharmony_ci params->pmkid); 2363e5b75505Sopenharmony_ci} 2364e5b75505Sopenharmony_ci 2365e5b75505Sopenharmony_ci 2366e5b75505Sopenharmony_cistatic int wpa_driver_wext_flush_pmkid(void *priv) 2367e5b75505Sopenharmony_ci{ 2368e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2369e5b75505Sopenharmony_ci return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); 2370e5b75505Sopenharmony_ci} 2371e5b75505Sopenharmony_ci 2372e5b75505Sopenharmony_ci 2373e5b75505Sopenharmony_ciint wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa) 2374e5b75505Sopenharmony_ci{ 2375e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2376e5b75505Sopenharmony_ci if (!drv->has_capability) 2377e5b75505Sopenharmony_ci return -1; 2378e5b75505Sopenharmony_ci os_memcpy(capa, &drv->capa, sizeof(*capa)); 2379e5b75505Sopenharmony_ci return 0; 2380e5b75505Sopenharmony_ci} 2381e5b75505Sopenharmony_ci 2382e5b75505Sopenharmony_ci 2383e5b75505Sopenharmony_ciint wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, 2384e5b75505Sopenharmony_ci const char *ifname) 2385e5b75505Sopenharmony_ci{ 2386e5b75505Sopenharmony_ci if (ifname == NULL) { 2387e5b75505Sopenharmony_ci drv->ifindex2 = -1; 2388e5b75505Sopenharmony_ci return 0; 2389e5b75505Sopenharmony_ci } 2390e5b75505Sopenharmony_ci 2391e5b75505Sopenharmony_ci drv->ifindex2 = if_nametoindex(ifname); 2392e5b75505Sopenharmony_ci if (drv->ifindex2 <= 0) 2393e5b75505Sopenharmony_ci return -1; 2394e5b75505Sopenharmony_ci 2395e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for " 2396e5b75505Sopenharmony_ci "wireless events", drv->ifindex2, ifname); 2397e5b75505Sopenharmony_ci 2398e5b75505Sopenharmony_ci return 0; 2399e5b75505Sopenharmony_ci} 2400e5b75505Sopenharmony_ci 2401e5b75505Sopenharmony_ci 2402e5b75505Sopenharmony_ciint wpa_driver_wext_set_operstate(void *priv, int state) 2403e5b75505Sopenharmony_ci{ 2404e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2405e5b75505Sopenharmony_ci 2406e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", 2407e5b75505Sopenharmony_ci __func__, drv->operstate, state, state ? "UP" : "DORMANT"); 2408e5b75505Sopenharmony_ci drv->operstate = state; 2409e5b75505Sopenharmony_ci return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, 2410e5b75505Sopenharmony_ci state ? IF_OPER_UP : IF_OPER_DORMANT); 2411e5b75505Sopenharmony_ci} 2412e5b75505Sopenharmony_ci 2413e5b75505Sopenharmony_ci 2414e5b75505Sopenharmony_ciint wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv) 2415e5b75505Sopenharmony_ci{ 2416e5b75505Sopenharmony_ci return drv->we_version_compiled; 2417e5b75505Sopenharmony_ci} 2418e5b75505Sopenharmony_ci 2419e5b75505Sopenharmony_ci 2420e5b75505Sopenharmony_cistatic const char * wext_get_radio_name(void *priv) 2421e5b75505Sopenharmony_ci{ 2422e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2423e5b75505Sopenharmony_ci return drv->phyname; 2424e5b75505Sopenharmony_ci} 2425e5b75505Sopenharmony_ci 2426e5b75505Sopenharmony_ci 2427e5b75505Sopenharmony_cistatic int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) 2428e5b75505Sopenharmony_ci{ 2429e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2430e5b75505Sopenharmony_ci struct iw_statistics stats; 2431e5b75505Sopenharmony_ci struct iwreq iwr; 2432e5b75505Sopenharmony_ci 2433e5b75505Sopenharmony_ci os_memset(si, 0, sizeof(*si)); 2434e5b75505Sopenharmony_ci si->current_signal = -WPA_INVALID_NOISE; 2435e5b75505Sopenharmony_ci si->current_noise = WPA_INVALID_NOISE; 2436e5b75505Sopenharmony_ci si->chanwidth = CHAN_WIDTH_UNKNOWN; 2437e5b75505Sopenharmony_ci 2438e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 2439e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 2440e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) &stats; 2441e5b75505Sopenharmony_ci iwr.u.data.length = sizeof(stats); 2442e5b75505Sopenharmony_ci iwr.u.data.flags = 1; 2443e5b75505Sopenharmony_ci 2444e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { 2445e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s", 2446e5b75505Sopenharmony_ci strerror(errno)); 2447e5b75505Sopenharmony_ci return -1; 2448e5b75505Sopenharmony_ci } 2449e5b75505Sopenharmony_ci 2450e5b75505Sopenharmony_ci si->current_signal = stats.qual.level - 2451e5b75505Sopenharmony_ci ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); 2452e5b75505Sopenharmony_ci si->current_noise = stats.qual.noise - 2453e5b75505Sopenharmony_ci ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); 2454e5b75505Sopenharmony_ci return 0; 2455e5b75505Sopenharmony_ci} 2456e5b75505Sopenharmony_ci 2457e5b75505Sopenharmony_ci 2458e5b75505Sopenharmony_cistatic int wpa_driver_wext_status(void *priv, char *buf, size_t buflen) 2459e5b75505Sopenharmony_ci{ 2460e5b75505Sopenharmony_ci struct wpa_driver_wext_data *drv = priv; 2461e5b75505Sopenharmony_ci int res; 2462e5b75505Sopenharmony_ci char *pos, *end; 2463e5b75505Sopenharmony_ci unsigned char addr[ETH_ALEN]; 2464e5b75505Sopenharmony_ci 2465e5b75505Sopenharmony_ci pos = buf; 2466e5b75505Sopenharmony_ci end = buf + buflen; 2467e5b75505Sopenharmony_ci 2468e5b75505Sopenharmony_ci if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr)) 2469e5b75505Sopenharmony_ci return -1; 2470e5b75505Sopenharmony_ci 2471e5b75505Sopenharmony_ci res = os_snprintf(pos, end - pos, 2472e5b75505Sopenharmony_ci "ifindex=%d\n" 2473e5b75505Sopenharmony_ci "ifname=%s\n" 2474e5b75505Sopenharmony_ci "addr=" MACSTR "\n", 2475e5b75505Sopenharmony_ci drv->ifindex, 2476e5b75505Sopenharmony_ci drv->ifname, 2477e5b75505Sopenharmony_ci MAC2STR(addr)); 2478e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, res)) 2479e5b75505Sopenharmony_ci return pos - buf; 2480e5b75505Sopenharmony_ci pos += res; 2481e5b75505Sopenharmony_ci 2482e5b75505Sopenharmony_ci return pos - buf; 2483e5b75505Sopenharmony_ci} 2484e5b75505Sopenharmony_ci 2485e5b75505Sopenharmony_ciconst struct wpa_driver_ops wpa_driver_wext_ops = { 2486e5b75505Sopenharmony_ci .name = "wext", 2487e5b75505Sopenharmony_ci .desc = "Linux wireless extensions (generic)", 2488e5b75505Sopenharmony_ci .get_bssid = wpa_driver_wext_get_bssid, 2489e5b75505Sopenharmony_ci .get_ssid = wpa_driver_wext_get_ssid, 2490e5b75505Sopenharmony_ci .set_key = wpa_driver_wext_set_key, 2491e5b75505Sopenharmony_ci .set_countermeasures = wpa_driver_wext_set_countermeasures, 2492e5b75505Sopenharmony_ci .scan2 = wpa_driver_wext_scan, 2493e5b75505Sopenharmony_ci .get_scan_results2 = wpa_driver_wext_get_scan_results, 2494e5b75505Sopenharmony_ci .deauthenticate = wpa_driver_wext_deauthenticate, 2495e5b75505Sopenharmony_ci .associate = wpa_driver_wext_associate, 2496e5b75505Sopenharmony_ci .init = wpa_driver_wext_init, 2497e5b75505Sopenharmony_ci .deinit = wpa_driver_wext_deinit, 2498e5b75505Sopenharmony_ci .add_pmkid = wpa_driver_wext_add_pmkid, 2499e5b75505Sopenharmony_ci .remove_pmkid = wpa_driver_wext_remove_pmkid, 2500e5b75505Sopenharmony_ci .flush_pmkid = wpa_driver_wext_flush_pmkid, 2501e5b75505Sopenharmony_ci .get_capa = wpa_driver_wext_get_capa, 2502e5b75505Sopenharmony_ci .set_operstate = wpa_driver_wext_set_operstate, 2503e5b75505Sopenharmony_ci .get_radio_name = wext_get_radio_name, 2504e5b75505Sopenharmony_ci .signal_poll = wpa_driver_wext_signal_poll, 2505e5b75505Sopenharmony_ci .status = wpa_driver_wext_status, 2506e5b75505Sopenharmony_ci}; 2507