1206b73d0SCy Schubert /* 2206b73d0SCy Schubert * hostapd / Driver interaction with Atheros driver 3206b73d0SCy Schubert * Copyright (c) 2004, Sam Leffler <sam@errno.com> 4206b73d0SCy Schubert * Copyright (c) 2004, Video54 Technologies 5206b73d0SCy Schubert * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> 6206b73d0SCy Schubert * Copyright (c) 2009, Atheros Communications 7206b73d0SCy Schubert * 8206b73d0SCy Schubert * This software may be distributed under the terms of the BSD license. 9206b73d0SCy Schubert * See README for more details. 10206b73d0SCy Schubert */ 11206b73d0SCy Schubert 12206b73d0SCy Schubert #include "includes.h" 13206b73d0SCy Schubert #include <net/if.h> 14206b73d0SCy Schubert #include <sys/ioctl.h> 15206b73d0SCy Schubert 16206b73d0SCy Schubert #include "common.h" 17206b73d0SCy Schubert #include "eloop.h" 18206b73d0SCy Schubert #include "common/ieee802_11_defs.h" 19206b73d0SCy Schubert #include "l2_packet/l2_packet.h" 20206b73d0SCy Schubert #include "p2p/p2p.h" 21206b73d0SCy Schubert 22206b73d0SCy Schubert #include "common.h" 23206b73d0SCy Schubert #ifndef _BYTE_ORDER 24206b73d0SCy Schubert #ifdef WORDS_BIGENDIAN 25206b73d0SCy Schubert #define _BYTE_ORDER _BIG_ENDIAN 26206b73d0SCy Schubert #else 27206b73d0SCy Schubert #define _BYTE_ORDER _LITTLE_ENDIAN 28206b73d0SCy Schubert #endif 29206b73d0SCy Schubert #endif /* _BYTE_ORDER */ 30206b73d0SCy Schubert 31206b73d0SCy Schubert /* 32206b73d0SCy Schubert * Note, the ATH_WPS_IE setting must match with the driver build.. If the 33206b73d0SCy Schubert * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail. 34206b73d0SCy Schubert */ 35206b73d0SCy Schubert #define ATH_WPS_IE 36206b73d0SCy Schubert 37206b73d0SCy Schubert #include "ieee80211_external.h" 38206b73d0SCy Schubert 39206b73d0SCy Schubert /* Avoid conflicting definition from the driver header files with 40206b73d0SCy Schubert * common/wpa_common.h */ 41206b73d0SCy Schubert #undef WPA_OUI_TYPE 42206b73d0SCy Schubert 43206b73d0SCy Schubert 44206b73d0SCy Schubert #ifdef CONFIG_WPS 45206b73d0SCy Schubert #include <netpacket/packet.h> 46206b73d0SCy Schubert #endif /* CONFIG_WPS */ 47206b73d0SCy Schubert 48206b73d0SCy Schubert #ifndef ETH_P_80211_RAW 49206b73d0SCy Schubert #define ETH_P_80211_RAW 0x0019 50206b73d0SCy Schubert #endif 51206b73d0SCy Schubert 52206b73d0SCy Schubert #include "linux_wext.h" 53206b73d0SCy Schubert 54206b73d0SCy Schubert #include "driver.h" 55206b73d0SCy Schubert #include "eloop.h" 56206b73d0SCy Schubert #include "priv_netlink.h" 57206b73d0SCy Schubert #include "l2_packet/l2_packet.h" 58206b73d0SCy Schubert #include "common/ieee802_11_defs.h" 59206b73d0SCy Schubert #include "netlink.h" 60206b73d0SCy Schubert #include "linux_ioctl.h" 61206b73d0SCy Schubert 62206b73d0SCy Schubert 63206b73d0SCy Schubert struct atheros_driver_data { 64206b73d0SCy Schubert struct hostapd_data *hapd; /* back pointer */ 65206b73d0SCy Schubert 66206b73d0SCy Schubert char iface[IFNAMSIZ + 1]; 67206b73d0SCy Schubert int ifindex; 68206b73d0SCy Schubert struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ 69206b73d0SCy Schubert struct l2_packet_data *sock_recv; /* raw packet recv socket */ 70206b73d0SCy Schubert int ioctl_sock; /* socket for ioctl() use */ 71206b73d0SCy Schubert struct netlink_data *netlink; 72206b73d0SCy Schubert int we_version; 73206b73d0SCy Schubert int fils_en; /* FILS enable/disable in driver */ 74206b73d0SCy Schubert u8 acct_mac[ETH_ALEN]; 75206b73d0SCy Schubert struct hostap_sta_driver_data acct_data; 76206b73d0SCy Schubert 77206b73d0SCy Schubert struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ 78206b73d0SCy Schubert struct wpabuf *wpa_ie; 79206b73d0SCy Schubert struct wpabuf *wps_beacon_ie; 80206b73d0SCy Schubert struct wpabuf *wps_probe_resp_ie; 81206b73d0SCy Schubert u8 own_addr[ETH_ALEN]; 82206b73d0SCy Schubert }; 83206b73d0SCy Schubert 84206b73d0SCy Schubert static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 85206b73d0SCy Schubert u16 reason_code); 86206b73d0SCy Schubert static int atheros_set_privacy(void *priv, int enabled); 87206b73d0SCy Schubert 88206b73d0SCy Schubert static const char * athr_get_ioctl_name(int op) 89206b73d0SCy Schubert { 90206b73d0SCy Schubert switch (op) { 91206b73d0SCy Schubert case IEEE80211_IOCTL_SETPARAM: 92206b73d0SCy Schubert return "SETPARAM"; 93206b73d0SCy Schubert case IEEE80211_IOCTL_GETPARAM: 94206b73d0SCy Schubert return "GETPARAM"; 95206b73d0SCy Schubert case IEEE80211_IOCTL_SETKEY: 96206b73d0SCy Schubert return "SETKEY"; 97206b73d0SCy Schubert case IEEE80211_IOCTL_SETWMMPARAMS: 98206b73d0SCy Schubert return "SETWMMPARAMS"; 99206b73d0SCy Schubert case IEEE80211_IOCTL_DELKEY: 100206b73d0SCy Schubert return "DELKEY"; 101206b73d0SCy Schubert case IEEE80211_IOCTL_GETWMMPARAMS: 102206b73d0SCy Schubert return "GETWMMPARAMS"; 103206b73d0SCy Schubert case IEEE80211_IOCTL_SETMLME: 104206b73d0SCy Schubert return "SETMLME"; 105206b73d0SCy Schubert case IEEE80211_IOCTL_GETCHANINFO: 106206b73d0SCy Schubert return "GETCHANINFO"; 107206b73d0SCy Schubert case IEEE80211_IOCTL_SETOPTIE: 108206b73d0SCy Schubert return "SETOPTIE"; 109206b73d0SCy Schubert case IEEE80211_IOCTL_GETOPTIE: 110206b73d0SCy Schubert return "GETOPTIE"; 111206b73d0SCy Schubert case IEEE80211_IOCTL_ADDMAC: 112206b73d0SCy Schubert return "ADDMAC"; 113206b73d0SCy Schubert case IEEE80211_IOCTL_DELMAC: 114206b73d0SCy Schubert return "DELMAC"; 115206b73d0SCy Schubert case IEEE80211_IOCTL_GETCHANLIST: 116206b73d0SCy Schubert return "GETCHANLIST"; 117206b73d0SCy Schubert case IEEE80211_IOCTL_SETCHANLIST: 118206b73d0SCy Schubert return "SETCHANLIST"; 119206b73d0SCy Schubert case IEEE80211_IOCTL_KICKMAC: 120206b73d0SCy Schubert return "KICKMAC"; 121206b73d0SCy Schubert case IEEE80211_IOCTL_CHANSWITCH: 122206b73d0SCy Schubert return "CHANSWITCH"; 123206b73d0SCy Schubert case IEEE80211_IOCTL_GETMODE: 124206b73d0SCy Schubert return "GETMODE"; 125206b73d0SCy Schubert case IEEE80211_IOCTL_SETMODE: 126206b73d0SCy Schubert return "SETMODE"; 127206b73d0SCy Schubert case IEEE80211_IOCTL_GET_APPIEBUF: 128206b73d0SCy Schubert return "GET_APPIEBUF"; 129206b73d0SCy Schubert case IEEE80211_IOCTL_SET_APPIEBUF: 130206b73d0SCy Schubert return "SET_APPIEBUF"; 131206b73d0SCy Schubert case IEEE80211_IOCTL_SET_ACPARAMS: 132206b73d0SCy Schubert return "SET_ACPARAMS"; 133206b73d0SCy Schubert case IEEE80211_IOCTL_FILTERFRAME: 134206b73d0SCy Schubert return "FILTERFRAME"; 135206b73d0SCy Schubert case IEEE80211_IOCTL_SET_RTPARAMS: 136206b73d0SCy Schubert return "SET_RTPARAMS"; 137206b73d0SCy Schubert case IEEE80211_IOCTL_SET_MEDENYENTRY: 138206b73d0SCy Schubert return "SET_MEDENYENTRY"; 139206b73d0SCy Schubert case IEEE80211_IOCTL_GET_MACADDR: 140206b73d0SCy Schubert return "GET_MACADDR"; 141206b73d0SCy Schubert case IEEE80211_IOCTL_SET_HBRPARAMS: 142206b73d0SCy Schubert return "SET_HBRPARAMS"; 143206b73d0SCy Schubert case IEEE80211_IOCTL_SET_RXTIMEOUT: 144206b73d0SCy Schubert return "SET_RXTIMEOUT"; 145206b73d0SCy Schubert case IEEE80211_IOCTL_STA_STATS: 146206b73d0SCy Schubert return "STA_STATS"; 147206b73d0SCy Schubert case IEEE80211_IOCTL_GETWPAIE: 148206b73d0SCy Schubert return "GETWPAIE"; 149206b73d0SCy Schubert default: 150206b73d0SCy Schubert return "??"; 151206b73d0SCy Schubert } 152206b73d0SCy Schubert } 153206b73d0SCy Schubert 154206b73d0SCy Schubert 155206b73d0SCy Schubert static const char * athr_get_param_name(int op) 156206b73d0SCy Schubert { 157206b73d0SCy Schubert switch (op) { 158206b73d0SCy Schubert case IEEE80211_IOC_MCASTCIPHER: 159206b73d0SCy Schubert return "MCASTCIPHER"; 160206b73d0SCy Schubert case IEEE80211_PARAM_MCASTKEYLEN: 161206b73d0SCy Schubert return "MCASTKEYLEN"; 162206b73d0SCy Schubert case IEEE80211_PARAM_UCASTCIPHERS: 163206b73d0SCy Schubert return "UCASTCIPHERS"; 164206b73d0SCy Schubert case IEEE80211_PARAM_KEYMGTALGS: 165206b73d0SCy Schubert return "KEYMGTALGS"; 166206b73d0SCy Schubert case IEEE80211_PARAM_RSNCAPS: 167206b73d0SCy Schubert return "RSNCAPS"; 168206b73d0SCy Schubert case IEEE80211_PARAM_WPA: 169206b73d0SCy Schubert return "WPA"; 170206b73d0SCy Schubert case IEEE80211_PARAM_AUTHMODE: 171206b73d0SCy Schubert return "AUTHMODE"; 172206b73d0SCy Schubert case IEEE80211_PARAM_PRIVACY: 173206b73d0SCy Schubert return "PRIVACY"; 174206b73d0SCy Schubert case IEEE80211_PARAM_COUNTERMEASURES: 175206b73d0SCy Schubert return "COUNTERMEASURES"; 176206b73d0SCy Schubert default: 177206b73d0SCy Schubert return "??"; 178206b73d0SCy Schubert } 179206b73d0SCy Schubert } 180206b73d0SCy Schubert 181206b73d0SCy Schubert 182206b73d0SCy Schubert #ifdef CONFIG_FILS 183206b73d0SCy Schubert static int 184206b73d0SCy Schubert get80211param(struct atheros_driver_data *drv, int op, int *data) 185206b73d0SCy Schubert { 186206b73d0SCy Schubert struct iwreq iwr; 187206b73d0SCy Schubert 188206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 189206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 190206b73d0SCy Schubert iwr.u.mode = op; 191206b73d0SCy Schubert 192206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_GETPARAM, &iwr) < 0) 193206b73d0SCy Schubert return -1; 194206b73d0SCy Schubert 195206b73d0SCy Schubert *data = iwr.u.mode; 196206b73d0SCy Schubert return 0; 197206b73d0SCy Schubert } 198206b73d0SCy Schubert #endif /* CONFIG_FILS */ 199206b73d0SCy Schubert 200206b73d0SCy Schubert 201206b73d0SCy Schubert static int 202206b73d0SCy Schubert set80211priv(struct atheros_driver_data *drv, int op, void *data, int len) 203206b73d0SCy Schubert { 204206b73d0SCy Schubert struct iwreq iwr; 205206b73d0SCy Schubert int do_inline = len < IFNAMSIZ; 206206b73d0SCy Schubert 207206b73d0SCy Schubert /* Certain ioctls must use the non-inlined method */ 208206b73d0SCy Schubert if (op == IEEE80211_IOCTL_SET_APPIEBUF || 209206b73d0SCy Schubert op == IEEE80211_IOCTL_FILTERFRAME) 210206b73d0SCy Schubert do_inline = 0; 211206b73d0SCy Schubert 212206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 213206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 214206b73d0SCy Schubert if (do_inline) { 215206b73d0SCy Schubert /* 216206b73d0SCy Schubert * Argument data fits inline; put it there. 217206b73d0SCy Schubert */ 218206b73d0SCy Schubert os_memcpy(iwr.u.name, data, len); 219206b73d0SCy Schubert } else { 220206b73d0SCy Schubert /* 221206b73d0SCy Schubert * Argument data too big for inline transfer; setup a 222206b73d0SCy Schubert * parameter block instead; the kernel will transfer 223206b73d0SCy Schubert * the data for the driver. 224206b73d0SCy Schubert */ 225206b73d0SCy Schubert iwr.u.data.pointer = data; 226206b73d0SCy Schubert iwr.u.data.length = len; 227206b73d0SCy Schubert } 228206b73d0SCy Schubert 229206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { 230206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x " 231206b73d0SCy Schubert "(%s) len=%d failed: %d (%s)", 232206b73d0SCy Schubert __func__, drv->iface, op, 233206b73d0SCy Schubert athr_get_ioctl_name(op), 234206b73d0SCy Schubert len, errno, strerror(errno)); 235206b73d0SCy Schubert return -1; 236206b73d0SCy Schubert } 237206b73d0SCy Schubert return 0; 238206b73d0SCy Schubert } 239206b73d0SCy Schubert 240206b73d0SCy Schubert static int 241206b73d0SCy Schubert set80211param(struct atheros_driver_data *drv, int op, int arg) 242206b73d0SCy Schubert { 243206b73d0SCy Schubert struct iwreq iwr; 244206b73d0SCy Schubert 245206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 246206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 247206b73d0SCy Schubert iwr.u.mode = op; 248206b73d0SCy Schubert os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg)); 249206b73d0SCy Schubert 250206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { 251206b73d0SCy Schubert wpa_printf(MSG_INFO, 252206b73d0SCy Schubert "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s", 253206b73d0SCy Schubert __func__, drv->iface, op, athr_get_param_name(op), 254206b73d0SCy Schubert arg, strerror(errno)); 255206b73d0SCy Schubert return -1; 256206b73d0SCy Schubert } 257206b73d0SCy Schubert return 0; 258206b73d0SCy Schubert } 259206b73d0SCy Schubert 260206b73d0SCy Schubert #ifndef CONFIG_NO_STDOUT_DEBUG 261206b73d0SCy Schubert static const char * 262206b73d0SCy Schubert ether_sprintf(const u8 *addr) 263206b73d0SCy Schubert { 264206b73d0SCy Schubert static char buf[sizeof(MACSTR)]; 265206b73d0SCy Schubert 266206b73d0SCy Schubert if (addr != NULL) 267206b73d0SCy Schubert os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 268206b73d0SCy Schubert else 269206b73d0SCy Schubert os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0); 270206b73d0SCy Schubert return buf; 271206b73d0SCy Schubert } 272206b73d0SCy Schubert #endif /* CONFIG_NO_STDOUT_DEBUG */ 273206b73d0SCy Schubert 274206b73d0SCy Schubert /* 275206b73d0SCy Schubert * Configure WPA parameters. 276206b73d0SCy Schubert */ 277206b73d0SCy Schubert static int 278206b73d0SCy Schubert atheros_configure_wpa(struct atheros_driver_data *drv, 279206b73d0SCy Schubert struct wpa_bss_params *params) 280206b73d0SCy Schubert { 281206b73d0SCy Schubert int v; 282206b73d0SCy Schubert 283206b73d0SCy Schubert switch (params->wpa_group) { 284206b73d0SCy Schubert case WPA_CIPHER_CCMP: 285206b73d0SCy Schubert v = IEEE80211_CIPHER_AES_CCM; 286206b73d0SCy Schubert break; 287206b73d0SCy Schubert #ifdef ATH_GCM_SUPPORT 288206b73d0SCy Schubert case WPA_CIPHER_CCMP_256: 289206b73d0SCy Schubert v = IEEE80211_CIPHER_AES_CCM_256; 290206b73d0SCy Schubert break; 291206b73d0SCy Schubert case WPA_CIPHER_GCMP: 292206b73d0SCy Schubert v = IEEE80211_CIPHER_AES_GCM; 293206b73d0SCy Schubert break; 294206b73d0SCy Schubert case WPA_CIPHER_GCMP_256: 295206b73d0SCy Schubert v = IEEE80211_CIPHER_AES_GCM_256; 296206b73d0SCy Schubert break; 297206b73d0SCy Schubert #endif /* ATH_GCM_SUPPORT */ 298206b73d0SCy Schubert case WPA_CIPHER_TKIP: 299206b73d0SCy Schubert v = IEEE80211_CIPHER_TKIP; 300206b73d0SCy Schubert break; 301206b73d0SCy Schubert case WPA_CIPHER_WEP104: 302206b73d0SCy Schubert v = IEEE80211_CIPHER_WEP; 303206b73d0SCy Schubert break; 304206b73d0SCy Schubert case WPA_CIPHER_WEP40: 305206b73d0SCy Schubert v = IEEE80211_CIPHER_WEP; 306206b73d0SCy Schubert break; 307206b73d0SCy Schubert case WPA_CIPHER_NONE: 308206b73d0SCy Schubert v = IEEE80211_CIPHER_NONE; 309206b73d0SCy Schubert break; 310206b73d0SCy Schubert default: 311206b73d0SCy Schubert wpa_printf(MSG_ERROR, "Unknown group key cipher %u", 312206b73d0SCy Schubert params->wpa_group); 313206b73d0SCy Schubert return -1; 314206b73d0SCy Schubert } 315206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); 316206b73d0SCy Schubert if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { 317206b73d0SCy Schubert wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v); 318206b73d0SCy Schubert return -1; 319206b73d0SCy Schubert } 320206b73d0SCy Schubert if (v == IEEE80211_CIPHER_WEP) { 321206b73d0SCy Schubert /* key length is done only for specific ciphers */ 322206b73d0SCy Schubert v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); 323206b73d0SCy Schubert if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { 324206b73d0SCy Schubert wpa_printf(MSG_INFO, 325206b73d0SCy Schubert "Unable to set group key length to %u", v); 326206b73d0SCy Schubert return -1; 327206b73d0SCy Schubert } 328206b73d0SCy Schubert } 329206b73d0SCy Schubert 330206b73d0SCy Schubert v = 0; 331206b73d0SCy Schubert if (params->wpa_pairwise & WPA_CIPHER_CCMP) 332206b73d0SCy Schubert v |= 1<<IEEE80211_CIPHER_AES_CCM; 333206b73d0SCy Schubert #ifdef ATH_GCM_SUPPORT 334206b73d0SCy Schubert if (params->wpa_pairwise & WPA_CIPHER_CCMP_256) 335206b73d0SCy Schubert v |= 1<<IEEE80211_CIPHER_AES_CCM_256; 336206b73d0SCy Schubert if (params->wpa_pairwise & WPA_CIPHER_GCMP) 337206b73d0SCy Schubert v |= 1<<IEEE80211_CIPHER_AES_GCM; 338206b73d0SCy Schubert if (params->wpa_pairwise & WPA_CIPHER_GCMP_256) 339206b73d0SCy Schubert v |= 1<<IEEE80211_CIPHER_AES_GCM_256; 340206b73d0SCy Schubert #endif /* ATH_GCM_SUPPORT */ 341206b73d0SCy Schubert if (params->wpa_pairwise & WPA_CIPHER_TKIP) 342206b73d0SCy Schubert v |= 1<<IEEE80211_CIPHER_TKIP; 343206b73d0SCy Schubert if (params->wpa_pairwise & WPA_CIPHER_NONE) 344206b73d0SCy Schubert v |= 1<<IEEE80211_CIPHER_NONE; 345206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v); 346206b73d0SCy Schubert if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) { 347206b73d0SCy Schubert wpa_printf(MSG_INFO, 348206b73d0SCy Schubert "Unable to set pairwise key ciphers to 0x%x", v); 349206b73d0SCy Schubert return -1; 350206b73d0SCy Schubert } 351206b73d0SCy Schubert 352206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x", 353206b73d0SCy Schubert __func__, params->wpa_key_mgmt); 354206b73d0SCy Schubert if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, 355206b73d0SCy Schubert params->wpa_key_mgmt)) { 356206b73d0SCy Schubert wpa_printf(MSG_INFO, 357206b73d0SCy Schubert "Unable to set key management algorithms to 0x%x", 358206b73d0SCy Schubert params->wpa_key_mgmt); 359206b73d0SCy Schubert return -1; 360206b73d0SCy Schubert } 361206b73d0SCy Schubert 362206b73d0SCy Schubert v = 0; 363206b73d0SCy Schubert if (params->rsn_preauth) 364206b73d0SCy Schubert v |= BIT(0); 365206b73d0SCy Schubert if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 366206b73d0SCy Schubert v |= BIT(7); 367206b73d0SCy Schubert if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) 368206b73d0SCy Schubert v |= BIT(6); 369206b73d0SCy Schubert } 370206b73d0SCy Schubert 371206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v); 372206b73d0SCy Schubert if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { 373206b73d0SCy Schubert wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", 374206b73d0SCy Schubert v); 375206b73d0SCy Schubert return -1; 376206b73d0SCy Schubert } 377206b73d0SCy Schubert 378206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); 379206b73d0SCy Schubert if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { 380206b73d0SCy Schubert wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); 381206b73d0SCy Schubert return -1; 382206b73d0SCy Schubert } 383206b73d0SCy Schubert return 0; 384206b73d0SCy Schubert } 385206b73d0SCy Schubert 386206b73d0SCy Schubert static int 387206b73d0SCy Schubert atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params) 388206b73d0SCy Schubert { 389206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 390206b73d0SCy Schubert 391206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); 392206b73d0SCy Schubert 393206b73d0SCy Schubert if (!params->enabled) { 394206b73d0SCy Schubert /* XXX restore state */ 395206b73d0SCy Schubert if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, 396206b73d0SCy Schubert IEEE80211_AUTH_AUTO) < 0) 397206b73d0SCy Schubert return -1; 398206b73d0SCy Schubert /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ 399206b73d0SCy Schubert return atheros_set_privacy(drv, 0); 400206b73d0SCy Schubert } 401206b73d0SCy Schubert if (!params->wpa && !params->ieee802_1x) { 402206b73d0SCy Schubert wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!"); 403206b73d0SCy Schubert return -1; 404206b73d0SCy Schubert } 405206b73d0SCy Schubert if (params->wpa && atheros_configure_wpa(drv, params) != 0) { 406206b73d0SCy Schubert wpa_printf(MSG_WARNING, "Error configuring WPA state!"); 407206b73d0SCy Schubert return -1; 408206b73d0SCy Schubert } 409206b73d0SCy Schubert if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, 410206b73d0SCy Schubert (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { 411206b73d0SCy Schubert wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!"); 412206b73d0SCy Schubert return -1; 413206b73d0SCy Schubert } 414206b73d0SCy Schubert 415206b73d0SCy Schubert return 0; 416206b73d0SCy Schubert } 417206b73d0SCy Schubert 418206b73d0SCy Schubert static int 419206b73d0SCy Schubert atheros_set_privacy(void *priv, int enabled) 420206b73d0SCy Schubert { 421206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 422206b73d0SCy Schubert 423206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 424206b73d0SCy Schubert 425206b73d0SCy Schubert return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); 426206b73d0SCy Schubert } 427206b73d0SCy Schubert 428206b73d0SCy Schubert static int 429206b73d0SCy Schubert atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) 430206b73d0SCy Schubert { 431206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 432206b73d0SCy Schubert struct ieee80211req_mlme mlme; 433206b73d0SCy Schubert int ret; 434206b73d0SCy Schubert 435206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", 436206b73d0SCy Schubert __func__, ether_sprintf(addr), authorized); 437206b73d0SCy Schubert 438206b73d0SCy Schubert if (authorized) 439206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_AUTHORIZE; 440206b73d0SCy Schubert else 441206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; 442206b73d0SCy Schubert mlme.im_reason = 0; 443206b73d0SCy Schubert os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 444206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 445206b73d0SCy Schubert if (ret < 0) { 446206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, 447206b73d0SCy Schubert __func__, authorized ? "" : "un", MAC2STR(addr)); 448206b73d0SCy Schubert } 449206b73d0SCy Schubert 450206b73d0SCy Schubert return ret; 451206b73d0SCy Schubert } 452206b73d0SCy Schubert 453206b73d0SCy Schubert static int 454206b73d0SCy Schubert atheros_sta_set_flags(void *priv, const u8 *addr, 455206b73d0SCy Schubert unsigned int total_flags, unsigned int flags_or, 456206b73d0SCy Schubert unsigned int flags_and) 457206b73d0SCy Schubert { 458206b73d0SCy Schubert /* For now, only support setting Authorized flag */ 459206b73d0SCy Schubert if (flags_or & WPA_STA_AUTHORIZED) 460206b73d0SCy Schubert return atheros_set_sta_authorized(priv, addr, 1); 461206b73d0SCy Schubert if (!(flags_and & WPA_STA_AUTHORIZED)) 462206b73d0SCy Schubert return atheros_set_sta_authorized(priv, addr, 0); 463206b73d0SCy Schubert return 0; 464206b73d0SCy Schubert } 465206b73d0SCy Schubert 466206b73d0SCy Schubert static int 467206b73d0SCy Schubert atheros_del_key(void *priv, const u8 *addr, int key_idx) 468206b73d0SCy Schubert { 469206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 470206b73d0SCy Schubert struct ieee80211req_del_key wk; 471206b73d0SCy Schubert int ret; 472206b73d0SCy Schubert 473206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", 474206b73d0SCy Schubert __func__, ether_sprintf(addr), key_idx); 475206b73d0SCy Schubert 476206b73d0SCy Schubert os_memset(&wk, 0, sizeof(wk)); 477206b73d0SCy Schubert if (addr != NULL) { 478206b73d0SCy Schubert os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); 479206b73d0SCy Schubert wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; 480206b73d0SCy Schubert } else { 481206b73d0SCy Schubert wk.idk_keyix = key_idx; 482206b73d0SCy Schubert } 483206b73d0SCy Schubert 484206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); 485206b73d0SCy Schubert if (ret < 0) { 486206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" 487206b73d0SCy Schubert " key_idx %d)", __func__, ether_sprintf(addr), 488206b73d0SCy Schubert key_idx); 489206b73d0SCy Schubert } 490206b73d0SCy Schubert 491206b73d0SCy Schubert return ret; 492206b73d0SCy Schubert } 493206b73d0SCy Schubert 494206b73d0SCy Schubert static int 495*c1d255d3SCy Schubert atheros_set_key(void *priv, struct wpa_driver_set_key_params *params) 496206b73d0SCy Schubert { 497206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 498206b73d0SCy Schubert struct ieee80211req_key wk; 499206b73d0SCy Schubert u_int8_t cipher; 500206b73d0SCy Schubert int ret; 501*c1d255d3SCy Schubert enum wpa_alg alg = params->alg; 502*c1d255d3SCy Schubert const u8 *addr = params->addr; 503*c1d255d3SCy Schubert int key_idx = params->key_idx; 504*c1d255d3SCy Schubert int set_tx = params->set_tx; 505*c1d255d3SCy Schubert const u8 *key = params->key; 506*c1d255d3SCy Schubert size_t key_len = params->key_len; 507206b73d0SCy Schubert 508206b73d0SCy Schubert if (alg == WPA_ALG_NONE) 509206b73d0SCy Schubert return atheros_del_key(drv, addr, key_idx); 510206b73d0SCy Schubert 511206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", 512206b73d0SCy Schubert __func__, alg, ether_sprintf(addr), key_idx); 513206b73d0SCy Schubert 514206b73d0SCy Schubert switch (alg) { 515206b73d0SCy Schubert case WPA_ALG_WEP: 516206b73d0SCy Schubert cipher = IEEE80211_CIPHER_WEP; 517206b73d0SCy Schubert break; 518206b73d0SCy Schubert case WPA_ALG_TKIP: 519206b73d0SCy Schubert cipher = IEEE80211_CIPHER_TKIP; 520206b73d0SCy Schubert break; 521206b73d0SCy Schubert case WPA_ALG_CCMP: 522206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_CCM; 523206b73d0SCy Schubert break; 524206b73d0SCy Schubert #ifdef ATH_GCM_SUPPORT 525206b73d0SCy Schubert case WPA_ALG_CCMP_256: 526206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_CCM_256; 527206b73d0SCy Schubert break; 528206b73d0SCy Schubert case WPA_ALG_GCMP: 529206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_GCM; 530206b73d0SCy Schubert break; 531206b73d0SCy Schubert case WPA_ALG_GCMP_256: 532206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_GCM_256; 533206b73d0SCy Schubert break; 534206b73d0SCy Schubert #endif /* ATH_GCM_SUPPORT */ 535*c1d255d3SCy Schubert case WPA_ALG_BIP_CMAC_128: 536206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_CMAC; 537206b73d0SCy Schubert break; 538206b73d0SCy Schubert #ifdef ATH_GCM_SUPPORT 539206b73d0SCy Schubert case WPA_ALG_BIP_CMAC_256: 540206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_CMAC_256; 541206b73d0SCy Schubert break; 542206b73d0SCy Schubert case WPA_ALG_BIP_GMAC_128: 543206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_GMAC; 544206b73d0SCy Schubert break; 545206b73d0SCy Schubert case WPA_ALG_BIP_GMAC_256: 546206b73d0SCy Schubert cipher = IEEE80211_CIPHER_AES_GMAC_256; 547206b73d0SCy Schubert break; 548206b73d0SCy Schubert #endif /* ATH_GCM_SUPPORT */ 549206b73d0SCy Schubert default: 550206b73d0SCy Schubert wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d", 551206b73d0SCy Schubert __func__, alg); 552206b73d0SCy Schubert return -1; 553206b73d0SCy Schubert } 554206b73d0SCy Schubert 555206b73d0SCy Schubert if (key_len > sizeof(wk.ik_keydata)) { 556206b73d0SCy Schubert wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__, 557206b73d0SCy Schubert (unsigned long) key_len); 558206b73d0SCy Schubert return -3; 559206b73d0SCy Schubert } 560206b73d0SCy Schubert 561206b73d0SCy Schubert os_memset(&wk, 0, sizeof(wk)); 562206b73d0SCy Schubert wk.ik_type = cipher; 563206b73d0SCy Schubert wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; 564206b73d0SCy Schubert if (addr == NULL || is_broadcast_ether_addr(addr)) { 565206b73d0SCy Schubert os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 566206b73d0SCy Schubert wk.ik_keyix = key_idx; 567206b73d0SCy Schubert if (set_tx) 568206b73d0SCy Schubert wk.ik_flags |= IEEE80211_KEY_DEFAULT; 569206b73d0SCy Schubert } else { 570206b73d0SCy Schubert os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 571206b73d0SCy Schubert wk.ik_keyix = IEEE80211_KEYIX_NONE; 572206b73d0SCy Schubert } 573206b73d0SCy Schubert wk.ik_keylen = key_len; 574206b73d0SCy Schubert os_memcpy(wk.ik_keydata, key, key_len); 575206b73d0SCy Schubert 576206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); 577206b73d0SCy Schubert if (ret < 0) { 578206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" 579206b73d0SCy Schubert " key_idx %d alg %d key_len %lu set_tx %d)", 580206b73d0SCy Schubert __func__, ether_sprintf(wk.ik_macaddr), key_idx, 581206b73d0SCy Schubert alg, (unsigned long) key_len, set_tx); 582206b73d0SCy Schubert } 583206b73d0SCy Schubert 584206b73d0SCy Schubert return ret; 585206b73d0SCy Schubert } 586206b73d0SCy Schubert 587206b73d0SCy Schubert 588206b73d0SCy Schubert static int 589206b73d0SCy Schubert atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, 590206b73d0SCy Schubert u8 *seq) 591206b73d0SCy Schubert { 592206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 593206b73d0SCy Schubert struct ieee80211req_key wk; 594206b73d0SCy Schubert 595206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", 596206b73d0SCy Schubert __func__, ether_sprintf(addr), idx); 597206b73d0SCy Schubert 598206b73d0SCy Schubert os_memset(&wk, 0, sizeof(wk)); 599206b73d0SCy Schubert if (addr == NULL) 600206b73d0SCy Schubert os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 601206b73d0SCy Schubert else 602206b73d0SCy Schubert os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 603206b73d0SCy Schubert wk.ik_keyix = idx; 604206b73d0SCy Schubert 605206b73d0SCy Schubert if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { 606206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " 607206b73d0SCy Schubert "(addr " MACSTR " key_idx %d)", 608206b73d0SCy Schubert __func__, MAC2STR(wk.ik_macaddr), idx); 609206b73d0SCy Schubert return -1; 610206b73d0SCy Schubert } 611206b73d0SCy Schubert 612206b73d0SCy Schubert #ifdef WORDS_BIGENDIAN 613206b73d0SCy Schubert { 614206b73d0SCy Schubert /* 615206b73d0SCy Schubert * wk.ik_keytsc is in host byte order (big endian), need to 616206b73d0SCy Schubert * swap it to match with the byte order used in WPA. 617206b73d0SCy Schubert */ 618206b73d0SCy Schubert int i; 619206b73d0SCy Schubert #ifndef WPA_KEY_RSC_LEN 620206b73d0SCy Schubert #define WPA_KEY_RSC_LEN 8 621206b73d0SCy Schubert #endif 622206b73d0SCy Schubert u8 tmp[WPA_KEY_RSC_LEN]; 623206b73d0SCy Schubert os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 624206b73d0SCy Schubert for (i = 0; i < WPA_KEY_RSC_LEN; i++) { 625206b73d0SCy Schubert seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; 626206b73d0SCy Schubert } 627206b73d0SCy Schubert } 628206b73d0SCy Schubert #else /* WORDS_BIGENDIAN */ 629206b73d0SCy Schubert os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 630206b73d0SCy Schubert #endif /* WORDS_BIGENDIAN */ 631206b73d0SCy Schubert return 0; 632206b73d0SCy Schubert } 633206b73d0SCy Schubert 634206b73d0SCy Schubert 635206b73d0SCy Schubert static int 636206b73d0SCy Schubert atheros_flush(void *priv) 637206b73d0SCy Schubert { 638206b73d0SCy Schubert u8 allsta[IEEE80211_ADDR_LEN]; 639206b73d0SCy Schubert os_memset(allsta, 0xff, IEEE80211_ADDR_LEN); 640206b73d0SCy Schubert return atheros_sta_deauth(priv, NULL, allsta, 641206b73d0SCy Schubert IEEE80211_REASON_AUTH_LEAVE); 642206b73d0SCy Schubert } 643206b73d0SCy Schubert 644206b73d0SCy Schubert 645206b73d0SCy Schubert static int 646206b73d0SCy Schubert atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, 647206b73d0SCy Schubert const u8 *addr) 648206b73d0SCy Schubert { 649206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 650206b73d0SCy Schubert struct ieee80211req_sta_stats stats; 651206b73d0SCy Schubert 652206b73d0SCy Schubert os_memset(data, 0, sizeof(*data)); 653206b73d0SCy Schubert 654206b73d0SCy Schubert /* 655206b73d0SCy Schubert * Fetch statistics for station from the system. 656206b73d0SCy Schubert */ 657206b73d0SCy Schubert os_memset(&stats, 0, sizeof(stats)); 658206b73d0SCy Schubert os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); 659206b73d0SCy Schubert if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, 660206b73d0SCy Schubert &stats, sizeof(stats))) { 661206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " 662206b73d0SCy Schubert MACSTR ")", __func__, MAC2STR(addr)); 663206b73d0SCy Schubert if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { 664206b73d0SCy Schubert os_memcpy(data, &drv->acct_data, sizeof(*data)); 665206b73d0SCy Schubert return 0; 666206b73d0SCy Schubert } 667206b73d0SCy Schubert 668206b73d0SCy Schubert wpa_printf(MSG_INFO, 669206b73d0SCy Schubert "Failed to get station stats information element"); 670206b73d0SCy Schubert return -1; 671206b73d0SCy Schubert } 672206b73d0SCy Schubert 673206b73d0SCy Schubert data->rx_packets = stats.is_stats.ns_rx_data; 674206b73d0SCy Schubert data->rx_bytes = stats.is_stats.ns_rx_bytes; 675206b73d0SCy Schubert data->tx_packets = stats.is_stats.ns_tx_data; 676206b73d0SCy Schubert data->tx_bytes = stats.is_stats.ns_tx_bytes; 677206b73d0SCy Schubert return 0; 678206b73d0SCy Schubert } 679206b73d0SCy Schubert 680206b73d0SCy Schubert 681206b73d0SCy Schubert static int 682206b73d0SCy Schubert atheros_sta_clear_stats(void *priv, const u8 *addr) 683206b73d0SCy Schubert { 684206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 685206b73d0SCy Schubert struct ieee80211req_mlme mlme; 686206b73d0SCy Schubert int ret; 687206b73d0SCy Schubert 688206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); 689206b73d0SCy Schubert 690206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_CLEAR_STATS; 691206b73d0SCy Schubert os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 692206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, 693206b73d0SCy Schubert sizeof(mlme)); 694206b73d0SCy Schubert if (ret < 0) { 695206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " 696206b73d0SCy Schubert MACSTR ")", __func__, MAC2STR(addr)); 697206b73d0SCy Schubert } 698206b73d0SCy Schubert 699206b73d0SCy Schubert return ret; 700206b73d0SCy Schubert } 701206b73d0SCy Schubert 702206b73d0SCy Schubert 703206b73d0SCy Schubert static int 704206b73d0SCy Schubert atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) 705206b73d0SCy Schubert { 706206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 707206b73d0SCy Schubert u8 buf[512]; 708206b73d0SCy Schubert struct ieee80211req_getset_appiebuf *app_ie; 709206b73d0SCy Schubert 710206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, 711206b73d0SCy Schubert (unsigned long) ie_len); 712206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len); 713206b73d0SCy Schubert 714206b73d0SCy Schubert wpabuf_free(drv->wpa_ie); 715206b73d0SCy Schubert if (ie) 716206b73d0SCy Schubert drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); 717206b73d0SCy Schubert else 718206b73d0SCy Schubert drv->wpa_ie = NULL; 719206b73d0SCy Schubert 720206b73d0SCy Schubert app_ie = (struct ieee80211req_getset_appiebuf *) buf; 721206b73d0SCy Schubert if (ie) 722206b73d0SCy Schubert os_memcpy(&(app_ie->app_buf[0]), ie, ie_len); 723206b73d0SCy Schubert app_ie->app_buflen = ie_len; 724206b73d0SCy Schubert 725206b73d0SCy Schubert app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON; 726206b73d0SCy Schubert 727206b73d0SCy Schubert /* append WPS IE for Beacon */ 728206b73d0SCy Schubert if (drv->wps_beacon_ie != NULL) { 729206b73d0SCy Schubert os_memcpy(&(app_ie->app_buf[ie_len]), 730206b73d0SCy Schubert wpabuf_head(drv->wps_beacon_ie), 731206b73d0SCy Schubert wpabuf_len(drv->wps_beacon_ie)); 732206b73d0SCy Schubert app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); 733206b73d0SCy Schubert } 734206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)", 735206b73d0SCy Schubert app_ie->app_buf, app_ie->app_buflen); 736206b73d0SCy Schubert set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, 737206b73d0SCy Schubert sizeof(struct ieee80211req_getset_appiebuf) + 738206b73d0SCy Schubert app_ie->app_buflen); 739206b73d0SCy Schubert 740206b73d0SCy Schubert /* append WPS IE for Probe Response */ 741206b73d0SCy Schubert app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP; 742206b73d0SCy Schubert if (drv->wps_probe_resp_ie != NULL) { 743206b73d0SCy Schubert os_memcpy(&(app_ie->app_buf[ie_len]), 744206b73d0SCy Schubert wpabuf_head(drv->wps_probe_resp_ie), 745206b73d0SCy Schubert wpabuf_len(drv->wps_probe_resp_ie)); 746206b73d0SCy Schubert app_ie->app_buflen = ie_len + 747206b73d0SCy Schubert wpabuf_len(drv->wps_probe_resp_ie); 748206b73d0SCy Schubert } else 749206b73d0SCy Schubert app_ie->app_buflen = ie_len; 750206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)", 751206b73d0SCy Schubert app_ie->app_buf, app_ie->app_buflen); 752206b73d0SCy Schubert set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, 753206b73d0SCy Schubert sizeof(struct ieee80211req_getset_appiebuf) + 754206b73d0SCy Schubert app_ie->app_buflen); 755206b73d0SCy Schubert return 0; 756206b73d0SCy Schubert } 757206b73d0SCy Schubert 758206b73d0SCy Schubert static int 759206b73d0SCy Schubert atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 760206b73d0SCy Schubert u16 reason_code) 761206b73d0SCy Schubert { 762206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 763206b73d0SCy Schubert struct ieee80211req_mlme mlme; 764206b73d0SCy Schubert int ret; 765206b73d0SCy Schubert 766206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", 767206b73d0SCy Schubert __func__, ether_sprintf(addr), reason_code); 768206b73d0SCy Schubert 769206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_DEAUTH; 770206b73d0SCy Schubert mlme.im_reason = reason_code; 771206b73d0SCy Schubert os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 772206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 773206b73d0SCy Schubert if (ret < 0) { 774206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR 775206b73d0SCy Schubert " reason %d)", 776206b73d0SCy Schubert __func__, MAC2STR(addr), reason_code); 777206b73d0SCy Schubert } 778206b73d0SCy Schubert 779206b73d0SCy Schubert return ret; 780206b73d0SCy Schubert } 781206b73d0SCy Schubert 782206b73d0SCy Schubert static int 783206b73d0SCy Schubert atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, 784206b73d0SCy Schubert u16 reason_code) 785206b73d0SCy Schubert { 786206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 787206b73d0SCy Schubert struct ieee80211req_mlme mlme; 788206b73d0SCy Schubert int ret; 789206b73d0SCy Schubert 790206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", 791206b73d0SCy Schubert __func__, ether_sprintf(addr), reason_code); 792206b73d0SCy Schubert 793206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_DISASSOC; 794206b73d0SCy Schubert mlme.im_reason = reason_code; 795206b73d0SCy Schubert os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 796206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 797206b73d0SCy Schubert if (ret < 0) { 798206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " 799206b73d0SCy Schubert MACSTR " reason %d)", 800206b73d0SCy Schubert __func__, MAC2STR(addr), reason_code); 801206b73d0SCy Schubert } 802206b73d0SCy Schubert 803206b73d0SCy Schubert return ret; 804206b73d0SCy Schubert } 805206b73d0SCy Schubert 806206b73d0SCy Schubert static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, 807206b73d0SCy Schubert u8 qos_map_set_len) 808206b73d0SCy Schubert { 809206b73d0SCy Schubert #ifdef CONFIG_ATHEROS_QOS_MAP 810206b73d0SCy Schubert struct atheros_driver_data *drv = ctx; 811206b73d0SCy Schubert struct ieee80211req_athdbg req; 812206b73d0SCy Schubert struct ieee80211_qos_map *qos_map = &req.data.qos_map; 813206b73d0SCy Schubert struct iwreq iwr; 814206b73d0SCy Schubert int i, up_start; 815206b73d0SCy Schubert 816206b73d0SCy Schubert if (qos_map_set_len < 16 || qos_map_set_len > 58 || 817206b73d0SCy Schubert qos_map_set_len & 1) { 818206b73d0SCy Schubert wpa_printf(MSG_ERROR, "Invalid QoS Map"); 819206b73d0SCy Schubert return -1; 820206b73d0SCy Schubert } else { 821206b73d0SCy Schubert os_memset(&req, 0, sizeof(struct ieee80211req_athdbg)); 822206b73d0SCy Schubert req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF; 823206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 824206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name)); 825206b73d0SCy Schubert iwr.u.data.pointer = (void *) &req; 826206b73d0SCy Schubert iwr.u.data.length = sizeof(struct ieee80211req_athdbg); 827206b73d0SCy Schubert } 828206b73d0SCy Schubert 829206b73d0SCy Schubert qos_map->valid = 1; 830206b73d0SCy Schubert qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; 831206b73d0SCy Schubert if (qos_map->num_dscp_except) { 832206b73d0SCy Schubert for (i = 0; i < qos_map->num_dscp_except; i++) { 833206b73d0SCy Schubert qos_map->dscp_exception[i].dscp = qos_map_set[i * 2]; 834206b73d0SCy Schubert qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1]; 835206b73d0SCy Schubert } 836206b73d0SCy Schubert } 837206b73d0SCy Schubert 838206b73d0SCy Schubert up_start = qos_map_set_len - 16; 839206b73d0SCy Schubert for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) { 840206b73d0SCy Schubert qos_map->up[i].low = qos_map_set[up_start + (i * 2)]; 841206b73d0SCy Schubert qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1]; 842206b73d0SCy Schubert } 843206b73d0SCy Schubert 844206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) { 845206b73d0SCy Schubert wpa_printf(MSG_ERROR, 846206b73d0SCy Schubert "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s", 847206b73d0SCy Schubert __func__, drv->iface, strerror(errno)); 848206b73d0SCy Schubert return -1; 849206b73d0SCy Schubert } 850206b73d0SCy Schubert #endif /* CONFIG_ATHEROS_QOS_MAP */ 851206b73d0SCy Schubert 852206b73d0SCy Schubert return 0; 853206b73d0SCy Schubert } 854206b73d0SCy Schubert 855*c1d255d3SCy Schubert 856206b73d0SCy Schubert static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, 857206b73d0SCy Schubert size_t len) 858206b73d0SCy Schubert { 859206b73d0SCy Schubert struct atheros_driver_data *drv = ctx; 860206b73d0SCy Schubert const struct ieee80211_mgmt *mgmt; 861206b73d0SCy Schubert union wpa_event_data event; 862206b73d0SCy Schubert u16 fc, stype; 863206b73d0SCy Schubert int ielen; 864206b73d0SCy Schubert const u8 *iebuf; 865206b73d0SCy Schubert 866206b73d0SCy Schubert if (len < IEEE80211_HDRLEN) 867206b73d0SCy Schubert return; 868206b73d0SCy Schubert 869206b73d0SCy Schubert mgmt = (const struct ieee80211_mgmt *) buf; 870206b73d0SCy Schubert 871206b73d0SCy Schubert fc = le_to_host16(mgmt->frame_control); 872206b73d0SCy Schubert 873206b73d0SCy Schubert if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) 874206b73d0SCy Schubert return; 875206b73d0SCy Schubert 876206b73d0SCy Schubert stype = WLAN_FC_GET_STYPE(fc); 877206b73d0SCy Schubert 878206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, 879206b73d0SCy Schubert (int) len); 880206b73d0SCy Schubert 881206b73d0SCy Schubert if (stype == WLAN_FC_STYPE_PROBE_REQ) { 882206b73d0SCy Schubert if (len < IEEE80211_HDRLEN) 883206b73d0SCy Schubert return; 884206b73d0SCy Schubert 885206b73d0SCy Schubert os_memset(&event, 0, sizeof(event)); 886206b73d0SCy Schubert event.rx_probe_req.sa = mgmt->sa; 887206b73d0SCy Schubert event.rx_probe_req.da = mgmt->da; 888206b73d0SCy Schubert event.rx_probe_req.bssid = mgmt->bssid; 889206b73d0SCy Schubert event.rx_probe_req.ie = buf + IEEE80211_HDRLEN; 890206b73d0SCy Schubert event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN; 891206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); 892206b73d0SCy Schubert return; 893206b73d0SCy Schubert } 894206b73d0SCy Schubert 895206b73d0SCy Schubert if (stype == WLAN_FC_STYPE_ACTION && 896206b73d0SCy Schubert (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 || 897206b73d0SCy Schubert is_broadcast_ether_addr(mgmt->bssid))) { 898206b73d0SCy Schubert os_memset(&event, 0, sizeof(event)); 899206b73d0SCy Schubert event.rx_mgmt.frame = buf; 900206b73d0SCy Schubert event.rx_mgmt.frame_len = len; 901206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); 902206b73d0SCy Schubert return; 903206b73d0SCy Schubert } 904206b73d0SCy Schubert 905206b73d0SCy Schubert if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { 906206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", 907206b73d0SCy Schubert __func__); 908206b73d0SCy Schubert return; 909206b73d0SCy Schubert } 910206b73d0SCy Schubert 911206b73d0SCy Schubert switch (stype) { 912206b73d0SCy Schubert case WLAN_FC_STYPE_ASSOC_REQ: 913206b73d0SCy Schubert if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)) 914206b73d0SCy Schubert break; 915206b73d0SCy Schubert ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); 916206b73d0SCy Schubert iebuf = mgmt->u.assoc_req.variable; 917206b73d0SCy Schubert drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0); 918206b73d0SCy Schubert break; 919206b73d0SCy Schubert case WLAN_FC_STYPE_REASSOC_REQ: 920206b73d0SCy Schubert if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)) 921206b73d0SCy Schubert break; 922206b73d0SCy Schubert ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); 923206b73d0SCy Schubert iebuf = mgmt->u.reassoc_req.variable; 924206b73d0SCy Schubert drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); 925206b73d0SCy Schubert break; 926206b73d0SCy Schubert case WLAN_FC_STYPE_AUTH: 927206b73d0SCy Schubert if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) 928206b73d0SCy Schubert break; 929206b73d0SCy Schubert os_memset(&event, 0, sizeof(event)); 930206b73d0SCy Schubert if (le_to_host16(mgmt->u.auth.auth_alg) == WLAN_AUTH_SAE) { 931206b73d0SCy Schubert event.rx_mgmt.frame = buf; 932206b73d0SCy Schubert event.rx_mgmt.frame_len = len; 933206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); 934206b73d0SCy Schubert break; 935206b73d0SCy Schubert } 936206b73d0SCy Schubert os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); 937206b73d0SCy Schubert os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN); 938206b73d0SCy Schubert event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); 939206b73d0SCy Schubert event.auth.status_code = 940206b73d0SCy Schubert le_to_host16(mgmt->u.auth.status_code); 941206b73d0SCy Schubert event.auth.auth_transaction = 942206b73d0SCy Schubert le_to_host16(mgmt->u.auth.auth_transaction); 943206b73d0SCy Schubert event.auth.ies = mgmt->u.auth.variable; 944206b73d0SCy Schubert event.auth.ies_len = len - IEEE80211_HDRLEN - 945206b73d0SCy Schubert sizeof(mgmt->u.auth); 946206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event); 947206b73d0SCy Schubert break; 948206b73d0SCy Schubert default: 949206b73d0SCy Schubert break; 950206b73d0SCy Schubert } 951206b73d0SCy Schubert } 952*c1d255d3SCy Schubert 953206b73d0SCy Schubert 954206b73d0SCy Schubert static int atheros_receive_pkt(struct atheros_driver_data *drv) 955206b73d0SCy Schubert { 956206b73d0SCy Schubert int ret = 0; 957206b73d0SCy Schubert struct ieee80211req_set_filter filt; 958206b73d0SCy Schubert 959206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s Enter", __func__); 960206b73d0SCy Schubert filt.app_filterype = 0; 961206b73d0SCy Schubert #ifdef CONFIG_WPS 962206b73d0SCy Schubert filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ; 963206b73d0SCy Schubert #endif /* CONFIG_WPS */ 964206b73d0SCy Schubert filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | 965206b73d0SCy Schubert IEEE80211_FILTER_TYPE_AUTH | 966206b73d0SCy Schubert IEEE80211_FILTER_TYPE_ACTION); 967206b73d0SCy Schubert #ifdef CONFIG_WNM 968206b73d0SCy Schubert filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; 969206b73d0SCy Schubert #endif /* CONFIG_WNM */ 970206b73d0SCy Schubert #ifdef CONFIG_HS20 971206b73d0SCy Schubert filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; 972206b73d0SCy Schubert #endif /* CONFIG_HS20 */ 973206b73d0SCy Schubert if (filt.app_filterype) { 974206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, 975206b73d0SCy Schubert sizeof(struct ieee80211req_set_filter)); 976206b73d0SCy Schubert if (ret) 977206b73d0SCy Schubert return ret; 978206b73d0SCy Schubert } 979206b73d0SCy Schubert 980206b73d0SCy Schubert #if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) 981206b73d0SCy Schubert drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, 982206b73d0SCy Schubert atheros_raw_receive, drv, 1); 983206b73d0SCy Schubert if (drv->sock_raw == NULL) 984206b73d0SCy Schubert return -1; 985206b73d0SCy Schubert #endif /* CONFIG_WPS || CONFIG_IEEE80211R || CONFIG_FILS */ 986206b73d0SCy Schubert return ret; 987206b73d0SCy Schubert } 988206b73d0SCy Schubert 989206b73d0SCy Schubert static int atheros_reset_appfilter(struct atheros_driver_data *drv) 990206b73d0SCy Schubert { 991206b73d0SCy Schubert struct ieee80211req_set_filter filt; 992206b73d0SCy Schubert filt.app_filterype = 0; 993206b73d0SCy Schubert return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, 994206b73d0SCy Schubert sizeof(struct ieee80211req_set_filter)); 995206b73d0SCy Schubert } 996206b73d0SCy Schubert 997206b73d0SCy Schubert #ifdef CONFIG_WPS 998206b73d0SCy Schubert static int 999206b73d0SCy Schubert atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) 1000206b73d0SCy Schubert { 1001206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1002206b73d0SCy Schubert u8 buf[512]; 1003206b73d0SCy Schubert struct ieee80211req_getset_appiebuf *beac_ie; 1004206b73d0SCy Schubert 1005206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__, 1006206b73d0SCy Schubert (unsigned long) len, frametype); 1007206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len); 1008206b73d0SCy Schubert 1009206b73d0SCy Schubert beac_ie = (struct ieee80211req_getset_appiebuf *) buf; 1010206b73d0SCy Schubert beac_ie->app_frmtype = frametype; 1011206b73d0SCy Schubert beac_ie->app_buflen = len; 1012206b73d0SCy Schubert if (ie) 1013206b73d0SCy Schubert os_memcpy(&(beac_ie->app_buf[0]), ie, len); 1014206b73d0SCy Schubert 1015206b73d0SCy Schubert /* append the WPA/RSN IE if it is set already */ 1016206b73d0SCy Schubert if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || 1017206b73d0SCy Schubert (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && 1018206b73d0SCy Schubert (drv->wpa_ie != NULL)) { 1019206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE", 1020206b73d0SCy Schubert drv->wpa_ie); 1021206b73d0SCy Schubert os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), 1022206b73d0SCy Schubert wpabuf_len(drv->wpa_ie)); 1023206b73d0SCy Schubert beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); 1024206b73d0SCy Schubert } 1025206b73d0SCy Schubert 1026206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF", 1027206b73d0SCy Schubert beac_ie->app_buf, beac_ie->app_buflen); 1028206b73d0SCy Schubert return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, 1029206b73d0SCy Schubert sizeof(struct ieee80211req_getset_appiebuf) + 1030206b73d0SCy Schubert beac_ie->app_buflen); 1031206b73d0SCy Schubert } 1032206b73d0SCy Schubert 1033206b73d0SCy Schubert static int 1034206b73d0SCy Schubert atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, 1035206b73d0SCy Schubert const struct wpabuf *proberesp, 1036206b73d0SCy Schubert const struct wpabuf *assocresp) 1037206b73d0SCy Schubert { 1038206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1039206b73d0SCy Schubert 1040206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon); 1041206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp", 1042206b73d0SCy Schubert proberesp); 1043206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp", 1044206b73d0SCy Schubert assocresp); 1045206b73d0SCy Schubert wpabuf_free(drv->wps_beacon_ie); 1046206b73d0SCy Schubert drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; 1047206b73d0SCy Schubert wpabuf_free(drv->wps_probe_resp_ie); 1048206b73d0SCy Schubert drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL; 1049206b73d0SCy Schubert 1050206b73d0SCy Schubert atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, 1051206b73d0SCy Schubert assocresp ? wpabuf_len(assocresp) : 0, 1052206b73d0SCy Schubert IEEE80211_APPIE_FRAME_ASSOC_RESP); 1053206b73d0SCy Schubert if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, 1054206b73d0SCy Schubert beacon ? wpabuf_len(beacon) : 0, 1055206b73d0SCy Schubert IEEE80211_APPIE_FRAME_BEACON)) 1056206b73d0SCy Schubert return -1; 1057206b73d0SCy Schubert return atheros_set_wps_ie(priv, 1058206b73d0SCy Schubert proberesp ? wpabuf_head(proberesp) : NULL, 1059206b73d0SCy Schubert proberesp ? wpabuf_len(proberesp): 0, 1060206b73d0SCy Schubert IEEE80211_APPIE_FRAME_PROBE_RESP); 1061206b73d0SCy Schubert } 1062206b73d0SCy Schubert #else /* CONFIG_WPS */ 1063206b73d0SCy Schubert #define atheros_set_ap_wps_ie NULL 1064206b73d0SCy Schubert #endif /* CONFIG_WPS */ 1065206b73d0SCy Schubert 1066206b73d0SCy Schubert static int 1067206b73d0SCy Schubert atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params) 1068206b73d0SCy Schubert { 1069206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1070206b73d0SCy Schubert struct ieee80211req_mlme mlme; 1071206b73d0SCy Schubert int ret; 1072206b73d0SCy Schubert 1073206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d", 1074206b73d0SCy Schubert __func__, ether_sprintf(params->addr), params->status); 1075206b73d0SCy Schubert 1076206b73d0SCy Schubert #ifdef CONFIG_FILS 1077206b73d0SCy Schubert /* Copy FILS AAD parameters if the driver supports FILS */ 1078206b73d0SCy Schubert if (params->fils_auth && drv->fils_en) { 1079206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: im_op IEEE80211_MLME_AUTH_FILS", 1080206b73d0SCy Schubert __func__); 1081206b73d0SCy Schubert os_memcpy(mlme.fils_aad.ANonce, params->fils_anonce, 1082206b73d0SCy Schubert IEEE80211_FILS_NONCE_LEN); 1083206b73d0SCy Schubert os_memcpy(mlme.fils_aad.SNonce, params->fils_snonce, 1084206b73d0SCy Schubert IEEE80211_FILS_NONCE_LEN); 1085206b73d0SCy Schubert os_memcpy(mlme.fils_aad.kek, params->fils_kek, 1086206b73d0SCy Schubert IEEE80211_MAX_WPA_KEK_LEN); 1087206b73d0SCy Schubert mlme.fils_aad.kek_len = params->fils_kek_len; 1088206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_AUTH_FILS; 1089206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "FILS: ANonce", 1090206b73d0SCy Schubert mlme.fils_aad.ANonce, FILS_NONCE_LEN); 1091206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "FILS: SNonce", 1092206b73d0SCy Schubert mlme.fils_aad.SNonce, FILS_NONCE_LEN); 1093206b73d0SCy Schubert wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", 1094206b73d0SCy Schubert mlme.fils_aad.kek, mlme.fils_aad.kek_len); 1095206b73d0SCy Schubert } else { 1096206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_AUTH; 1097206b73d0SCy Schubert } 1098206b73d0SCy Schubert #else /* CONFIG_FILS */ 1099206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_AUTH; 1100206b73d0SCy Schubert #endif /* CONFIG_FILS */ 1101206b73d0SCy Schubert 1102206b73d0SCy Schubert mlme.im_reason = params->status; 1103206b73d0SCy Schubert mlme.im_seq = params->seq; 1104206b73d0SCy Schubert os_memcpy(mlme.im_macaddr, params->addr, IEEE80211_ADDR_LEN); 1105206b73d0SCy Schubert mlme.im_optie_len = params->len; 1106206b73d0SCy Schubert if (params->len) { 1107206b73d0SCy Schubert if (params->len < IEEE80211_MAX_OPT_IE) { 1108206b73d0SCy Schubert os_memcpy(mlme.im_optie, params->ie, params->len); 1109206b73d0SCy Schubert } else { 1110206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " 1111206b73d0SCy Schubert "opt_ie STA (addr " MACSTR " reason %d, " 1112206b73d0SCy Schubert "ie_len %d)", 1113206b73d0SCy Schubert __func__, MAC2STR(params->addr), 1114206b73d0SCy Schubert params->status, (int) params->len); 1115206b73d0SCy Schubert return -1; 1116206b73d0SCy Schubert } 1117206b73d0SCy Schubert } 1118206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 1119206b73d0SCy Schubert if (ret < 0) { 1120206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR 1121206b73d0SCy Schubert " reason %d)", 1122206b73d0SCy Schubert __func__, MAC2STR(params->addr), params->status); 1123206b73d0SCy Schubert } 1124206b73d0SCy Schubert return ret; 1125206b73d0SCy Schubert } 1126206b73d0SCy Schubert 1127206b73d0SCy Schubert static int 1128206b73d0SCy Schubert atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, 1129206b73d0SCy Schubert int reassoc, u16 status_code, const u8 *ie, size_t len) 1130206b73d0SCy Schubert { 1131206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1132206b73d0SCy Schubert struct ieee80211req_mlme mlme; 1133206b73d0SCy Schubert int ret; 1134206b73d0SCy Schubert 1135206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d", 1136206b73d0SCy Schubert __func__, ether_sprintf(addr), status_code, reassoc); 1137206b73d0SCy Schubert 1138206b73d0SCy Schubert if (reassoc) 1139206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_REASSOC; 1140206b73d0SCy Schubert else 1141206b73d0SCy Schubert mlme.im_op = IEEE80211_MLME_ASSOC; 1142206b73d0SCy Schubert mlme.im_reason = status_code; 1143206b73d0SCy Schubert os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 1144206b73d0SCy Schubert mlme.im_optie_len = len; 1145206b73d0SCy Schubert if (len) { 1146206b73d0SCy Schubert if (len < IEEE80211_MAX_OPT_IE) { 1147206b73d0SCy Schubert os_memcpy(mlme.im_optie, ie, len); 1148206b73d0SCy Schubert } else { 1149206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " 1150206b73d0SCy Schubert "opt_ie STA (addr " MACSTR " reason %d, " 1151206b73d0SCy Schubert "ie_len %d)", 1152206b73d0SCy Schubert __func__, MAC2STR(addr), status_code, 1153206b73d0SCy Schubert (int) len); 1154206b73d0SCy Schubert return -1; 1155206b73d0SCy Schubert } 1156206b73d0SCy Schubert } 1157206b73d0SCy Schubert ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 1158206b73d0SCy Schubert if (ret < 0) { 1159206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR 1160206b73d0SCy Schubert " reason %d)", 1161206b73d0SCy Schubert __func__, MAC2STR(addr), status_code); 1162206b73d0SCy Schubert } 1163206b73d0SCy Schubert return ret; 1164206b73d0SCy Schubert } 1165*c1d255d3SCy Schubert 1166206b73d0SCy Schubert 1167206b73d0SCy Schubert static void 1168206b73d0SCy Schubert atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) 1169206b73d0SCy Schubert { 1170206b73d0SCy Schubert struct hostapd_data *hapd = drv->hapd; 1171206b73d0SCy Schubert struct ieee80211req_wpaie ie; 1172206b73d0SCy Schubert int ielen = 0; 1173206b73d0SCy Schubert u8 *iebuf = NULL; 1174206b73d0SCy Schubert 1175206b73d0SCy Schubert /* 1176206b73d0SCy Schubert * Fetch negotiated WPA/RSN parameters from the system. 1177206b73d0SCy Schubert */ 1178206b73d0SCy Schubert os_memset(&ie, 0, sizeof(ie)); 1179206b73d0SCy Schubert os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); 1180206b73d0SCy Schubert if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { 1181206b73d0SCy Schubert /* 1182206b73d0SCy Schubert * See ATH_WPS_IE comment in the beginning of the file for a 1183206b73d0SCy Schubert * possible cause for the failure.. 1184206b73d0SCy Schubert */ 1185206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", 1186206b73d0SCy Schubert __func__, strerror(errno)); 1187206b73d0SCy Schubert goto no_ie; 1188206b73d0SCy Schubert } 1189206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", 1190206b73d0SCy Schubert ie.wpa_ie, IEEE80211_MAX_OPT_IE); 1191206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", 1192206b73d0SCy Schubert ie.rsn_ie, IEEE80211_MAX_OPT_IE); 1193206b73d0SCy Schubert #ifdef ATH_WPS_IE 1194206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", 1195206b73d0SCy Schubert ie.wps_ie, IEEE80211_MAX_OPT_IE); 1196206b73d0SCy Schubert #endif /* ATH_WPS_IE */ 1197206b73d0SCy Schubert iebuf = ie.wpa_ie; 1198206b73d0SCy Schubert /* atheros seems to return some random data if WPA/RSN IE is not set. 1199206b73d0SCy Schubert * Assume the IE was not included if the IE type is unknown. */ 1200206b73d0SCy Schubert if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) 1201206b73d0SCy Schubert iebuf[1] = 0; 1202206b73d0SCy Schubert if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { 1203206b73d0SCy Schubert /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not 1204206b73d0SCy Schubert * set. This is needed for WPA2. */ 1205206b73d0SCy Schubert iebuf = ie.rsn_ie; 1206206b73d0SCy Schubert if (iebuf[0] != WLAN_EID_RSN) 1207206b73d0SCy Schubert iebuf[1] = 0; 1208206b73d0SCy Schubert } 1209206b73d0SCy Schubert 1210206b73d0SCy Schubert ielen = iebuf[1]; 1211206b73d0SCy Schubert 1212206b73d0SCy Schubert #ifdef ATH_WPS_IE 1213206b73d0SCy Schubert /* if WPS IE is present, preference is given to WPS */ 1214206b73d0SCy Schubert if (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie.wps_ie[1] > 0) { 1215206b73d0SCy Schubert iebuf = ie.wps_ie; 1216206b73d0SCy Schubert ielen = ie.wps_ie[1]; 1217206b73d0SCy Schubert } 1218206b73d0SCy Schubert #endif /* ATH_WPS_IE */ 1219206b73d0SCy Schubert 1220206b73d0SCy Schubert if (ielen == 0) 1221206b73d0SCy Schubert iebuf = NULL; 1222206b73d0SCy Schubert else 1223206b73d0SCy Schubert ielen += 2; 1224206b73d0SCy Schubert 1225206b73d0SCy Schubert no_ie: 1226206b73d0SCy Schubert drv_event_assoc(hapd, addr, iebuf, ielen, 0); 1227206b73d0SCy Schubert 1228206b73d0SCy Schubert if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { 1229206b73d0SCy Schubert /* Cached accounting data is not valid anymore. */ 1230206b73d0SCy Schubert os_memset(drv->acct_mac, 0, ETH_ALEN); 1231206b73d0SCy Schubert os_memset(&drv->acct_data, 0, sizeof(drv->acct_data)); 1232206b73d0SCy Schubert } 1233206b73d0SCy Schubert } 1234206b73d0SCy Schubert 1235206b73d0SCy Schubert static void 1236206b73d0SCy Schubert atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, 1237206b73d0SCy Schubert char *custom, char *end) 1238206b73d0SCy Schubert { 1239206b73d0SCy Schubert #define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ 1240206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); 1241206b73d0SCy Schubert 1242206b73d0SCy Schubert if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { 1243206b73d0SCy Schubert char *pos; 1244206b73d0SCy Schubert u8 addr[ETH_ALEN]; 1245206b73d0SCy Schubert pos = os_strstr(custom, "addr="); 1246206b73d0SCy Schubert if (pos == NULL) { 1247206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1248206b73d0SCy Schubert "MLME-MICHAELMICFAILURE.indication " 1249206b73d0SCy Schubert "without sender address ignored"); 1250206b73d0SCy Schubert return; 1251206b73d0SCy Schubert } 1252206b73d0SCy Schubert pos += 5; 1253206b73d0SCy Schubert if (hwaddr_aton(pos, addr) == 0) { 1254206b73d0SCy Schubert union wpa_event_data data; 1255206b73d0SCy Schubert os_memset(&data, 0, sizeof(data)); 1256206b73d0SCy Schubert data.michael_mic_failure.unicast = 1; 1257206b73d0SCy Schubert data.michael_mic_failure.src = addr; 1258206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, 1259206b73d0SCy Schubert EVENT_MICHAEL_MIC_FAILURE, &data); 1260206b73d0SCy Schubert } else { 1261206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1262206b73d0SCy Schubert "MLME-MICHAELMICFAILURE.indication " 1263206b73d0SCy Schubert "with invalid MAC address"); 1264206b73d0SCy Schubert } 1265206b73d0SCy Schubert } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { 1266206b73d0SCy Schubert char *key, *value; 1267206b73d0SCy Schubert u32 val; 1268206b73d0SCy Schubert key = custom; 1269206b73d0SCy Schubert while ((key = os_strchr(key, '\n')) != NULL) { 1270206b73d0SCy Schubert key++; 1271206b73d0SCy Schubert value = os_strchr(key, '='); 1272206b73d0SCy Schubert if (value == NULL) 1273206b73d0SCy Schubert continue; 1274206b73d0SCy Schubert *value++ = '\0'; 1275206b73d0SCy Schubert val = strtoul(value, NULL, 10); 1276206b73d0SCy Schubert if (os_strcmp(key, "mac") == 0) 1277206b73d0SCy Schubert hwaddr_aton(value, drv->acct_mac); 1278206b73d0SCy Schubert else if (os_strcmp(key, "rx_packets") == 0) 1279206b73d0SCy Schubert drv->acct_data.rx_packets = val; 1280206b73d0SCy Schubert else if (os_strcmp(key, "tx_packets") == 0) 1281206b73d0SCy Schubert drv->acct_data.tx_packets = val; 1282206b73d0SCy Schubert else if (os_strcmp(key, "rx_bytes") == 0) 1283206b73d0SCy Schubert drv->acct_data.rx_bytes = val; 1284206b73d0SCy Schubert else if (os_strcmp(key, "tx_bytes") == 0) 1285206b73d0SCy Schubert drv->acct_data.tx_bytes = val; 1286206b73d0SCy Schubert key = value; 1287206b73d0SCy Schubert } 1288206b73d0SCy Schubert #ifdef CONFIG_WPS 1289206b73d0SCy Schubert } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { 1290206b73d0SCy Schubert /* Some atheros kernels send push button as a wireless event */ 1291206b73d0SCy Schubert /* PROBLEM! this event is received for ALL BSSs ... 1292206b73d0SCy Schubert * so all are enabled for WPS... ugh. 1293206b73d0SCy Schubert */ 1294206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); 1295206b73d0SCy Schubert } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) { 1296206b73d0SCy Schubert /* 1297206b73d0SCy Schubert * Atheros driver uses a hack to pass Probe Request frames as a 1298206b73d0SCy Schubert * binary data in the custom wireless event. The old way (using 1299206b73d0SCy Schubert * packet sniffing) didn't work when bridging. 1300206b73d0SCy Schubert * Format: "Manage.prob_req <frame len>" | zero padding | frame 1301206b73d0SCy Schubert */ 1302206b73d0SCy Schubert int len = atoi(custom + 16); 1303206b73d0SCy Schubert if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1304206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event " 1305206b73d0SCy Schubert "length %d", len); 1306206b73d0SCy Schubert return; 1307206b73d0SCy Schubert } 1308206b73d0SCy Schubert atheros_raw_receive(drv, NULL, 1309206b73d0SCy Schubert (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1310206b73d0SCy Schubert #endif /* CONFIG_WPS */ 1311206b73d0SCy Schubert } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) { 1312206b73d0SCy Schubert /* Format: "Manage.assoc_req <frame len>" | zero padding | 1313206b73d0SCy Schubert * frame */ 1314206b73d0SCy Schubert int len = atoi(custom + 17); 1315206b73d0SCy Schubert if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1316206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1317206b73d0SCy Schubert "Invalid Manage.assoc_req event length %d", 1318206b73d0SCy Schubert len); 1319206b73d0SCy Schubert return; 1320206b73d0SCy Schubert } 1321206b73d0SCy Schubert atheros_raw_receive(drv, NULL, 1322206b73d0SCy Schubert (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1323206b73d0SCy Schubert } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { 1324206b73d0SCy Schubert /* Format: "Manage.auth <frame len>" | zero padding | frame */ 1325206b73d0SCy Schubert int len = atoi(custom + 12); 1326206b73d0SCy Schubert if (len < 0 || 1327206b73d0SCy Schubert MGMT_FRAM_TAG_SIZE + len > end - custom) { 1328206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1329206b73d0SCy Schubert "Invalid Manage.auth event length %d", len); 1330206b73d0SCy Schubert return; 1331206b73d0SCy Schubert } 1332206b73d0SCy Schubert atheros_raw_receive(drv, NULL, 1333206b73d0SCy Schubert (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1334206b73d0SCy Schubert } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { 1335206b73d0SCy Schubert /* Format: "Manage.assoc_req <frame len>" | zero padding | frame 1336206b73d0SCy Schubert */ 1337206b73d0SCy Schubert int len = atoi(custom + 14); 1338206b73d0SCy Schubert if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1339206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1340206b73d0SCy Schubert "Invalid Manage.action event length %d", 1341206b73d0SCy Schubert len); 1342206b73d0SCy Schubert return; 1343206b73d0SCy Schubert } 1344206b73d0SCy Schubert atheros_raw_receive(drv, NULL, 1345206b73d0SCy Schubert (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1346206b73d0SCy Schubert } 1347206b73d0SCy Schubert } 1348206b73d0SCy Schubert 1349206b73d0SCy Schubert 1350206b73d0SCy Schubert static void send_action_cb_event(struct atheros_driver_data *drv, 1351206b73d0SCy Schubert char *data, size_t data_len) 1352206b73d0SCy Schubert { 1353206b73d0SCy Schubert union wpa_event_data event; 1354206b73d0SCy Schubert struct ieee80211_send_action_cb *sa; 1355206b73d0SCy Schubert const struct ieee80211_hdr *hdr; 1356206b73d0SCy Schubert u16 fc; 1357206b73d0SCy Schubert 1358206b73d0SCy Schubert if (data_len < sizeof(*sa) + 24) { 1359206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1360206b73d0SCy Schubert "athr: Too short event message (data_len=%d sizeof(*sa)=%d)", 1361206b73d0SCy Schubert (int) data_len, (int) sizeof(*sa)); 1362206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "athr: Short event message", 1363206b73d0SCy Schubert data, data_len); 1364206b73d0SCy Schubert return; 1365206b73d0SCy Schubert } 1366206b73d0SCy Schubert 1367206b73d0SCy Schubert sa = (struct ieee80211_send_action_cb *) data; 1368206b73d0SCy Schubert 1369206b73d0SCy Schubert hdr = (const struct ieee80211_hdr *) (sa + 1); 1370206b73d0SCy Schubert fc = le_to_host16(hdr->frame_control); 1371206b73d0SCy Schubert 1372206b73d0SCy Schubert os_memset(&event, 0, sizeof(event)); 1373206b73d0SCy Schubert event.tx_status.type = WLAN_FC_GET_TYPE(fc); 1374206b73d0SCy Schubert event.tx_status.stype = WLAN_FC_GET_STYPE(fc); 1375206b73d0SCy Schubert event.tx_status.dst = sa->dst_addr; 1376206b73d0SCy Schubert event.tx_status.data = (const u8 *) hdr; 1377206b73d0SCy Schubert event.tx_status.data_len = data_len - sizeof(*sa); 1378206b73d0SCy Schubert event.tx_status.ack = sa->ack; 1379206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event); 1380206b73d0SCy Schubert } 1381206b73d0SCy Schubert 1382206b73d0SCy Schubert 1383206b73d0SCy Schubert /* 1384206b73d0SCy Schubert * Handle size of data problem. WEXT only allows data of 256 bytes for custom 1385206b73d0SCy Schubert * events, and p2p data can be much bigger. So the athr driver sends a small 1386206b73d0SCy Schubert * event telling me to collect the big data with an ioctl. 1387206b73d0SCy Schubert * On the first event, send all pending events to supplicant. 1388206b73d0SCy Schubert */ 1389206b73d0SCy Schubert static void fetch_pending_big_events(struct atheros_driver_data *drv) 1390206b73d0SCy Schubert { 1391206b73d0SCy Schubert union wpa_event_data event; 1392206b73d0SCy Schubert const struct ieee80211_mgmt *mgmt; 1393206b73d0SCy Schubert u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */ 1394206b73d0SCy Schubert u16 fc, stype; 1395206b73d0SCy Schubert struct iwreq iwr; 1396206b73d0SCy Schubert size_t data_len; 1397206b73d0SCy Schubert u32 freq, frame_type; 1398206b73d0SCy Schubert 1399206b73d0SCy Schubert while (1) { 1400206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 1401206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1402206b73d0SCy Schubert 1403206b73d0SCy Schubert iwr.u.data.pointer = (void *) tbuf; 1404206b73d0SCy Schubert iwr.u.data.length = sizeof(tbuf); 1405206b73d0SCy Schubert iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME; 1406206b73d0SCy Schubert 1407206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) 1408206b73d0SCy Schubert < 0) { 1409206b73d0SCy Schubert if (errno == ENOSPC) { 1410206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s:%d exit", 1411206b73d0SCy Schubert __func__, __LINE__); 1412206b73d0SCy Schubert return; 1413206b73d0SCy Schubert } 1414206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM[" 1415206b73d0SCy Schubert "P2P_FETCH_FRAME] failed: %s", 1416206b73d0SCy Schubert __func__, strerror(errno)); 1417206b73d0SCy Schubert return; 1418206b73d0SCy Schubert } 1419206b73d0SCy Schubert data_len = iwr.u.data.length; 1420206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data", 1421206b73d0SCy Schubert (u8 *) tbuf, data_len); 1422206b73d0SCy Schubert if (data_len < sizeof(freq) + sizeof(frame_type) + 24) { 1423206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "athr: frame too short"); 1424206b73d0SCy Schubert continue; 1425206b73d0SCy Schubert } 1426206b73d0SCy Schubert os_memcpy(&freq, tbuf, sizeof(freq)); 1427206b73d0SCy Schubert os_memcpy(&frame_type, &tbuf[sizeof(freq)], 1428206b73d0SCy Schubert sizeof(frame_type)); 1429206b73d0SCy Schubert mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)]; 1430206b73d0SCy Schubert data_len -= sizeof(freq) + sizeof(frame_type); 1431206b73d0SCy Schubert 1432206b73d0SCy Schubert if (frame_type == IEEE80211_EV_RX_MGMT) { 1433206b73d0SCy Schubert fc = le_to_host16(mgmt->frame_control); 1434206b73d0SCy Schubert stype = WLAN_FC_GET_STYPE(fc); 1435206b73d0SCy Schubert 1436206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u " 1437206b73d0SCy Schubert "freq=%u len=%u", stype, freq, (int) data_len); 1438206b73d0SCy Schubert 1439206b73d0SCy Schubert if (stype == WLAN_FC_STYPE_ACTION) { 1440206b73d0SCy Schubert os_memset(&event, 0, sizeof(event)); 1441206b73d0SCy Schubert event.rx_mgmt.frame = (const u8 *) mgmt; 1442206b73d0SCy Schubert event.rx_mgmt.frame_len = data_len; 1443206b73d0SCy Schubert wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, 1444206b73d0SCy Schubert &event); 1445206b73d0SCy Schubert continue; 1446206b73d0SCy Schubert } 1447206b73d0SCy Schubert } else if (frame_type == IEEE80211_EV_P2P_SEND_ACTION_CB) { 1448206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1449206b73d0SCy Schubert "%s: ACTION_CB frame_type=%u len=%zu", 1450206b73d0SCy Schubert __func__, frame_type, data_len); 1451206b73d0SCy Schubert send_action_cb_event(drv, (void *) mgmt, data_len); 1452206b73d0SCy Schubert } else { 1453206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "athr: %s unknown type %d", 1454206b73d0SCy Schubert __func__, frame_type); 1455206b73d0SCy Schubert continue; 1456206b73d0SCy Schubert } 1457206b73d0SCy Schubert } 1458206b73d0SCy Schubert } 1459206b73d0SCy Schubert 1460206b73d0SCy Schubert static void 1461206b73d0SCy Schubert atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv, 1462206b73d0SCy Schubert int opcode, char *buf, int len) 1463206b73d0SCy Schubert { 1464206b73d0SCy Schubert switch (opcode) { 1465206b73d0SCy Schubert case IEEE80211_EV_P2P_SEND_ACTION_CB: 1466206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "WEXT: EV_P2P_SEND_ACTION_CB"); 1467206b73d0SCy Schubert fetch_pending_big_events(drv); 1468206b73d0SCy Schubert break; 1469206b73d0SCy Schubert case IEEE80211_EV_RX_MGMT: 1470206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT"); 1471206b73d0SCy Schubert fetch_pending_big_events(drv); 1472206b73d0SCy Schubert break; 1473206b73d0SCy Schubert default: 1474206b73d0SCy Schubert break; 1475206b73d0SCy Schubert } 1476206b73d0SCy Schubert } 1477206b73d0SCy Schubert 1478206b73d0SCy Schubert static void 1479206b73d0SCy Schubert atheros_wireless_event_wireless(struct atheros_driver_data *drv, 1480206b73d0SCy Schubert char *data, unsigned int len) 1481206b73d0SCy Schubert { 1482206b73d0SCy Schubert struct iw_event iwe_buf, *iwe = &iwe_buf; 1483206b73d0SCy Schubert char *pos, *end, *custom, *buf; 1484206b73d0SCy Schubert 1485206b73d0SCy Schubert pos = data; 1486206b73d0SCy Schubert end = data + len; 1487206b73d0SCy Schubert 1488206b73d0SCy Schubert while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { 1489206b73d0SCy Schubert /* Event data may be unaligned, so make a local, aligned copy 1490206b73d0SCy Schubert * before processing. */ 1491206b73d0SCy Schubert os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); 1492206b73d0SCy Schubert wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", 1493206b73d0SCy Schubert iwe->cmd, iwe->len); 1494206b73d0SCy Schubert if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) 1495206b73d0SCy Schubert return; 1496206b73d0SCy Schubert 1497206b73d0SCy Schubert custom = pos + IW_EV_POINT_LEN; 1498206b73d0SCy Schubert if (drv->we_version > 18 && 1499206b73d0SCy Schubert (iwe->cmd == IWEVMICHAELMICFAILURE || 1500206b73d0SCy Schubert iwe->cmd == IWEVASSOCREQIE || 1501206b73d0SCy Schubert iwe->cmd == IWEVCUSTOM)) { 1502206b73d0SCy Schubert /* WE-19 removed the pointer from struct iw_point */ 1503206b73d0SCy Schubert char *dpos = (char *) &iwe_buf.u.data.length; 1504206b73d0SCy Schubert int dlen = dpos - (char *) &iwe_buf; 1505206b73d0SCy Schubert os_memcpy(dpos, pos + IW_EV_LCP_LEN, 1506206b73d0SCy Schubert sizeof(struct iw_event) - dlen); 1507206b73d0SCy Schubert } else { 1508206b73d0SCy Schubert os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); 1509206b73d0SCy Schubert custom += IW_EV_POINT_OFF; 1510206b73d0SCy Schubert } 1511206b73d0SCy Schubert 1512206b73d0SCy Schubert switch (iwe->cmd) { 1513206b73d0SCy Schubert case IWEVEXPIRED: 1514206b73d0SCy Schubert drv_event_disassoc(drv->hapd, 1515206b73d0SCy Schubert (u8 *) iwe->u.addr.sa_data); 1516206b73d0SCy Schubert break; 1517206b73d0SCy Schubert case IWEVREGISTERED: 1518206b73d0SCy Schubert atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data); 1519206b73d0SCy Schubert break; 1520206b73d0SCy Schubert case IWEVASSOCREQIE: 1521206b73d0SCy Schubert /* Driver hack.. Use IWEVASSOCREQIE to bypass 1522206b73d0SCy Schubert * IWEVCUSTOM size limitations. Need to handle this 1523206b73d0SCy Schubert * just like IWEVCUSTOM. 1524206b73d0SCy Schubert */ 1525206b73d0SCy Schubert case IWEVCUSTOM: 1526206b73d0SCy Schubert if (iwe->u.data.length > end - custom) 1527206b73d0SCy Schubert return; 1528206b73d0SCy Schubert buf = os_malloc(iwe->u.data.length + 1); 1529206b73d0SCy Schubert if (buf == NULL) 1530206b73d0SCy Schubert return; /* XXX */ 1531206b73d0SCy Schubert os_memcpy(buf, custom, iwe->u.data.length); 1532206b73d0SCy Schubert buf[iwe->u.data.length] = '\0'; 1533206b73d0SCy Schubert 1534206b73d0SCy Schubert if (iwe->u.data.flags != 0) { 1535206b73d0SCy Schubert atheros_wireless_event_atheros_custom( 1536206b73d0SCy Schubert drv, (int) iwe->u.data.flags, 1537206b73d0SCy Schubert buf, len); 1538206b73d0SCy Schubert } else { 1539206b73d0SCy Schubert atheros_wireless_event_wireless_custom( 1540206b73d0SCy Schubert drv, buf, buf + iwe->u.data.length); 1541206b73d0SCy Schubert } 1542206b73d0SCy Schubert os_free(buf); 1543206b73d0SCy Schubert break; 1544206b73d0SCy Schubert } 1545206b73d0SCy Schubert 1546206b73d0SCy Schubert pos += iwe->len; 1547206b73d0SCy Schubert } 1548206b73d0SCy Schubert } 1549206b73d0SCy Schubert 1550206b73d0SCy Schubert 1551206b73d0SCy Schubert static void 1552206b73d0SCy Schubert atheros_wireless_event_rtm_newlink(void *ctx, 1553206b73d0SCy Schubert struct ifinfomsg *ifi, u8 *buf, size_t len) 1554206b73d0SCy Schubert { 1555206b73d0SCy Schubert struct atheros_driver_data *drv = ctx; 1556206b73d0SCy Schubert int attrlen, rta_len; 1557206b73d0SCy Schubert struct rtattr *attr; 1558206b73d0SCy Schubert 1559206b73d0SCy Schubert if (ifi->ifi_index != drv->ifindex) 1560206b73d0SCy Schubert return; 1561206b73d0SCy Schubert 1562206b73d0SCy Schubert attrlen = len; 1563206b73d0SCy Schubert attr = (struct rtattr *) buf; 1564206b73d0SCy Schubert 1565206b73d0SCy Schubert rta_len = RTA_ALIGN(sizeof(struct rtattr)); 1566206b73d0SCy Schubert while (RTA_OK(attr, attrlen)) { 1567206b73d0SCy Schubert if (attr->rta_type == IFLA_WIRELESS) { 1568206b73d0SCy Schubert atheros_wireless_event_wireless( 1569206b73d0SCy Schubert drv, ((char *) attr) + rta_len, 1570206b73d0SCy Schubert attr->rta_len - rta_len); 1571206b73d0SCy Schubert } 1572206b73d0SCy Schubert attr = RTA_NEXT(attr, attrlen); 1573206b73d0SCy Schubert } 1574206b73d0SCy Schubert } 1575206b73d0SCy Schubert 1576206b73d0SCy Schubert 1577206b73d0SCy Schubert static int 1578206b73d0SCy Schubert atheros_get_we_version(struct atheros_driver_data *drv) 1579206b73d0SCy Schubert { 1580206b73d0SCy Schubert struct iw_range *range; 1581206b73d0SCy Schubert struct iwreq iwr; 1582206b73d0SCy Schubert int minlen; 1583206b73d0SCy Schubert size_t buflen; 1584206b73d0SCy Schubert 1585206b73d0SCy Schubert drv->we_version = 0; 1586206b73d0SCy Schubert 1587206b73d0SCy Schubert /* 1588206b73d0SCy Schubert * Use larger buffer than struct iw_range in order to allow the 1589206b73d0SCy Schubert * structure to grow in the future. 1590206b73d0SCy Schubert */ 1591206b73d0SCy Schubert buflen = sizeof(struct iw_range) + 500; 1592206b73d0SCy Schubert range = os_zalloc(buflen); 1593206b73d0SCy Schubert if (range == NULL) 1594206b73d0SCy Schubert return -1; 1595206b73d0SCy Schubert 1596206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 1597206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1598206b73d0SCy Schubert iwr.u.data.pointer = (caddr_t) range; 1599206b73d0SCy Schubert iwr.u.data.length = buflen; 1600206b73d0SCy Schubert 1601206b73d0SCy Schubert minlen = ((char *) &range->enc_capa) - (char *) range + 1602206b73d0SCy Schubert sizeof(range->enc_capa); 1603206b73d0SCy Schubert 1604206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { 1605206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", 1606206b73d0SCy Schubert strerror(errno)); 1607206b73d0SCy Schubert os_free(range); 1608206b73d0SCy Schubert return -1; 1609206b73d0SCy Schubert } else if (iwr.u.data.length >= minlen && 1610206b73d0SCy Schubert range->we_version_compiled >= 18) { 1611206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " 1612206b73d0SCy Schubert "WE(source)=%d enc_capa=0x%x", 1613206b73d0SCy Schubert range->we_version_compiled, 1614206b73d0SCy Schubert range->we_version_source, 1615206b73d0SCy Schubert range->enc_capa); 1616206b73d0SCy Schubert drv->we_version = range->we_version_compiled; 1617206b73d0SCy Schubert } 1618206b73d0SCy Schubert 1619206b73d0SCy Schubert os_free(range); 1620206b73d0SCy Schubert return 0; 1621206b73d0SCy Schubert } 1622206b73d0SCy Schubert 1623206b73d0SCy Schubert 1624206b73d0SCy Schubert static int 1625206b73d0SCy Schubert atheros_wireless_event_init(struct atheros_driver_data *drv) 1626206b73d0SCy Schubert { 1627206b73d0SCy Schubert struct netlink_config *cfg; 1628206b73d0SCy Schubert 1629206b73d0SCy Schubert atheros_get_we_version(drv); 1630206b73d0SCy Schubert 1631206b73d0SCy Schubert cfg = os_zalloc(sizeof(*cfg)); 1632206b73d0SCy Schubert if (cfg == NULL) 1633206b73d0SCy Schubert return -1; 1634206b73d0SCy Schubert cfg->ctx = drv; 1635206b73d0SCy Schubert cfg->newlink_cb = atheros_wireless_event_rtm_newlink; 1636206b73d0SCy Schubert drv->netlink = netlink_init(cfg); 1637206b73d0SCy Schubert if (drv->netlink == NULL) { 1638206b73d0SCy Schubert os_free(cfg); 1639206b73d0SCy Schubert return -1; 1640206b73d0SCy Schubert } 1641206b73d0SCy Schubert 1642206b73d0SCy Schubert return 0; 1643206b73d0SCy Schubert } 1644206b73d0SCy Schubert 1645206b73d0SCy Schubert 1646206b73d0SCy Schubert static int 1647206b73d0SCy Schubert atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, 1648206b73d0SCy Schubert int encrypt, const u8 *own_addr, u32 flags) 1649206b73d0SCy Schubert { 1650206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1651206b73d0SCy Schubert unsigned char buf[3000]; 1652206b73d0SCy Schubert unsigned char *bp = buf; 1653206b73d0SCy Schubert struct l2_ethhdr *eth; 1654206b73d0SCy Schubert size_t len; 1655206b73d0SCy Schubert int status; 1656206b73d0SCy Schubert 1657206b73d0SCy Schubert /* 1658206b73d0SCy Schubert * Prepend the Ethernet header. If the caller left us 1659206b73d0SCy Schubert * space at the front we could just insert it but since 1660206b73d0SCy Schubert * we don't know we copy to a local buffer. Given the frequency 1661206b73d0SCy Schubert * and size of frames this probably doesn't matter. 1662206b73d0SCy Schubert */ 1663206b73d0SCy Schubert len = data_len + sizeof(struct l2_ethhdr); 1664206b73d0SCy Schubert if (len > sizeof(buf)) { 1665206b73d0SCy Schubert bp = os_malloc(len); 1666206b73d0SCy Schubert if (bp == NULL) { 1667206b73d0SCy Schubert wpa_printf(MSG_INFO, 1668206b73d0SCy Schubert "EAPOL frame discarded, cannot malloc temp buffer of size %lu!", 1669206b73d0SCy Schubert (unsigned long) len); 1670206b73d0SCy Schubert return -1; 1671206b73d0SCy Schubert } 1672206b73d0SCy Schubert } 1673206b73d0SCy Schubert eth = (struct l2_ethhdr *) bp; 1674206b73d0SCy Schubert os_memcpy(eth->h_dest, addr, ETH_ALEN); 1675206b73d0SCy Schubert os_memcpy(eth->h_source, own_addr, ETH_ALEN); 1676206b73d0SCy Schubert eth->h_proto = host_to_be16(ETH_P_EAPOL); 1677206b73d0SCy Schubert os_memcpy(eth + 1, data, data_len); 1678206b73d0SCy Schubert 1679206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); 1680206b73d0SCy Schubert 1681206b73d0SCy Schubert status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); 1682206b73d0SCy Schubert 1683206b73d0SCy Schubert if (bp != buf) 1684206b73d0SCy Schubert os_free(bp); 1685206b73d0SCy Schubert return status; 1686206b73d0SCy Schubert } 1687206b73d0SCy Schubert 1688206b73d0SCy Schubert static void 1689206b73d0SCy Schubert handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 1690206b73d0SCy Schubert { 1691206b73d0SCy Schubert struct atheros_driver_data *drv = ctx; 1692206b73d0SCy Schubert drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), 1693206b73d0SCy Schubert len - sizeof(struct l2_ethhdr)); 1694206b73d0SCy Schubert } 1695206b73d0SCy Schubert 1696206b73d0SCy Schubert 1697206b73d0SCy Schubert static void atheros_read_fils_cap(struct atheros_driver_data *drv) 1698206b73d0SCy Schubert { 1699206b73d0SCy Schubert int fils = 0; 1700206b73d0SCy Schubert 1701206b73d0SCy Schubert #ifdef CONFIG_FILS 1702206b73d0SCy Schubert /* TODO: Would be better to have #ifdef on the IEEE80211_PARAM_* value 1703206b73d0SCy Schubert * to automatically check this against the driver header files. */ 1704206b73d0SCy Schubert if (get80211param(drv, IEEE80211_PARAM_ENABLE_FILS, &fils) < 0) { 1705206b73d0SCy Schubert wpa_printf(MSG_DEBUG, 1706206b73d0SCy Schubert "%s: Failed to get FILS capability from driver", 1707206b73d0SCy Schubert __func__); 1708206b73d0SCy Schubert /* Assume driver does not support FILS */ 1709206b73d0SCy Schubert fils = 0; 1710206b73d0SCy Schubert } 1711206b73d0SCy Schubert #endif /* CONFIG_FILS */ 1712206b73d0SCy Schubert drv->fils_en = fils; 1713206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: fils_en=%d", drv->fils_en); 1714206b73d0SCy Schubert } 1715206b73d0SCy Schubert 1716206b73d0SCy Schubert 1717206b73d0SCy Schubert static void * 1718206b73d0SCy Schubert atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) 1719206b73d0SCy Schubert { 1720206b73d0SCy Schubert struct atheros_driver_data *drv; 1721206b73d0SCy Schubert struct ifreq ifr; 1722206b73d0SCy Schubert struct iwreq iwr; 1723206b73d0SCy Schubert char brname[IFNAMSIZ]; 1724206b73d0SCy Schubert 1725206b73d0SCy Schubert drv = os_zalloc(sizeof(struct atheros_driver_data)); 1726206b73d0SCy Schubert if (drv == NULL) { 1727206b73d0SCy Schubert wpa_printf(MSG_INFO, 1728206b73d0SCy Schubert "Could not allocate memory for atheros driver data"); 1729206b73d0SCy Schubert return NULL; 1730206b73d0SCy Schubert } 1731206b73d0SCy Schubert 1732206b73d0SCy Schubert drv->hapd = hapd; 1733206b73d0SCy Schubert drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); 1734206b73d0SCy Schubert if (drv->ioctl_sock < 0) { 1735206b73d0SCy Schubert wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", 1736206b73d0SCy Schubert strerror(errno)); 1737206b73d0SCy Schubert goto bad; 1738206b73d0SCy Schubert } 1739206b73d0SCy Schubert os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); 1740206b73d0SCy Schubert 1741206b73d0SCy Schubert os_memset(&ifr, 0, sizeof(ifr)); 1742206b73d0SCy Schubert os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); 1743206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { 1744206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", 1745206b73d0SCy Schubert strerror(errno)); 1746206b73d0SCy Schubert goto bad; 1747206b73d0SCy Schubert } 1748206b73d0SCy Schubert drv->ifindex = ifr.ifr_ifindex; 1749206b73d0SCy Schubert 1750206b73d0SCy Schubert drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, 1751206b73d0SCy Schubert handle_read, drv, 1); 1752206b73d0SCy Schubert if (drv->sock_xmit == NULL) 1753206b73d0SCy Schubert goto bad; 1754206b73d0SCy Schubert if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) 1755206b73d0SCy Schubert goto bad; 1756206b73d0SCy Schubert os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN); 1757206b73d0SCy Schubert if (params->bridge[0]) { 1758206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", 1759206b73d0SCy Schubert params->bridge[0]); 1760206b73d0SCy Schubert drv->sock_recv = l2_packet_init(params->bridge[0], NULL, 1761206b73d0SCy Schubert ETH_P_EAPOL, handle_read, drv, 1762206b73d0SCy Schubert 1); 1763206b73d0SCy Schubert if (drv->sock_recv == NULL) 1764206b73d0SCy Schubert goto bad; 1765206b73d0SCy Schubert } else if (linux_br_get(brname, drv->iface) == 0) { 1766206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " 1767206b73d0SCy Schubert "EAPOL receive", brname); 1768206b73d0SCy Schubert drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, 1769206b73d0SCy Schubert handle_read, drv, 1); 1770206b73d0SCy Schubert if (drv->sock_recv == NULL) 1771206b73d0SCy Schubert goto bad; 1772206b73d0SCy Schubert } else 1773206b73d0SCy Schubert drv->sock_recv = drv->sock_xmit; 1774206b73d0SCy Schubert 1775206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 1776206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1777206b73d0SCy Schubert 1778206b73d0SCy Schubert iwr.u.mode = IW_MODE_MASTER; 1779206b73d0SCy Schubert 1780206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { 1781206b73d0SCy Schubert wpa_printf(MSG_ERROR, 1782206b73d0SCy Schubert "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s", 1783206b73d0SCy Schubert strerror(errno)); 1784206b73d0SCy Schubert goto bad; 1785206b73d0SCy Schubert } 1786206b73d0SCy Schubert 1787206b73d0SCy Schubert /* mark down during setup */ 1788206b73d0SCy Schubert linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); 1789206b73d0SCy Schubert atheros_set_privacy(drv, 0); /* default to no privacy */ 1790206b73d0SCy Schubert 1791206b73d0SCy Schubert if (atheros_receive_pkt(drv)) 1792206b73d0SCy Schubert goto bad; 1793206b73d0SCy Schubert 1794206b73d0SCy Schubert if (atheros_wireless_event_init(drv)) 1795206b73d0SCy Schubert goto bad; 1796206b73d0SCy Schubert 1797206b73d0SCy Schubert /* Read FILS capability from the driver */ 1798206b73d0SCy Schubert atheros_read_fils_cap(drv); 1799206b73d0SCy Schubert 1800206b73d0SCy Schubert return drv; 1801206b73d0SCy Schubert bad: 1802206b73d0SCy Schubert atheros_reset_appfilter(drv); 1803206b73d0SCy Schubert if (drv->sock_raw) 1804206b73d0SCy Schubert l2_packet_deinit(drv->sock_raw); 1805206b73d0SCy Schubert if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) 1806206b73d0SCy Schubert l2_packet_deinit(drv->sock_recv); 1807206b73d0SCy Schubert if (drv->sock_xmit != NULL) 1808206b73d0SCy Schubert l2_packet_deinit(drv->sock_xmit); 1809206b73d0SCy Schubert if (drv->ioctl_sock >= 0) 1810206b73d0SCy Schubert close(drv->ioctl_sock); 1811206b73d0SCy Schubert os_free(drv); 1812206b73d0SCy Schubert return NULL; 1813206b73d0SCy Schubert } 1814206b73d0SCy Schubert 1815206b73d0SCy Schubert 1816206b73d0SCy Schubert static void 1817206b73d0SCy Schubert atheros_deinit(void *priv) 1818206b73d0SCy Schubert { 1819206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1820206b73d0SCy Schubert 1821206b73d0SCy Schubert atheros_reset_appfilter(drv); 1822206b73d0SCy Schubert 1823206b73d0SCy Schubert if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) { 1824206b73d0SCy Schubert atheros_set_opt_ie(priv, NULL, 0); 1825206b73d0SCy Schubert wpabuf_free(drv->wpa_ie); 1826206b73d0SCy Schubert wpabuf_free(drv->wps_beacon_ie); 1827206b73d0SCy Schubert wpabuf_free(drv->wps_probe_resp_ie); 1828206b73d0SCy Schubert } 1829206b73d0SCy Schubert netlink_deinit(drv->netlink); 1830206b73d0SCy Schubert (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); 1831206b73d0SCy Schubert if (drv->ioctl_sock >= 0) 1832206b73d0SCy Schubert close(drv->ioctl_sock); 1833206b73d0SCy Schubert if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) 1834206b73d0SCy Schubert l2_packet_deinit(drv->sock_recv); 1835206b73d0SCy Schubert if (drv->sock_xmit != NULL) 1836206b73d0SCy Schubert l2_packet_deinit(drv->sock_xmit); 1837206b73d0SCy Schubert if (drv->sock_raw) 1838206b73d0SCy Schubert l2_packet_deinit(drv->sock_raw); 1839206b73d0SCy Schubert os_free(drv); 1840206b73d0SCy Schubert } 1841206b73d0SCy Schubert 1842206b73d0SCy Schubert static int 1843206b73d0SCy Schubert atheros_set_ssid(void *priv, const u8 *buf, int len) 1844206b73d0SCy Schubert { 1845206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1846206b73d0SCy Schubert struct iwreq iwr; 1847206b73d0SCy Schubert 1848206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 1849206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1850206b73d0SCy Schubert iwr.u.essid.flags = 1; /* SSID active */ 1851206b73d0SCy Schubert iwr.u.essid.pointer = (caddr_t) buf; 1852206b73d0SCy Schubert iwr.u.essid.length = len; 1853206b73d0SCy Schubert 1854206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { 1855206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s", 1856206b73d0SCy Schubert len, strerror(errno)); 1857206b73d0SCy Schubert return -1; 1858206b73d0SCy Schubert } 1859206b73d0SCy Schubert return 0; 1860206b73d0SCy Schubert } 1861206b73d0SCy Schubert 1862206b73d0SCy Schubert static int 1863206b73d0SCy Schubert atheros_get_ssid(void *priv, u8 *buf, int len) 1864206b73d0SCy Schubert { 1865206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1866206b73d0SCy Schubert struct iwreq iwr; 1867206b73d0SCy Schubert int ret = 0; 1868206b73d0SCy Schubert 1869206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 1870206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1871206b73d0SCy Schubert iwr.u.essid.pointer = (caddr_t) buf; 1872206b73d0SCy Schubert iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? 1873206b73d0SCy Schubert IW_ESSID_MAX_SIZE : len; 1874206b73d0SCy Schubert 1875206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { 1876206b73d0SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", 1877206b73d0SCy Schubert strerror(errno)); 1878206b73d0SCy Schubert ret = -1; 1879206b73d0SCy Schubert } else 1880206b73d0SCy Schubert ret = iwr.u.essid.length; 1881206b73d0SCy Schubert 1882206b73d0SCy Schubert return ret; 1883206b73d0SCy Schubert } 1884206b73d0SCy Schubert 1885206b73d0SCy Schubert static int 1886206b73d0SCy Schubert atheros_set_countermeasures(void *priv, int enabled) 1887206b73d0SCy Schubert { 1888206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1889206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 1890206b73d0SCy Schubert return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); 1891206b73d0SCy Schubert } 1892206b73d0SCy Schubert 1893206b73d0SCy Schubert static int 1894206b73d0SCy Schubert atheros_commit(void *priv) 1895206b73d0SCy Schubert { 1896206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1897206b73d0SCy Schubert return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); 1898206b73d0SCy Schubert } 1899206b73d0SCy Schubert 1900206b73d0SCy Schubert static int atheros_set_authmode(void *priv, int auth_algs) 1901206b73d0SCy Schubert { 1902206b73d0SCy Schubert int authmode; 1903206b73d0SCy Schubert 1904206b73d0SCy Schubert if ((auth_algs & WPA_AUTH_ALG_OPEN) && 1905206b73d0SCy Schubert (auth_algs & WPA_AUTH_ALG_SHARED)) 1906206b73d0SCy Schubert authmode = IEEE80211_AUTH_AUTO; 1907206b73d0SCy Schubert else if (auth_algs & WPA_AUTH_ALG_OPEN) 1908206b73d0SCy Schubert authmode = IEEE80211_AUTH_OPEN; 1909206b73d0SCy Schubert else if (auth_algs & WPA_AUTH_ALG_SHARED) 1910206b73d0SCy Schubert authmode = IEEE80211_AUTH_SHARED; 1911206b73d0SCy Schubert else 1912206b73d0SCy Schubert return -1; 1913206b73d0SCy Schubert 1914206b73d0SCy Schubert return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode); 1915206b73d0SCy Schubert } 1916206b73d0SCy Schubert 1917206b73d0SCy Schubert static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) 1918206b73d0SCy Schubert { 1919206b73d0SCy Schubert /* 1920206b73d0SCy Schubert * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x, 1921206b73d0SCy Schubert * set_generic_elem, and hapd_set_ssid. 1922206b73d0SCy Schubert */ 1923206b73d0SCy Schubert 1924206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x " 1925206b73d0SCy Schubert "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x " 1926206b73d0SCy Schubert "wpa_version=0x%x privacy=%d interworking=%d", 1927206b73d0SCy Schubert params->pairwise_ciphers, params->group_cipher, 1928206b73d0SCy Schubert params->key_mgmt_suites, params->auth_algs, 1929206b73d0SCy Schubert params->wpa_version, params->privacy, params->interworking); 1930206b73d0SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID", 1931206b73d0SCy Schubert params->ssid, params->ssid_len); 1932206b73d0SCy Schubert if (params->hessid) 1933206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR, 1934206b73d0SCy Schubert MAC2STR(params->hessid)); 1935206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies", 1936206b73d0SCy Schubert params->beacon_ies); 1937206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies", 1938206b73d0SCy Schubert params->proberesp_ies); 1939206b73d0SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", 1940206b73d0SCy Schubert params->assocresp_ies); 1941206b73d0SCy Schubert 1942206b73d0SCy Schubert #if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN)) 1943206b73d0SCy Schubert if (params->osen) { 1944206b73d0SCy Schubert struct wpa_bss_params bss_params; 1945206b73d0SCy Schubert 1946206b73d0SCy Schubert os_memset(&bss_params, 0, sizeof(struct wpa_bss_params)); 1947206b73d0SCy Schubert bss_params.enabled = 1; 1948206b73d0SCy Schubert bss_params.wpa = 2; 1949206b73d0SCy Schubert bss_params.wpa_pairwise = WPA_CIPHER_CCMP; 1950206b73d0SCy Schubert bss_params.wpa_group = WPA_CIPHER_CCMP; 1951206b73d0SCy Schubert bss_params.ieee802_1x = 1; 1952206b73d0SCy Schubert 1953206b73d0SCy Schubert if (atheros_set_privacy(priv, 1) || 1954206b73d0SCy Schubert set80211param(priv, IEEE80211_PARAM_OSEN, 1)) 1955206b73d0SCy Schubert return -1; 1956206b73d0SCy Schubert 1957206b73d0SCy Schubert return atheros_set_ieee8021x(priv, &bss_params); 1958206b73d0SCy Schubert } 1959206b73d0SCy Schubert #endif /* CONFIG_HS20 && IEEE80211_PARAM_OSEN */ 1960206b73d0SCy Schubert 1961206b73d0SCy Schubert return 0; 1962206b73d0SCy Schubert } 1963206b73d0SCy Schubert 1964206b73d0SCy Schubert 1965206b73d0SCy Schubert static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, 1966206b73d0SCy Schubert int noack, unsigned int freq, 1967*c1d255d3SCy Schubert const u16 *csa_offs, size_t csa_offs_len, 1968*c1d255d3SCy Schubert int no_encrypt, unsigned int wait) 1969206b73d0SCy Schubert { 1970206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1971206b73d0SCy Schubert u8 buf[1510]; 1972206b73d0SCy Schubert const struct ieee80211_mgmt *mgmt; 1973206b73d0SCy Schubert struct ieee80211req_mgmtbuf *mgmt_frm; 1974206b73d0SCy Schubert 1975206b73d0SCy Schubert mgmt = (const struct ieee80211_mgmt *) frm; 1976206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__, 1977206b73d0SCy Schubert (unsigned long) data_len, MAC2STR(mgmt->da)); 1978206b73d0SCy Schubert mgmt_frm = (struct ieee80211req_mgmtbuf *) buf; 1979206b73d0SCy Schubert os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); 1980206b73d0SCy Schubert mgmt_frm->buflen = data_len; 1981206b73d0SCy Schubert if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) { 1982206b73d0SCy Schubert wpa_printf(MSG_INFO, "atheros: Too long frame for " 1983206b73d0SCy Schubert "atheros_send_mgmt (%u)", (unsigned int) data_len); 1984206b73d0SCy Schubert return -1; 1985206b73d0SCy Schubert } 1986206b73d0SCy Schubert os_memcpy(&mgmt_frm->buf[0], frm, data_len); 1987206b73d0SCy Schubert return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm, 1988206b73d0SCy Schubert sizeof(struct ieee80211req_mgmtbuf) + data_len); 1989206b73d0SCy Schubert } 1990206b73d0SCy Schubert 1991206b73d0SCy Schubert 1992206b73d0SCy Schubert #ifdef CONFIG_IEEE80211R 1993206b73d0SCy Schubert 1994206b73d0SCy Schubert static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie, 1995206b73d0SCy Schubert size_t tspec_ielen) 1996206b73d0SCy Schubert { 1997206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 1998206b73d0SCy Schubert int retv; 1999206b73d0SCy Schubert struct ieee80211req_res req; 2000206b73d0SCy Schubert struct ieee80211req_res_addts *addts = &req.u.addts; 2001206b73d0SCy Schubert 2002206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__); 2003206b73d0SCy Schubert req.type = IEEE80211_RESREQ_ADDTS; 2004206b73d0SCy Schubert os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); 2005206b73d0SCy Schubert os_memcpy(addts->tspecie, tspec_ie, tspec_ielen); 2006206b73d0SCy Schubert retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, 2007206b73d0SCy Schubert sizeof(struct ieee80211req_res)); 2008206b73d0SCy Schubert if (retv < 0) { 2009206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED " 2010206b73d0SCy Schubert "retv = %d", __func__, retv); 2011206b73d0SCy Schubert return -1; 2012206b73d0SCy Schubert } 2013206b73d0SCy Schubert os_memcpy(tspec_ie, addts->tspecie, tspec_ielen); 2014206b73d0SCy Schubert return addts->status; 2015206b73d0SCy Schubert } 2016206b73d0SCy Schubert 2017206b73d0SCy Schubert 2018206b73d0SCy Schubert static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg) 2019206b73d0SCy Schubert { 2020206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 2021206b73d0SCy Schubert struct ieee80211req_res req; 2022206b73d0SCy Schubert struct ieee80211req_res_addnode *addnode = &req.u.addnode; 2023206b73d0SCy Schubert 2024206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s", __func__); 2025206b73d0SCy Schubert req.type = IEEE80211_RESREQ_ADDNODE; 2026206b73d0SCy Schubert os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); 2027206b73d0SCy Schubert addnode->auth_alg = auth_alg; 2028206b73d0SCy Schubert return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, 2029206b73d0SCy Schubert sizeof(struct ieee80211req_res)); 2030206b73d0SCy Schubert } 2031206b73d0SCy Schubert 2032206b73d0SCy Schubert #endif /* CONFIG_IEEE80211R */ 2033206b73d0SCy Schubert 2034206b73d0SCy Schubert 2035206b73d0SCy Schubert /* Use only to set a big param, get will not work. */ 2036206b73d0SCy Schubert static int 2037206b73d0SCy Schubert set80211big(struct atheros_driver_data *drv, int op, const void *data, int len) 2038206b73d0SCy Schubert { 2039206b73d0SCy Schubert struct iwreq iwr; 2040206b73d0SCy Schubert 2041206b73d0SCy Schubert os_memset(&iwr, 0, sizeof(iwr)); 2042206b73d0SCy Schubert os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 2043206b73d0SCy Schubert 2044206b73d0SCy Schubert iwr.u.data.pointer = (void *) data; 2045206b73d0SCy Schubert iwr.u.data.length = len; 2046206b73d0SCy Schubert iwr.u.data.flags = op; 2047206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x", 2048206b73d0SCy Schubert __func__, op, op, athr_get_param_name(op), len); 2049206b73d0SCy Schubert 2050206b73d0SCy Schubert if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) { 2051206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d " 2052206b73d0SCy Schubert "value=0x%x,0x%x failed: %d (%s)", 2053206b73d0SCy Schubert __func__, op, athr_get_ioctl_name(op), iwr.u.mode, 2054206b73d0SCy Schubert iwr.u.mode, iwr.u.data.length, 2055206b73d0SCy Schubert iwr.u.data.flags, errno, strerror(errno)); 2056206b73d0SCy Schubert return -1; 2057206b73d0SCy Schubert } 2058206b73d0SCy Schubert return 0; 2059206b73d0SCy Schubert } 2060206b73d0SCy Schubert 2061206b73d0SCy Schubert 2062206b73d0SCy Schubert static int atheros_send_action(void *priv, unsigned int freq, 2063206b73d0SCy Schubert unsigned int wait, 2064206b73d0SCy Schubert const u8 *dst, const u8 *src, 2065206b73d0SCy Schubert const u8 *bssid, 2066206b73d0SCy Schubert const u8 *data, size_t data_len, int no_cck) 2067206b73d0SCy Schubert { 2068206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 2069206b73d0SCy Schubert struct ieee80211_p2p_send_action *act; 2070206b73d0SCy Schubert int res; 2071206b73d0SCy Schubert 2072206b73d0SCy Schubert act = os_zalloc(sizeof(*act) + data_len); 2073206b73d0SCy Schubert if (act == NULL) 2074206b73d0SCy Schubert return -1; 2075206b73d0SCy Schubert act->freq = freq; 2076206b73d0SCy Schubert os_memcpy(act->dst_addr, dst, ETH_ALEN); 2077206b73d0SCy Schubert os_memcpy(act->src_addr, src, ETH_ALEN); 2078206b73d0SCy Schubert os_memcpy(act->bssid, bssid, ETH_ALEN); 2079206b73d0SCy Schubert os_memcpy(act + 1, data, data_len); 2080206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src=" 2081206b73d0SCy Schubert MACSTR ", bssid=" MACSTR, 2082206b73d0SCy Schubert __func__, act->freq, wait, MAC2STR(act->dst_addr), 2083206b73d0SCy Schubert MAC2STR(act->src_addr), MAC2STR(act->bssid)); 2084206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act)); 2085206b73d0SCy Schubert wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len); 2086206b73d0SCy Schubert 2087206b73d0SCy Schubert res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION, 2088206b73d0SCy Schubert act, sizeof(*act) + data_len); 2089206b73d0SCy Schubert os_free(act); 2090206b73d0SCy Schubert return res; 2091206b73d0SCy Schubert } 2092206b73d0SCy Schubert 2093206b73d0SCy Schubert 2094206b73d0SCy Schubert #if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) 2095206b73d0SCy Schubert static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer, 2096206b73d0SCy Schubert u8 *ie, u16 *len, enum wnm_oper oper) 2097206b73d0SCy Schubert { 2098206b73d0SCy Schubert #define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */ 2099206b73d0SCy Schubert u8 buf[IEEE80211_APPIE_MAX]; 2100206b73d0SCy Schubert struct ieee80211req_getset_appiebuf *tfs_ie; 2101206b73d0SCy Schubert u16 val; 2102206b73d0SCy Schubert 2103206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR, 2104206b73d0SCy Schubert drv->iface, oper, MAC2STR(peer)); 2105206b73d0SCy Schubert 2106206b73d0SCy Schubert switch (oper) { 2107206b73d0SCy Schubert case WNM_SLEEP_TFS_REQ_IE_SET: 2108206b73d0SCy Schubert if (*len > IEEE80211_APPIE_MAX - 2109206b73d0SCy Schubert sizeof(struct ieee80211req_getset_appiebuf)) { 2110206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large"); 2111206b73d0SCy Schubert return -1; 2112206b73d0SCy Schubert } 2113206b73d0SCy Schubert tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2114206b73d0SCy Schubert tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2115206b73d0SCy Schubert tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len; 2116206b73d0SCy Schubert 2117206b73d0SCy Schubert /* Command header for driver */ 2118206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2119206b73d0SCy Schubert val = oper; 2120206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2121206b73d0SCy Schubert val = *len; 2122206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2123206b73d0SCy Schubert 2124206b73d0SCy Schubert /* copy the ie */ 2125206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len); 2126206b73d0SCy Schubert 2127206b73d0SCy Schubert if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, 2128206b73d0SCy Schubert IEEE80211_APPIE_MAX)) { 2129206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " 2130206b73d0SCy Schubert "%s", __func__, strerror(errno)); 2131206b73d0SCy Schubert return -1; 2132206b73d0SCy Schubert } 2133206b73d0SCy Schubert break; 2134206b73d0SCy Schubert case WNM_SLEEP_TFS_RESP_IE_ADD: 2135206b73d0SCy Schubert tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2136206b73d0SCy Schubert tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2137206b73d0SCy Schubert tfs_ie->app_buflen = IEEE80211_APPIE_MAX - 2138206b73d0SCy Schubert sizeof(struct ieee80211req_getset_appiebuf); 2139206b73d0SCy Schubert /* Command header for driver */ 2140206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2141206b73d0SCy Schubert val = oper; 2142206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2143206b73d0SCy Schubert val = 0; 2144206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2145206b73d0SCy Schubert 2146206b73d0SCy Schubert if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie, 2147206b73d0SCy Schubert IEEE80211_APPIE_MAX)) { 2148206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: " 2149206b73d0SCy Schubert "%s", __func__, strerror(errno)); 2150206b73d0SCy Schubert return -1; 2151206b73d0SCy Schubert } 2152206b73d0SCy Schubert 2153206b73d0SCy Schubert *len = tfs_ie->app_buflen; 2154206b73d0SCy Schubert os_memcpy(ie, &(tfs_ie->app_buf[0]), *len); 2155206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0], 2156206b73d0SCy Schubert *len); 2157206b73d0SCy Schubert break; 2158206b73d0SCy Schubert case WNM_SLEEP_TFS_RESP_IE_NONE: 2159206b73d0SCy Schubert *len = 0; 2160206b73d0SCy Schubert break; 2161206b73d0SCy Schubert case WNM_SLEEP_TFS_IE_DEL: 2162206b73d0SCy Schubert tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2163206b73d0SCy Schubert tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2164206b73d0SCy Schubert tfs_ie->app_buflen = IEEE80211_APPIE_MAX - 2165206b73d0SCy Schubert sizeof(struct ieee80211req_getset_appiebuf); 2166206b73d0SCy Schubert /* Command header for driver */ 2167206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2168206b73d0SCy Schubert val = oper; 2169206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2170206b73d0SCy Schubert val = 0; 2171206b73d0SCy Schubert os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2172206b73d0SCy Schubert 2173206b73d0SCy Schubert if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, 2174206b73d0SCy Schubert IEEE80211_APPIE_MAX)) { 2175206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " 2176206b73d0SCy Schubert "%s", __func__, strerror(errno)); 2177206b73d0SCy Schubert return -1; 2178206b73d0SCy Schubert } 2179206b73d0SCy Schubert break; 2180206b73d0SCy Schubert default: 2181206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper); 2182206b73d0SCy Schubert break; 2183206b73d0SCy Schubert } 2184206b73d0SCy Schubert 2185206b73d0SCy Schubert return 0; 2186206b73d0SCy Schubert } 2187206b73d0SCy Schubert 2188206b73d0SCy Schubert 2189206b73d0SCy Schubert static int atheros_wnm_sleep(struct atheros_driver_data *drv, 2190206b73d0SCy Schubert const u8 *peer, enum wnm_oper oper) 2191206b73d0SCy Schubert { 2192206b73d0SCy Schubert u8 *data, *pos; 2193206b73d0SCy Schubert size_t dlen; 2194206b73d0SCy Schubert int ret; 2195206b73d0SCy Schubert u16 val; 2196206b73d0SCy Schubert 2197206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR, 2198206b73d0SCy Schubert oper, MAC2STR(peer)); 2199206b73d0SCy Schubert 2200206b73d0SCy Schubert dlen = ETH_ALEN + 2 + 2; 2201206b73d0SCy Schubert data = os_malloc(dlen); 2202206b73d0SCy Schubert if (data == NULL) 2203206b73d0SCy Schubert return -1; 2204206b73d0SCy Schubert 2205206b73d0SCy Schubert /* Command header for driver */ 2206206b73d0SCy Schubert pos = data; 2207206b73d0SCy Schubert os_memcpy(pos, peer, ETH_ALEN); 2208206b73d0SCy Schubert pos += ETH_ALEN; 2209206b73d0SCy Schubert 2210206b73d0SCy Schubert val = oper; 2211206b73d0SCy Schubert os_memcpy(pos, &val, 2); 2212206b73d0SCy Schubert pos += 2; 2213206b73d0SCy Schubert 2214206b73d0SCy Schubert val = 0; 2215206b73d0SCy Schubert os_memcpy(pos, &val, 2); 2216206b73d0SCy Schubert 2217206b73d0SCy Schubert ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM); 2218206b73d0SCy Schubert 2219206b73d0SCy Schubert os_free(data); 2220206b73d0SCy Schubert 2221206b73d0SCy Schubert return ret; 2222206b73d0SCy Schubert } 2223206b73d0SCy Schubert 2224206b73d0SCy Schubert 2225206b73d0SCy Schubert static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer, 2226206b73d0SCy Schubert u8 *buf, u16 *buf_len) 2227206b73d0SCy Schubert { 2228206b73d0SCy Schubert struct atheros_driver_data *drv = priv; 2229206b73d0SCy Schubert 2230206b73d0SCy Schubert switch (oper) { 2231206b73d0SCy Schubert case WNM_SLEEP_ENTER_CONFIRM: 2232206b73d0SCy Schubert case WNM_SLEEP_ENTER_FAIL: 2233206b73d0SCy Schubert case WNM_SLEEP_EXIT_CONFIRM: 2234206b73d0SCy Schubert case WNM_SLEEP_EXIT_FAIL: 2235206b73d0SCy Schubert return atheros_wnm_sleep(drv, peer, oper); 2236206b73d0SCy Schubert case WNM_SLEEP_TFS_REQ_IE_SET: 2237206b73d0SCy Schubert case WNM_SLEEP_TFS_RESP_IE_ADD: 2238206b73d0SCy Schubert case WNM_SLEEP_TFS_RESP_IE_NONE: 2239206b73d0SCy Schubert case WNM_SLEEP_TFS_IE_DEL: 2240206b73d0SCy Schubert return athr_wnm_tfs(drv, peer, buf, buf_len, oper); 2241206b73d0SCy Schubert default: 2242206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d", 2243206b73d0SCy Schubert oper); 2244206b73d0SCy Schubert return -1; 2245206b73d0SCy Schubert } 2246206b73d0SCy Schubert } 2247206b73d0SCy Schubert #endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ 2248206b73d0SCy Schubert 2249206b73d0SCy Schubert 2250206b73d0SCy Schubert const struct wpa_driver_ops wpa_driver_atheros_ops = { 2251206b73d0SCy Schubert .name = "atheros", 2252206b73d0SCy Schubert .hapd_init = atheros_init, 2253206b73d0SCy Schubert .hapd_deinit = atheros_deinit, 2254206b73d0SCy Schubert .set_ieee8021x = atheros_set_ieee8021x, 2255206b73d0SCy Schubert .set_privacy = atheros_set_privacy, 2256206b73d0SCy Schubert .set_key = atheros_set_key, 2257206b73d0SCy Schubert .get_seqnum = atheros_get_seqnum, 2258206b73d0SCy Schubert .flush = atheros_flush, 2259206b73d0SCy Schubert .set_generic_elem = atheros_set_opt_ie, 2260206b73d0SCy Schubert .sta_set_flags = atheros_sta_set_flags, 2261206b73d0SCy Schubert .read_sta_data = atheros_read_sta_driver_data, 2262206b73d0SCy Schubert .hapd_send_eapol = atheros_send_eapol, 2263206b73d0SCy Schubert .sta_disassoc = atheros_sta_disassoc, 2264206b73d0SCy Schubert .sta_deauth = atheros_sta_deauth, 2265206b73d0SCy Schubert .hapd_set_ssid = atheros_set_ssid, 2266206b73d0SCy Schubert .hapd_get_ssid = atheros_get_ssid, 2267206b73d0SCy Schubert .set_countermeasures = atheros_set_countermeasures, 2268206b73d0SCy Schubert .sta_clear_stats = atheros_sta_clear_stats, 2269206b73d0SCy Schubert .commit = atheros_commit, 2270206b73d0SCy Schubert .set_ap_wps_ie = atheros_set_ap_wps_ie, 2271206b73d0SCy Schubert .set_authmode = atheros_set_authmode, 2272206b73d0SCy Schubert .set_ap = atheros_set_ap, 2273206b73d0SCy Schubert .sta_assoc = atheros_sta_assoc, 2274206b73d0SCy Schubert .sta_auth = atheros_sta_auth, 2275206b73d0SCy Schubert .send_mlme = atheros_send_mgmt, 2276206b73d0SCy Schubert #ifdef CONFIG_IEEE80211R 2277206b73d0SCy Schubert .add_tspec = atheros_add_tspec, 2278206b73d0SCy Schubert .add_sta_node = atheros_add_sta_node, 2279206b73d0SCy Schubert #endif /* CONFIG_IEEE80211R */ 2280206b73d0SCy Schubert .send_action = atheros_send_action, 2281206b73d0SCy Schubert #if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) 2282206b73d0SCy Schubert .wnm_oper = atheros_wnm_oper, 2283206b73d0SCy Schubert #endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ 2284206b73d0SCy Schubert .set_qos_map = atheros_set_qos_map, 2285206b73d0SCy Schubert }; 2286