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