1214501Srpaulo/* 2214501Srpaulo * hostapd / Driver interaction with Atheros driver 3214501Srpaulo * Copyright (c) 2004, Sam Leffler <sam@errno.com> 4214501Srpaulo * Copyright (c) 2004, Video54 Technologies 5214501Srpaulo * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> 6214501Srpaulo * Copyright (c) 2009, Atheros Communications 7214501Srpaulo * 8252190Srpaulo * This software may be distributed under the terms of the BSD license. 9252190Srpaulo * See README for more details. 10214501Srpaulo */ 11214501Srpaulo 12214501Srpaulo#include "includes.h" 13214501Srpaulo#include <net/if.h> 14214501Srpaulo#include <sys/ioctl.h> 15214501Srpaulo 16214501Srpaulo#include "common.h" 17252190Srpaulo#include "eloop.h" 18252190Srpaulo#include "common/ieee802_11_defs.h" 19252190Srpaulo#include "l2_packet/l2_packet.h" 20252190Srpaulo#include "p2p/p2p.h" 21252190Srpaulo 22252190Srpaulo#include "common.h" 23214501Srpaulo#ifndef _BYTE_ORDER 24214501Srpaulo#ifdef WORDS_BIGENDIAN 25214501Srpaulo#define _BYTE_ORDER _BIG_ENDIAN 26214501Srpaulo#else 27214501Srpaulo#define _BYTE_ORDER _LITTLE_ENDIAN 28214501Srpaulo#endif 29214501Srpaulo#endif /* _BYTE_ORDER */ 30214501Srpaulo 31214501Srpaulo/* 32214501Srpaulo * Note, the ATH_WPS_IE setting must match with the driver build.. If the 33214501Srpaulo * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail. 34214501Srpaulo */ 35214501Srpaulo#define ATH_WPS_IE 36214501Srpaulo 37252190Srpaulo#include "ieee80211_external.h" 38214501Srpaulo 39341618Scy/* Avoid conflicting definition from the driver header files with 40341618Scy * common/wpa_common.h */ 41341618Scy#undef WPA_OUI_TYPE 42214501Srpaulo 43341618Scy 44214501Srpaulo#ifdef CONFIG_WPS 45214501Srpaulo#include <netpacket/packet.h> 46252190Srpaulo#endif /* CONFIG_WPS */ 47214501Srpaulo 48214501Srpaulo#ifndef ETH_P_80211_RAW 49214501Srpaulo#define ETH_P_80211_RAW 0x0019 50214501Srpaulo#endif 51214501Srpaulo 52252190Srpaulo#include "linux_wext.h" 53214501Srpaulo 54214501Srpaulo#include "driver.h" 55214501Srpaulo#include "eloop.h" 56214501Srpaulo#include "priv_netlink.h" 57214501Srpaulo#include "l2_packet/l2_packet.h" 58214501Srpaulo#include "common/ieee802_11_defs.h" 59214501Srpaulo#include "netlink.h" 60214501Srpaulo#include "linux_ioctl.h" 61214501Srpaulo 62341618Scy#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS) 63289284Srpaulo#define ATHEROS_USE_RAW_RECEIVE 64289284Srpaulo#endif 65214501Srpaulo 66289284Srpaulo 67252190Srpaulostruct atheros_driver_data { 68214501Srpaulo struct hostapd_data *hapd; /* back pointer */ 69214501Srpaulo 70214501Srpaulo char iface[IFNAMSIZ + 1]; 71214501Srpaulo int ifindex; 72214501Srpaulo struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ 73214501Srpaulo struct l2_packet_data *sock_recv; /* raw packet recv socket */ 74214501Srpaulo int ioctl_sock; /* socket for ioctl() use */ 75214501Srpaulo struct netlink_data *netlink; 76214501Srpaulo int we_version; 77341618Scy int fils_en; /* FILS enable/disable in driver */ 78214501Srpaulo u8 acct_mac[ETH_ALEN]; 79214501Srpaulo struct hostap_sta_driver_data acct_data; 80214501Srpaulo 81214501Srpaulo struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ 82252190Srpaulo struct wpabuf *wpa_ie; 83252190Srpaulo struct wpabuf *wps_beacon_ie; 84252190Srpaulo struct wpabuf *wps_probe_resp_ie; 85252190Srpaulo u8 own_addr[ETH_ALEN]; 86214501Srpaulo}; 87214501Srpaulo 88252190Srpaulostatic int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 89351377Scy u16 reason_code); 90252190Srpaulostatic int atheros_set_privacy(void *priv, int enabled); 91214501Srpaulo 92214501Srpaulostatic const char * athr_get_ioctl_name(int op) 93214501Srpaulo{ 94214501Srpaulo switch (op) { 95214501Srpaulo case IEEE80211_IOCTL_SETPARAM: 96214501Srpaulo return "SETPARAM"; 97214501Srpaulo case IEEE80211_IOCTL_GETPARAM: 98214501Srpaulo return "GETPARAM"; 99214501Srpaulo case IEEE80211_IOCTL_SETKEY: 100214501Srpaulo return "SETKEY"; 101214501Srpaulo case IEEE80211_IOCTL_SETWMMPARAMS: 102214501Srpaulo return "SETWMMPARAMS"; 103214501Srpaulo case IEEE80211_IOCTL_DELKEY: 104214501Srpaulo return "DELKEY"; 105214501Srpaulo case IEEE80211_IOCTL_GETWMMPARAMS: 106214501Srpaulo return "GETWMMPARAMS"; 107214501Srpaulo case IEEE80211_IOCTL_SETMLME: 108214501Srpaulo return "SETMLME"; 109214501Srpaulo case IEEE80211_IOCTL_GETCHANINFO: 110214501Srpaulo return "GETCHANINFO"; 111214501Srpaulo case IEEE80211_IOCTL_SETOPTIE: 112214501Srpaulo return "SETOPTIE"; 113214501Srpaulo case IEEE80211_IOCTL_GETOPTIE: 114214501Srpaulo return "GETOPTIE"; 115214501Srpaulo case IEEE80211_IOCTL_ADDMAC: 116214501Srpaulo return "ADDMAC"; 117214501Srpaulo case IEEE80211_IOCTL_DELMAC: 118214501Srpaulo return "DELMAC"; 119214501Srpaulo case IEEE80211_IOCTL_GETCHANLIST: 120214501Srpaulo return "GETCHANLIST"; 121214501Srpaulo case IEEE80211_IOCTL_SETCHANLIST: 122214501Srpaulo return "SETCHANLIST"; 123214501Srpaulo case IEEE80211_IOCTL_KICKMAC: 124214501Srpaulo return "KICKMAC"; 125214501Srpaulo case IEEE80211_IOCTL_CHANSWITCH: 126214501Srpaulo return "CHANSWITCH"; 127214501Srpaulo case IEEE80211_IOCTL_GETMODE: 128214501Srpaulo return "GETMODE"; 129214501Srpaulo case IEEE80211_IOCTL_SETMODE: 130214501Srpaulo return "SETMODE"; 131214501Srpaulo case IEEE80211_IOCTL_GET_APPIEBUF: 132214501Srpaulo return "GET_APPIEBUF"; 133214501Srpaulo case IEEE80211_IOCTL_SET_APPIEBUF: 134214501Srpaulo return "SET_APPIEBUF"; 135214501Srpaulo case IEEE80211_IOCTL_SET_ACPARAMS: 136214501Srpaulo return "SET_ACPARAMS"; 137214501Srpaulo case IEEE80211_IOCTL_FILTERFRAME: 138214501Srpaulo return "FILTERFRAME"; 139214501Srpaulo case IEEE80211_IOCTL_SET_RTPARAMS: 140214501Srpaulo return "SET_RTPARAMS"; 141214501Srpaulo case IEEE80211_IOCTL_SET_MEDENYENTRY: 142214501Srpaulo return "SET_MEDENYENTRY"; 143214501Srpaulo case IEEE80211_IOCTL_GET_MACADDR: 144214501Srpaulo return "GET_MACADDR"; 145214501Srpaulo case IEEE80211_IOCTL_SET_HBRPARAMS: 146214501Srpaulo return "SET_HBRPARAMS"; 147214501Srpaulo case IEEE80211_IOCTL_SET_RXTIMEOUT: 148214501Srpaulo return "SET_RXTIMEOUT"; 149214501Srpaulo case IEEE80211_IOCTL_STA_STATS: 150214501Srpaulo return "STA_STATS"; 151214501Srpaulo case IEEE80211_IOCTL_GETWPAIE: 152214501Srpaulo return "GETWPAIE"; 153214501Srpaulo default: 154214501Srpaulo return "??"; 155214501Srpaulo } 156214501Srpaulo} 157214501Srpaulo 158214501Srpaulo 159214501Srpaulostatic const char * athr_get_param_name(int op) 160214501Srpaulo{ 161214501Srpaulo switch (op) { 162214501Srpaulo case IEEE80211_IOC_MCASTCIPHER: 163214501Srpaulo return "MCASTCIPHER"; 164214501Srpaulo case IEEE80211_PARAM_MCASTKEYLEN: 165214501Srpaulo return "MCASTKEYLEN"; 166214501Srpaulo case IEEE80211_PARAM_UCASTCIPHERS: 167214501Srpaulo return "UCASTCIPHERS"; 168214501Srpaulo case IEEE80211_PARAM_KEYMGTALGS: 169214501Srpaulo return "KEYMGTALGS"; 170214501Srpaulo case IEEE80211_PARAM_RSNCAPS: 171214501Srpaulo return "RSNCAPS"; 172214501Srpaulo case IEEE80211_PARAM_WPA: 173214501Srpaulo return "WPA"; 174214501Srpaulo case IEEE80211_PARAM_AUTHMODE: 175214501Srpaulo return "AUTHMODE"; 176214501Srpaulo case IEEE80211_PARAM_PRIVACY: 177214501Srpaulo return "PRIVACY"; 178214501Srpaulo case IEEE80211_PARAM_COUNTERMEASURES: 179214501Srpaulo return "COUNTERMEASURES"; 180214501Srpaulo default: 181214501Srpaulo return "??"; 182214501Srpaulo } 183214501Srpaulo} 184214501Srpaulo 185214501Srpaulo 186341618Scy#ifdef CONFIG_FILS 187214501Srpaulostatic int 188341618Scyget80211param(struct atheros_driver_data *drv, int op, int *data) 189341618Scy{ 190341618Scy struct iwreq iwr; 191341618Scy 192341618Scy os_memset(&iwr, 0, sizeof(iwr)); 193341618Scy os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 194341618Scy iwr.u.mode = op; 195341618Scy 196341618Scy if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_GETPARAM, &iwr) < 0) 197341618Scy return -1; 198341618Scy 199341618Scy *data = iwr.u.mode; 200341618Scy return 0; 201341618Scy} 202341618Scy#endif /* CONFIG_FILS */ 203341618Scy 204341618Scy 205341618Scystatic int 206252190Srpauloset80211priv(struct atheros_driver_data *drv, int op, void *data, int len) 207214501Srpaulo{ 208214501Srpaulo struct iwreq iwr; 209214501Srpaulo int do_inline = len < IFNAMSIZ; 210214501Srpaulo 211214501Srpaulo /* Certain ioctls must use the non-inlined method */ 212214501Srpaulo if (op == IEEE80211_IOCTL_SET_APPIEBUF || 213214501Srpaulo op == IEEE80211_IOCTL_FILTERFRAME) 214214501Srpaulo do_inline = 0; 215214501Srpaulo 216324714Scy os_memset(&iwr, 0, sizeof(iwr)); 217214501Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 218214501Srpaulo if (do_inline) { 219214501Srpaulo /* 220214501Srpaulo * Argument data fits inline; put it there. 221214501Srpaulo */ 222324714Scy os_memcpy(iwr.u.name, data, len); 223214501Srpaulo } else { 224214501Srpaulo /* 225214501Srpaulo * Argument data too big for inline transfer; setup a 226214501Srpaulo * parameter block instead; the kernel will transfer 227214501Srpaulo * the data for the driver. 228214501Srpaulo */ 229214501Srpaulo iwr.u.data.pointer = data; 230214501Srpaulo iwr.u.data.length = len; 231214501Srpaulo } 232214501Srpaulo 233214501Srpaulo if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { 234214501Srpaulo wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x " 235214501Srpaulo "(%s) len=%d failed: %d (%s)", 236214501Srpaulo __func__, drv->iface, op, 237214501Srpaulo athr_get_ioctl_name(op), 238214501Srpaulo len, errno, strerror(errno)); 239214501Srpaulo return -1; 240214501Srpaulo } 241214501Srpaulo return 0; 242214501Srpaulo} 243214501Srpaulo 244214501Srpaulostatic int 245252190Srpauloset80211param(struct atheros_driver_data *drv, int op, int arg) 246214501Srpaulo{ 247214501Srpaulo struct iwreq iwr; 248214501Srpaulo 249324714Scy os_memset(&iwr, 0, sizeof(iwr)); 250214501Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 251214501Srpaulo iwr.u.mode = op; 252324714Scy os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg)); 253214501Srpaulo 254214501Srpaulo if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { 255281681Srpaulo wpa_printf(MSG_INFO, 256281681Srpaulo "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s", 257281681Srpaulo __func__, drv->iface, op, athr_get_param_name(op), 258281681Srpaulo arg, strerror(errno)); 259214501Srpaulo return -1; 260214501Srpaulo } 261214501Srpaulo return 0; 262214501Srpaulo} 263214501Srpaulo 264214501Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG 265214501Srpaulostatic const char * 266214501Srpauloether_sprintf(const u8 *addr) 267214501Srpaulo{ 268214501Srpaulo static char buf[sizeof(MACSTR)]; 269214501Srpaulo 270214501Srpaulo if (addr != NULL) 271324714Scy os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 272214501Srpaulo else 273324714Scy os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0); 274214501Srpaulo return buf; 275214501Srpaulo} 276214501Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */ 277214501Srpaulo 278214501Srpaulo/* 279214501Srpaulo * Configure WPA parameters. 280214501Srpaulo */ 281214501Srpaulostatic int 282252190Srpauloatheros_configure_wpa(struct atheros_driver_data *drv, 283214501Srpaulo struct wpa_bss_params *params) 284214501Srpaulo{ 285214501Srpaulo int v; 286214501Srpaulo 287214501Srpaulo switch (params->wpa_group) { 288214501Srpaulo case WPA_CIPHER_CCMP: 289214501Srpaulo v = IEEE80211_CIPHER_AES_CCM; 290214501Srpaulo break; 291281681Srpaulo#ifdef ATH_GCM_SUPPORT 292281681Srpaulo case WPA_CIPHER_CCMP_256: 293281681Srpaulo v = IEEE80211_CIPHER_AES_CCM_256; 294281681Srpaulo break; 295281681Srpaulo case WPA_CIPHER_GCMP: 296281681Srpaulo v = IEEE80211_CIPHER_AES_GCM; 297281681Srpaulo break; 298281681Srpaulo case WPA_CIPHER_GCMP_256: 299281681Srpaulo v = IEEE80211_CIPHER_AES_GCM_256; 300281681Srpaulo break; 301281681Srpaulo#endif /* ATH_GCM_SUPPORT */ 302214501Srpaulo case WPA_CIPHER_TKIP: 303214501Srpaulo v = IEEE80211_CIPHER_TKIP; 304214501Srpaulo break; 305214501Srpaulo case WPA_CIPHER_WEP104: 306214501Srpaulo v = IEEE80211_CIPHER_WEP; 307214501Srpaulo break; 308214501Srpaulo case WPA_CIPHER_WEP40: 309214501Srpaulo v = IEEE80211_CIPHER_WEP; 310214501Srpaulo break; 311214501Srpaulo case WPA_CIPHER_NONE: 312214501Srpaulo v = IEEE80211_CIPHER_NONE; 313214501Srpaulo break; 314214501Srpaulo default: 315214501Srpaulo wpa_printf(MSG_ERROR, "Unknown group key cipher %u", 316214501Srpaulo params->wpa_group); 317214501Srpaulo return -1; 318214501Srpaulo } 319214501Srpaulo wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); 320214501Srpaulo if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { 321281681Srpaulo wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v); 322214501Srpaulo return -1; 323214501Srpaulo } 324214501Srpaulo if (v == IEEE80211_CIPHER_WEP) { 325214501Srpaulo /* key length is done only for specific ciphers */ 326214501Srpaulo v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); 327214501Srpaulo if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { 328281681Srpaulo wpa_printf(MSG_INFO, 329281681Srpaulo "Unable to set group key length to %u", v); 330214501Srpaulo return -1; 331214501Srpaulo } 332214501Srpaulo } 333214501Srpaulo 334214501Srpaulo v = 0; 335214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_CCMP) 336214501Srpaulo v |= 1<<IEEE80211_CIPHER_AES_CCM; 337281681Srpaulo#ifdef ATH_GCM_SUPPORT 338281681Srpaulo if (params->wpa_pairwise & WPA_CIPHER_CCMP_256) 339281681Srpaulo v |= 1<<IEEE80211_CIPHER_AES_CCM_256; 340281681Srpaulo if (params->wpa_pairwise & WPA_CIPHER_GCMP) 341281681Srpaulo v |= 1<<IEEE80211_CIPHER_AES_GCM; 342281681Srpaulo if (params->wpa_pairwise & WPA_CIPHER_GCMP_256) 343281681Srpaulo v |= 1<<IEEE80211_CIPHER_AES_GCM_256; 344281681Srpaulo#endif /* ATH_GCM_SUPPORT */ 345214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_TKIP) 346214501Srpaulo v |= 1<<IEEE80211_CIPHER_TKIP; 347214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_NONE) 348214501Srpaulo v |= 1<<IEEE80211_CIPHER_NONE; 349214501Srpaulo wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v); 350214501Srpaulo if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) { 351281681Srpaulo wpa_printf(MSG_INFO, 352281681Srpaulo "Unable to set pairwise key ciphers to 0x%x", v); 353214501Srpaulo return -1; 354214501Srpaulo } 355214501Srpaulo 356214501Srpaulo wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x", 357214501Srpaulo __func__, params->wpa_key_mgmt); 358214501Srpaulo if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, 359214501Srpaulo params->wpa_key_mgmt)) { 360281681Srpaulo wpa_printf(MSG_INFO, 361281681Srpaulo "Unable to set key management algorithms to 0x%x", 362281681Srpaulo params->wpa_key_mgmt); 363214501Srpaulo return -1; 364214501Srpaulo } 365214501Srpaulo 366214501Srpaulo v = 0; 367214501Srpaulo if (params->rsn_preauth) 368214501Srpaulo v |= BIT(0); 369252190Srpaulo#ifdef CONFIG_IEEE80211W 370252190Srpaulo if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 371252190Srpaulo v |= BIT(7); 372252190Srpaulo if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) 373252190Srpaulo v |= BIT(6); 374252190Srpaulo } 375252190Srpaulo#endif /* CONFIG_IEEE80211W */ 376252190Srpaulo 377252190Srpaulo wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v); 378214501Srpaulo if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { 379281681Srpaulo wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", 380281681Srpaulo v); 381214501Srpaulo return -1; 382214501Srpaulo } 383214501Srpaulo 384214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); 385214501Srpaulo if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { 386281681Srpaulo wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); 387214501Srpaulo return -1; 388214501Srpaulo } 389214501Srpaulo return 0; 390214501Srpaulo} 391214501Srpaulo 392214501Srpaulostatic int 393252190Srpauloatheros_set_ieee8021x(void *priv, struct wpa_bss_params *params) 394214501Srpaulo{ 395252190Srpaulo struct atheros_driver_data *drv = priv; 396214501Srpaulo 397214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); 398214501Srpaulo 399214501Srpaulo if (!params->enabled) { 400214501Srpaulo /* XXX restore state */ 401214501Srpaulo if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, 402214501Srpaulo IEEE80211_AUTH_AUTO) < 0) 403214501Srpaulo return -1; 404214501Srpaulo /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ 405252190Srpaulo return atheros_set_privacy(drv, 0); 406214501Srpaulo } 407214501Srpaulo if (!params->wpa && !params->ieee802_1x) { 408281681Srpaulo wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!"); 409214501Srpaulo return -1; 410214501Srpaulo } 411252190Srpaulo if (params->wpa && atheros_configure_wpa(drv, params) != 0) { 412281681Srpaulo wpa_printf(MSG_WARNING, "Error configuring WPA state!"); 413214501Srpaulo return -1; 414214501Srpaulo } 415214501Srpaulo if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, 416214501Srpaulo (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { 417281681Srpaulo wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!"); 418214501Srpaulo return -1; 419214501Srpaulo } 420214501Srpaulo 421214501Srpaulo return 0; 422214501Srpaulo} 423214501Srpaulo 424214501Srpaulostatic int 425252190Srpauloatheros_set_privacy(void *priv, int enabled) 426214501Srpaulo{ 427252190Srpaulo struct atheros_driver_data *drv = priv; 428214501Srpaulo 429214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 430214501Srpaulo 431214501Srpaulo return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); 432214501Srpaulo} 433214501Srpaulo 434214501Srpaulostatic int 435252190Srpauloatheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) 436214501Srpaulo{ 437252190Srpaulo struct atheros_driver_data *drv = priv; 438214501Srpaulo struct ieee80211req_mlme mlme; 439214501Srpaulo int ret; 440214501Srpaulo 441214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", 442214501Srpaulo __func__, ether_sprintf(addr), authorized); 443214501Srpaulo 444214501Srpaulo if (authorized) 445214501Srpaulo mlme.im_op = IEEE80211_MLME_AUTHORIZE; 446214501Srpaulo else 447214501Srpaulo mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; 448214501Srpaulo mlme.im_reason = 0; 449324714Scy os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 450214501Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 451214501Srpaulo if (ret < 0) { 452214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, 453214501Srpaulo __func__, authorized ? "" : "un", MAC2STR(addr)); 454214501Srpaulo } 455214501Srpaulo 456214501Srpaulo return ret; 457214501Srpaulo} 458214501Srpaulo 459214501Srpaulostatic int 460252190Srpauloatheros_sta_set_flags(void *priv, const u8 *addr, 461289284Srpaulo unsigned int total_flags, unsigned int flags_or, 462289284Srpaulo unsigned int flags_and) 463214501Srpaulo{ 464214501Srpaulo /* For now, only support setting Authorized flag */ 465214501Srpaulo if (flags_or & WPA_STA_AUTHORIZED) 466252190Srpaulo return atheros_set_sta_authorized(priv, addr, 1); 467214501Srpaulo if (!(flags_and & WPA_STA_AUTHORIZED)) 468252190Srpaulo return atheros_set_sta_authorized(priv, addr, 0); 469214501Srpaulo return 0; 470214501Srpaulo} 471214501Srpaulo 472214501Srpaulostatic int 473252190Srpauloatheros_del_key(void *priv, const u8 *addr, int key_idx) 474214501Srpaulo{ 475252190Srpaulo struct atheros_driver_data *drv = priv; 476214501Srpaulo struct ieee80211req_del_key wk; 477214501Srpaulo int ret; 478214501Srpaulo 479214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", 480214501Srpaulo __func__, ether_sprintf(addr), key_idx); 481214501Srpaulo 482324714Scy os_memset(&wk, 0, sizeof(wk)); 483214501Srpaulo if (addr != NULL) { 484324714Scy os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); 485214501Srpaulo wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; 486214501Srpaulo } else { 487214501Srpaulo wk.idk_keyix = key_idx; 488214501Srpaulo } 489214501Srpaulo 490214501Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); 491214501Srpaulo if (ret < 0) { 492214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" 493214501Srpaulo " key_idx %d)", __func__, ether_sprintf(addr), 494214501Srpaulo key_idx); 495214501Srpaulo } 496214501Srpaulo 497214501Srpaulo return ret; 498214501Srpaulo} 499214501Srpaulo 500214501Srpaulostatic int 501252190Srpauloatheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, 502214501Srpaulo const u8 *addr, int key_idx, int set_tx, const u8 *seq, 503214501Srpaulo size_t seq_len, const u8 *key, size_t key_len) 504214501Srpaulo{ 505252190Srpaulo struct atheros_driver_data *drv = priv; 506214501Srpaulo struct ieee80211req_key wk; 507214501Srpaulo u_int8_t cipher; 508214501Srpaulo int ret; 509214501Srpaulo 510214501Srpaulo if (alg == WPA_ALG_NONE) 511252190Srpaulo return atheros_del_key(drv, addr, key_idx); 512214501Srpaulo 513214501Srpaulo wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", 514214501Srpaulo __func__, alg, ether_sprintf(addr), key_idx); 515214501Srpaulo 516214501Srpaulo switch (alg) { 517214501Srpaulo case WPA_ALG_WEP: 518214501Srpaulo cipher = IEEE80211_CIPHER_WEP; 519214501Srpaulo break; 520214501Srpaulo case WPA_ALG_TKIP: 521214501Srpaulo cipher = IEEE80211_CIPHER_TKIP; 522214501Srpaulo break; 523214501Srpaulo case WPA_ALG_CCMP: 524214501Srpaulo cipher = IEEE80211_CIPHER_AES_CCM; 525214501Srpaulo break; 526281681Srpaulo#ifdef ATH_GCM_SUPPORT 527281681Srpaulo case WPA_ALG_CCMP_256: 528281681Srpaulo cipher = IEEE80211_CIPHER_AES_CCM_256; 529281681Srpaulo break; 530281681Srpaulo case WPA_ALG_GCMP: 531281681Srpaulo cipher = IEEE80211_CIPHER_AES_GCM; 532281681Srpaulo break; 533281681Srpaulo case WPA_ALG_GCMP_256: 534281681Srpaulo cipher = IEEE80211_CIPHER_AES_GCM_256; 535281681Srpaulo break; 536281681Srpaulo#endif /* ATH_GCM_SUPPORT */ 537252190Srpaulo#ifdef CONFIG_IEEE80211W 538252190Srpaulo case WPA_ALG_IGTK: 539252190Srpaulo cipher = IEEE80211_CIPHER_AES_CMAC; 540252190Srpaulo break; 541281681Srpaulo#ifdef ATH_GCM_SUPPORT 542281681Srpaulo case WPA_ALG_BIP_CMAC_256: 543281681Srpaulo cipher = IEEE80211_CIPHER_AES_CMAC_256; 544281681Srpaulo break; 545281681Srpaulo case WPA_ALG_BIP_GMAC_128: 546281681Srpaulo cipher = IEEE80211_CIPHER_AES_GMAC; 547281681Srpaulo break; 548281681Srpaulo case WPA_ALG_BIP_GMAC_256: 549281681Srpaulo cipher = IEEE80211_CIPHER_AES_GMAC_256; 550281681Srpaulo break; 551281681Srpaulo#endif /* ATH_GCM_SUPPORT */ 552252190Srpaulo#endif /* CONFIG_IEEE80211W */ 553214501Srpaulo default: 554281681Srpaulo wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d", 555281681Srpaulo __func__, alg); 556214501Srpaulo return -1; 557214501Srpaulo } 558214501Srpaulo 559214501Srpaulo if (key_len > sizeof(wk.ik_keydata)) { 560281681Srpaulo wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__, 561281681Srpaulo (unsigned long) key_len); 562214501Srpaulo return -3; 563214501Srpaulo } 564214501Srpaulo 565324714Scy os_memset(&wk, 0, sizeof(wk)); 566214501Srpaulo wk.ik_type = cipher; 567214501Srpaulo wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; 568252190Srpaulo if (addr == NULL || is_broadcast_ether_addr(addr)) { 569324714Scy os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 570214501Srpaulo wk.ik_keyix = key_idx; 571252190Srpaulo if (set_tx) 572252190Srpaulo wk.ik_flags |= IEEE80211_KEY_DEFAULT; 573214501Srpaulo } else { 574324714Scy os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 575214501Srpaulo wk.ik_keyix = IEEE80211_KEYIX_NONE; 576214501Srpaulo } 577214501Srpaulo wk.ik_keylen = key_len; 578324714Scy os_memcpy(wk.ik_keydata, key, key_len); 579214501Srpaulo 580214501Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); 581214501Srpaulo if (ret < 0) { 582214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" 583214501Srpaulo " key_idx %d alg %d key_len %lu set_tx %d)", 584214501Srpaulo __func__, ether_sprintf(wk.ik_macaddr), key_idx, 585214501Srpaulo alg, (unsigned long) key_len, set_tx); 586214501Srpaulo } 587214501Srpaulo 588214501Srpaulo return ret; 589214501Srpaulo} 590214501Srpaulo 591214501Srpaulo 592214501Srpaulostatic int 593252190Srpauloatheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, 594214501Srpaulo u8 *seq) 595214501Srpaulo{ 596252190Srpaulo struct atheros_driver_data *drv = priv; 597214501Srpaulo struct ieee80211req_key wk; 598214501Srpaulo 599214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", 600214501Srpaulo __func__, ether_sprintf(addr), idx); 601214501Srpaulo 602324714Scy os_memset(&wk, 0, sizeof(wk)); 603214501Srpaulo if (addr == NULL) 604324714Scy os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 605214501Srpaulo else 606324714Scy os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 607214501Srpaulo wk.ik_keyix = idx; 608214501Srpaulo 609214501Srpaulo if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { 610214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " 611214501Srpaulo "(addr " MACSTR " key_idx %d)", 612214501Srpaulo __func__, MAC2STR(wk.ik_macaddr), idx); 613214501Srpaulo return -1; 614214501Srpaulo } 615214501Srpaulo 616214501Srpaulo#ifdef WORDS_BIGENDIAN 617214501Srpaulo { 618214501Srpaulo /* 619214501Srpaulo * wk.ik_keytsc is in host byte order (big endian), need to 620214501Srpaulo * swap it to match with the byte order used in WPA. 621214501Srpaulo */ 622214501Srpaulo int i; 623214501Srpaulo#ifndef WPA_KEY_RSC_LEN 624214501Srpaulo#define WPA_KEY_RSC_LEN 8 625214501Srpaulo#endif 626214501Srpaulo u8 tmp[WPA_KEY_RSC_LEN]; 627324714Scy os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 628214501Srpaulo for (i = 0; i < WPA_KEY_RSC_LEN; i++) { 629214501Srpaulo seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; 630214501Srpaulo } 631214501Srpaulo } 632214501Srpaulo#else /* WORDS_BIGENDIAN */ 633324714Scy os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 634214501Srpaulo#endif /* WORDS_BIGENDIAN */ 635214501Srpaulo return 0; 636214501Srpaulo} 637214501Srpaulo 638214501Srpaulo 639214501Srpaulostatic int 640252190Srpauloatheros_flush(void *priv) 641214501Srpaulo{ 642214501Srpaulo u8 allsta[IEEE80211_ADDR_LEN]; 643324714Scy os_memset(allsta, 0xff, IEEE80211_ADDR_LEN); 644252190Srpaulo return atheros_sta_deauth(priv, NULL, allsta, 645214501Srpaulo IEEE80211_REASON_AUTH_LEAVE); 646214501Srpaulo} 647214501Srpaulo 648214501Srpaulo 649214501Srpaulostatic int 650252190Srpauloatheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, 651214501Srpaulo const u8 *addr) 652214501Srpaulo{ 653252190Srpaulo struct atheros_driver_data *drv = priv; 654214501Srpaulo struct ieee80211req_sta_stats stats; 655214501Srpaulo 656324714Scy os_memset(data, 0, sizeof(*data)); 657214501Srpaulo 658214501Srpaulo /* 659214501Srpaulo * Fetch statistics for station from the system. 660214501Srpaulo */ 661324714Scy os_memset(&stats, 0, sizeof(stats)); 662324714Scy os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); 663214501Srpaulo if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, 664214501Srpaulo &stats, sizeof(stats))) { 665214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " 666214501Srpaulo MACSTR ")", __func__, MAC2STR(addr)); 667324714Scy if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { 668324714Scy os_memcpy(data, &drv->acct_data, sizeof(*data)); 669214501Srpaulo return 0; 670214501Srpaulo } 671214501Srpaulo 672281681Srpaulo wpa_printf(MSG_INFO, 673281681Srpaulo "Failed to get station stats information element"); 674214501Srpaulo return -1; 675214501Srpaulo } 676214501Srpaulo 677214501Srpaulo data->rx_packets = stats.is_stats.ns_rx_data; 678214501Srpaulo data->rx_bytes = stats.is_stats.ns_rx_bytes; 679214501Srpaulo data->tx_packets = stats.is_stats.ns_tx_data; 680214501Srpaulo data->tx_bytes = stats.is_stats.ns_tx_bytes; 681214501Srpaulo return 0; 682214501Srpaulo} 683214501Srpaulo 684214501Srpaulo 685214501Srpaulostatic int 686252190Srpauloatheros_sta_clear_stats(void *priv, const u8 *addr) 687214501Srpaulo{ 688252190Srpaulo struct atheros_driver_data *drv = priv; 689214501Srpaulo struct ieee80211req_mlme mlme; 690214501Srpaulo int ret; 691214501Srpaulo 692214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); 693214501Srpaulo 694214501Srpaulo mlme.im_op = IEEE80211_MLME_CLEAR_STATS; 695324714Scy os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 696214501Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, 697214501Srpaulo sizeof(mlme)); 698214501Srpaulo if (ret < 0) { 699214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " 700214501Srpaulo MACSTR ")", __func__, MAC2STR(addr)); 701214501Srpaulo } 702214501Srpaulo 703214501Srpaulo return ret; 704214501Srpaulo} 705214501Srpaulo 706214501Srpaulo 707214501Srpaulostatic int 708252190Srpauloatheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) 709214501Srpaulo{ 710252190Srpaulo struct atheros_driver_data *drv = priv; 711252190Srpaulo u8 buf[512]; 712252190Srpaulo struct ieee80211req_getset_appiebuf *app_ie; 713252190Srpaulo 714252190Srpaulo wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, 715252190Srpaulo (unsigned long) ie_len); 716252190Srpaulo wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len); 717252190Srpaulo 718252190Srpaulo wpabuf_free(drv->wpa_ie); 719341618Scy if (ie) 720341618Scy drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); 721341618Scy else 722341618Scy drv->wpa_ie = NULL; 723252190Srpaulo 724252190Srpaulo app_ie = (struct ieee80211req_getset_appiebuf *) buf; 725341618Scy if (ie) 726341618Scy os_memcpy(&(app_ie->app_buf[0]), ie, ie_len); 727252190Srpaulo app_ie->app_buflen = ie_len; 728252190Srpaulo 729252190Srpaulo app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON; 730252190Srpaulo 731252190Srpaulo /* append WPS IE for Beacon */ 732252190Srpaulo if (drv->wps_beacon_ie != NULL) { 733252190Srpaulo os_memcpy(&(app_ie->app_buf[ie_len]), 734252190Srpaulo wpabuf_head(drv->wps_beacon_ie), 735252190Srpaulo wpabuf_len(drv->wps_beacon_ie)); 736252190Srpaulo app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); 737252190Srpaulo } 738252190Srpaulo wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)", 739252190Srpaulo app_ie->app_buf, app_ie->app_buflen); 740252190Srpaulo set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, 741252190Srpaulo sizeof(struct ieee80211req_getset_appiebuf) + 742252190Srpaulo app_ie->app_buflen); 743252190Srpaulo 744252190Srpaulo /* append WPS IE for Probe Response */ 745252190Srpaulo app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP; 746252190Srpaulo if (drv->wps_probe_resp_ie != NULL) { 747252190Srpaulo os_memcpy(&(app_ie->app_buf[ie_len]), 748252190Srpaulo wpabuf_head(drv->wps_probe_resp_ie), 749252190Srpaulo wpabuf_len(drv->wps_probe_resp_ie)); 750252190Srpaulo app_ie->app_buflen = ie_len + 751252190Srpaulo wpabuf_len(drv->wps_probe_resp_ie); 752252190Srpaulo } else 753252190Srpaulo app_ie->app_buflen = ie_len; 754252190Srpaulo wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)", 755252190Srpaulo app_ie->app_buf, app_ie->app_buflen); 756252190Srpaulo set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, 757252190Srpaulo sizeof(struct ieee80211req_getset_appiebuf) + 758252190Srpaulo app_ie->app_buflen); 759214501Srpaulo return 0; 760214501Srpaulo} 761214501Srpaulo 762214501Srpaulostatic int 763252190Srpauloatheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 764351377Scy u16 reason_code) 765214501Srpaulo{ 766252190Srpaulo struct atheros_driver_data *drv = priv; 767214501Srpaulo struct ieee80211req_mlme mlme; 768214501Srpaulo int ret; 769214501Srpaulo 770214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", 771214501Srpaulo __func__, ether_sprintf(addr), reason_code); 772214501Srpaulo 773214501Srpaulo mlme.im_op = IEEE80211_MLME_DEAUTH; 774214501Srpaulo mlme.im_reason = reason_code; 775324714Scy os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 776214501Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 777214501Srpaulo if (ret < 0) { 778214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR 779214501Srpaulo " reason %d)", 780214501Srpaulo __func__, MAC2STR(addr), reason_code); 781214501Srpaulo } 782214501Srpaulo 783214501Srpaulo return ret; 784214501Srpaulo} 785214501Srpaulo 786214501Srpaulostatic int 787252190Srpauloatheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, 788351377Scy u16 reason_code) 789214501Srpaulo{ 790252190Srpaulo struct atheros_driver_data *drv = priv; 791214501Srpaulo struct ieee80211req_mlme mlme; 792214501Srpaulo int ret; 793214501Srpaulo 794214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", 795214501Srpaulo __func__, ether_sprintf(addr), reason_code); 796214501Srpaulo 797214501Srpaulo mlme.im_op = IEEE80211_MLME_DISASSOC; 798214501Srpaulo mlme.im_reason = reason_code; 799324714Scy os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 800214501Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 801214501Srpaulo if (ret < 0) { 802214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " 803214501Srpaulo MACSTR " reason %d)", 804214501Srpaulo __func__, MAC2STR(addr), reason_code); 805214501Srpaulo } 806214501Srpaulo 807214501Srpaulo return ret; 808214501Srpaulo} 809214501Srpaulo 810281681Srpaulostatic int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, 811281681Srpaulo u8 qos_map_set_len) 812214501Srpaulo{ 813281681Srpaulo#ifdef CONFIG_ATHEROS_QOS_MAP 814252190Srpaulo struct atheros_driver_data *drv = ctx; 815281681Srpaulo struct ieee80211req_athdbg req; 816281681Srpaulo struct ieee80211_qos_map *qos_map = &req.data.qos_map; 817281681Srpaulo struct iwreq iwr; 818281681Srpaulo int i, up_start; 819214501Srpaulo 820281681Srpaulo if (qos_map_set_len < 16 || qos_map_set_len > 58 || 821281681Srpaulo qos_map_set_len & 1) { 822281681Srpaulo wpa_printf(MSG_ERROR, "Invalid QoS Map"); 823281681Srpaulo return -1; 824281681Srpaulo } else { 825324714Scy os_memset(&req, 0, sizeof(struct ieee80211req_athdbg)); 826281681Srpaulo req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF; 827281681Srpaulo os_memset(&iwr, 0, sizeof(iwr)); 828281681Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name)); 829281681Srpaulo iwr.u.data.pointer = (void *) &req; 830281681Srpaulo iwr.u.data.length = sizeof(struct ieee80211req_athdbg); 831281681Srpaulo } 832214501Srpaulo 833281681Srpaulo qos_map->valid = 1; 834281681Srpaulo qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; 835281681Srpaulo if (qos_map->num_dscp_except) { 836281681Srpaulo for (i = 0; i < qos_map->num_dscp_except; i++) { 837281681Srpaulo qos_map->dscp_exception[i].dscp = qos_map_set[i * 2]; 838281681Srpaulo qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1]; 839281681Srpaulo } 840281681Srpaulo } 841214501Srpaulo 842281681Srpaulo up_start = qos_map_set_len - 16; 843281681Srpaulo for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) { 844281681Srpaulo qos_map->up[i].low = qos_map_set[up_start + (i * 2)]; 845281681Srpaulo qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1]; 846281681Srpaulo } 847214501Srpaulo 848281681Srpaulo if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) { 849281681Srpaulo wpa_printf(MSG_ERROR, 850281681Srpaulo "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s", 851281681Srpaulo __func__, drv->iface, strerror(errno)); 852281681Srpaulo return -1; 853281681Srpaulo } 854281681Srpaulo#endif /* CONFIG_ATHEROS_QOS_MAP */ 855281681Srpaulo 856281681Srpaulo return 0; 857214501Srpaulo} 858214501Srpaulo 859289284Srpaulo#ifdef ATHEROS_USE_RAW_RECEIVE 860281681Srpaulostatic void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, 861281681Srpaulo size_t len) 862214501Srpaulo{ 863252190Srpaulo struct atheros_driver_data *drv = ctx; 864281681Srpaulo const struct ieee80211_mgmt *mgmt; 865252190Srpaulo union wpa_event_data event; 866281681Srpaulo u16 fc, stype; 867252190Srpaulo int ielen; 868252190Srpaulo const u8 *iebuf; 869252190Srpaulo 870252190Srpaulo if (len < IEEE80211_HDRLEN) 871252190Srpaulo return; 872281681Srpaulo 873252190Srpaulo mgmt = (const struct ieee80211_mgmt *) buf; 874252190Srpaulo 875252190Srpaulo fc = le_to_host16(mgmt->frame_control); 876252190Srpaulo 877252190Srpaulo if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) 878252190Srpaulo return; 879281681Srpaulo 880252190Srpaulo stype = WLAN_FC_GET_STYPE(fc); 881252190Srpaulo 882252190Srpaulo wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, 883252190Srpaulo (int) len); 884252190Srpaulo 885281681Srpaulo if (stype == WLAN_FC_STYPE_PROBE_REQ) { 886324714Scy if (len < IEEE80211_HDRLEN) 887281681Srpaulo return; 888281681Srpaulo 889281681Srpaulo os_memset(&event, 0, sizeof(event)); 890281681Srpaulo event.rx_probe_req.sa = mgmt->sa; 891281681Srpaulo event.rx_probe_req.da = mgmt->da; 892281681Srpaulo event.rx_probe_req.bssid = mgmt->bssid; 893324714Scy event.rx_probe_req.ie = buf + IEEE80211_HDRLEN; 894324714Scy event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN; 895281681Srpaulo wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); 896281681Srpaulo return; 897281681Srpaulo } 898281681Srpaulo 899324714Scy if (stype == WLAN_FC_STYPE_ACTION && 900324714Scy (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 || 901324714Scy is_broadcast_ether_addr(mgmt->bssid))) { 902324714Scy os_memset(&event, 0, sizeof(event)); 903324714Scy event.rx_mgmt.frame = buf; 904324714Scy event.rx_mgmt.frame_len = len; 905324714Scy wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); 906324714Scy return; 907324714Scy } 908324714Scy 909252190Srpaulo if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { 910252190Srpaulo wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", 911252190Srpaulo __func__); 912252190Srpaulo return; 913252190Srpaulo } 914281681Srpaulo 915252190Srpaulo switch (stype) { 916252190Srpaulo case WLAN_FC_STYPE_ASSOC_REQ: 917281681Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)) 918252190Srpaulo break; 919252190Srpaulo ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); 920252190Srpaulo iebuf = mgmt->u.assoc_req.variable; 921252190Srpaulo drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0); 922252190Srpaulo break; 923252190Srpaulo case WLAN_FC_STYPE_REASSOC_REQ: 924281681Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)) 925252190Srpaulo break; 926252190Srpaulo ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); 927252190Srpaulo iebuf = mgmt->u.reassoc_req.variable; 928252190Srpaulo drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); 929252190Srpaulo break; 930252190Srpaulo case WLAN_FC_STYPE_AUTH: 931281681Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) 932252190Srpaulo break; 933252190Srpaulo os_memset(&event, 0, sizeof(event)); 934341618Scy if (le_to_host16(mgmt->u.auth.auth_alg) == WLAN_AUTH_SAE) { 935341618Scy event.rx_mgmt.frame = buf; 936341618Scy event.rx_mgmt.frame_len = len; 937341618Scy wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); 938341618Scy break; 939341618Scy } 940252190Srpaulo os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); 941252190Srpaulo os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN); 942252190Srpaulo event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); 943252190Srpaulo event.auth.status_code = 944252190Srpaulo le_to_host16(mgmt->u.auth.status_code); 945252190Srpaulo event.auth.auth_transaction = 946252190Srpaulo le_to_host16(mgmt->u.auth.auth_transaction); 947252190Srpaulo event.auth.ies = mgmt->u.auth.variable; 948252190Srpaulo event.auth.ies_len = len - IEEE80211_HDRLEN - 949252190Srpaulo sizeof(mgmt->u.auth); 950252190Srpaulo wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event); 951252190Srpaulo break; 952252190Srpaulo default: 953252190Srpaulo break; 954252190Srpaulo } 955252190Srpaulo} 956289284Srpaulo#endif /* ATHEROS_USE_RAW_RECEIVE */ 957252190Srpaulo 958252190Srpaulostatic int atheros_receive_pkt(struct atheros_driver_data *drv) 959252190Srpaulo{ 960214501Srpaulo int ret = 0; 961214501Srpaulo struct ieee80211req_set_filter filt; 962214501Srpaulo 963214501Srpaulo wpa_printf(MSG_DEBUG, "%s Enter", __func__); 964252190Srpaulo filt.app_filterype = 0; 965252190Srpaulo#ifdef CONFIG_WPS 966252190Srpaulo filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ; 967252190Srpaulo#endif /* CONFIG_WPS */ 968341618Scy#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) 969252190Srpaulo filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | 970252190Srpaulo IEEE80211_FILTER_TYPE_AUTH | 971252190Srpaulo IEEE80211_FILTER_TYPE_ACTION); 972341618Scy#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 973252190Srpaulo#ifdef CONFIG_WNM 974252190Srpaulo filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; 975252190Srpaulo#endif /* CONFIG_WNM */ 976252190Srpaulo#ifdef CONFIG_HS20 977252190Srpaulo filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; 978252190Srpaulo#endif /* CONFIG_HS20 */ 979252190Srpaulo if (filt.app_filterype) { 980252190Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, 981252190Srpaulo sizeof(struct ieee80211req_set_filter)); 982252190Srpaulo if (ret) 983252190Srpaulo return ret; 984252190Srpaulo } 985214501Srpaulo 986341618Scy#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) 987214501Srpaulo drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, 988252190Srpaulo atheros_raw_receive, drv, 1); 989214501Srpaulo if (drv->sock_raw == NULL) 990214501Srpaulo return -1; 991341618Scy#endif /* CONFIG_WPS || CONFIG_IEEE80211R || CONFIG_FILS */ 992214501Srpaulo return ret; 993214501Srpaulo} 994214501Srpaulo 995252190Srpaulostatic int atheros_reset_appfilter(struct atheros_driver_data *drv) 996252190Srpaulo{ 997252190Srpaulo struct ieee80211req_set_filter filt; 998252190Srpaulo filt.app_filterype = 0; 999252190Srpaulo return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, 1000252190Srpaulo sizeof(struct ieee80211req_set_filter)); 1001252190Srpaulo} 1002252190Srpaulo 1003214501Srpaulo#ifdef CONFIG_WPS 1004214501Srpaulostatic int 1005252190Srpauloatheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) 1006214501Srpaulo{ 1007252190Srpaulo struct atheros_driver_data *drv = priv; 1008252190Srpaulo u8 buf[512]; 1009214501Srpaulo struct ieee80211req_getset_appiebuf *beac_ie; 1010214501Srpaulo 1011252190Srpaulo wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__, 1012252190Srpaulo (unsigned long) len, frametype); 1013252190Srpaulo wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len); 1014214501Srpaulo 1015214501Srpaulo beac_ie = (struct ieee80211req_getset_appiebuf *) buf; 1016214501Srpaulo beac_ie->app_frmtype = frametype; 1017214501Srpaulo beac_ie->app_buflen = len; 1018341618Scy if (ie) 1019341618Scy os_memcpy(&(beac_ie->app_buf[0]), ie, len); 1020214501Srpaulo 1021252190Srpaulo /* append the WPA/RSN IE if it is set already */ 1022252190Srpaulo if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || 1023252190Srpaulo (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && 1024252190Srpaulo (drv->wpa_ie != NULL)) { 1025252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE", 1026252190Srpaulo drv->wpa_ie); 1027252190Srpaulo os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), 1028252190Srpaulo wpabuf_len(drv->wpa_ie)); 1029252190Srpaulo beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); 1030252190Srpaulo } 1031252190Srpaulo 1032252190Srpaulo wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF", 1033252190Srpaulo beac_ie->app_buf, beac_ie->app_buflen); 1034214501Srpaulo return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, 1035252190Srpaulo sizeof(struct ieee80211req_getset_appiebuf) + 1036252190Srpaulo beac_ie->app_buflen); 1037214501Srpaulo} 1038214501Srpaulo 1039214501Srpaulostatic int 1040252190Srpauloatheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, 1041252190Srpaulo const struct wpabuf *proberesp, 1042252190Srpaulo const struct wpabuf *assocresp) 1043214501Srpaulo{ 1044252190Srpaulo struct atheros_driver_data *drv = priv; 1045252190Srpaulo 1046252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon); 1047252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp", 1048252190Srpaulo proberesp); 1049252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp", 1050252190Srpaulo assocresp); 1051252190Srpaulo wpabuf_free(drv->wps_beacon_ie); 1052252190Srpaulo drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; 1053252190Srpaulo wpabuf_free(drv->wps_probe_resp_ie); 1054252190Srpaulo drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL; 1055252190Srpaulo 1056252190Srpaulo atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, 1057252190Srpaulo assocresp ? wpabuf_len(assocresp) : 0, 1058252190Srpaulo IEEE80211_APPIE_FRAME_ASSOC_RESP); 1059252190Srpaulo if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, 1060214501Srpaulo beacon ? wpabuf_len(beacon) : 0, 1061214501Srpaulo IEEE80211_APPIE_FRAME_BEACON)) 1062214501Srpaulo return -1; 1063252190Srpaulo return atheros_set_wps_ie(priv, 1064214501Srpaulo proberesp ? wpabuf_head(proberesp) : NULL, 1065214501Srpaulo proberesp ? wpabuf_len(proberesp): 0, 1066214501Srpaulo IEEE80211_APPIE_FRAME_PROBE_RESP); 1067214501Srpaulo} 1068214501Srpaulo#else /* CONFIG_WPS */ 1069252190Srpaulo#define atheros_set_ap_wps_ie NULL 1070214501Srpaulo#endif /* CONFIG_WPS */ 1071214501Srpaulo 1072341618Scy#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1073252190Srpaulostatic int 1074341618Scyatheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params) 1075252190Srpaulo{ 1076252190Srpaulo struct atheros_driver_data *drv = priv; 1077252190Srpaulo struct ieee80211req_mlme mlme; 1078252190Srpaulo int ret; 1079252190Srpaulo 1080252190Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d", 1081341618Scy __func__, ether_sprintf(params->addr), params->status); 1082252190Srpaulo 1083341618Scy#ifdef CONFIG_FILS 1084341618Scy /* Copy FILS AAD parameters if the driver supports FILS */ 1085341618Scy if (params->fils_auth && drv->fils_en) { 1086341618Scy wpa_printf(MSG_DEBUG, "%s: im_op IEEE80211_MLME_AUTH_FILS", 1087341618Scy __func__); 1088341618Scy os_memcpy(mlme.fils_aad.ANonce, params->fils_anonce, 1089341618Scy IEEE80211_FILS_NONCE_LEN); 1090341618Scy os_memcpy(mlme.fils_aad.SNonce, params->fils_snonce, 1091341618Scy IEEE80211_FILS_NONCE_LEN); 1092341618Scy os_memcpy(mlme.fils_aad.kek, params->fils_kek, 1093341618Scy IEEE80211_MAX_WPA_KEK_LEN); 1094341618Scy mlme.fils_aad.kek_len = params->fils_kek_len; 1095341618Scy mlme.im_op = IEEE80211_MLME_AUTH_FILS; 1096341618Scy wpa_hexdump(MSG_DEBUG, "FILS: ANonce", 1097341618Scy mlme.fils_aad.ANonce, FILS_NONCE_LEN); 1098341618Scy wpa_hexdump(MSG_DEBUG, "FILS: SNonce", 1099341618Scy mlme.fils_aad.SNonce, FILS_NONCE_LEN); 1100341618Scy wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", 1101341618Scy mlme.fils_aad.kek, mlme.fils_aad.kek_len); 1102341618Scy } else { 1103341618Scy mlme.im_op = IEEE80211_MLME_AUTH; 1104341618Scy } 1105341618Scy#else /* CONFIG_FILS */ 1106252190Srpaulo mlme.im_op = IEEE80211_MLME_AUTH; 1107341618Scy#endif /* CONFIG_FILS */ 1108341618Scy 1109341618Scy mlme.im_reason = params->status; 1110341618Scy mlme.im_seq = params->seq; 1111341618Scy os_memcpy(mlme.im_macaddr, params->addr, IEEE80211_ADDR_LEN); 1112341618Scy mlme.im_optie_len = params->len; 1113341618Scy if (params->len) { 1114341618Scy if (params->len < IEEE80211_MAX_OPT_IE) { 1115341618Scy os_memcpy(mlme.im_optie, params->ie, params->len); 1116252190Srpaulo } else { 1117252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " 1118252190Srpaulo "opt_ie STA (addr " MACSTR " reason %d, " 1119252190Srpaulo "ie_len %d)", 1120341618Scy __func__, MAC2STR(params->addr), 1121341618Scy params->status, (int) params->len); 1122252190Srpaulo return -1; 1123252190Srpaulo } 1124252190Srpaulo } 1125252190Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 1126252190Srpaulo if (ret < 0) { 1127252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR 1128252190Srpaulo " reason %d)", 1129341618Scy __func__, MAC2STR(params->addr), params->status); 1130252190Srpaulo } 1131252190Srpaulo return ret; 1132252190Srpaulo} 1133252190Srpaulo 1134252190Srpaulostatic int 1135252190Srpauloatheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, 1136252190Srpaulo int reassoc, u16 status_code, const u8 *ie, size_t len) 1137252190Srpaulo{ 1138252190Srpaulo struct atheros_driver_data *drv = priv; 1139252190Srpaulo struct ieee80211req_mlme mlme; 1140252190Srpaulo int ret; 1141252190Srpaulo 1142252190Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d", 1143252190Srpaulo __func__, ether_sprintf(addr), status_code, reassoc); 1144252190Srpaulo 1145252190Srpaulo if (reassoc) 1146252190Srpaulo mlme.im_op = IEEE80211_MLME_REASSOC; 1147252190Srpaulo else 1148252190Srpaulo mlme.im_op = IEEE80211_MLME_ASSOC; 1149252190Srpaulo mlme.im_reason = status_code; 1150252190Srpaulo os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 1151252190Srpaulo mlme.im_optie_len = len; 1152252190Srpaulo if (len) { 1153252190Srpaulo if (len < IEEE80211_MAX_OPT_IE) { 1154252190Srpaulo os_memcpy(mlme.im_optie, ie, len); 1155252190Srpaulo } else { 1156252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " 1157252190Srpaulo "opt_ie STA (addr " MACSTR " reason %d, " 1158252190Srpaulo "ie_len %d)", 1159252190Srpaulo __func__, MAC2STR(addr), status_code, 1160252190Srpaulo (int) len); 1161252190Srpaulo return -1; 1162252190Srpaulo } 1163252190Srpaulo } 1164252190Srpaulo ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 1165252190Srpaulo if (ret < 0) { 1166252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR 1167252190Srpaulo " reason %d)", 1168252190Srpaulo __func__, MAC2STR(addr), status_code); 1169252190Srpaulo } 1170252190Srpaulo return ret; 1171252190Srpaulo} 1172341618Scy#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 1173252190Srpaulo 1174214501Srpaulostatic void 1175252190Srpauloatheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) 1176214501Srpaulo{ 1177214501Srpaulo struct hostapd_data *hapd = drv->hapd; 1178214501Srpaulo struct ieee80211req_wpaie ie; 1179214501Srpaulo int ielen = 0; 1180214501Srpaulo u8 *iebuf = NULL; 1181214501Srpaulo 1182214501Srpaulo /* 1183214501Srpaulo * Fetch negotiated WPA/RSN parameters from the system. 1184214501Srpaulo */ 1185324714Scy os_memset(&ie, 0, sizeof(ie)); 1186324714Scy os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); 1187214501Srpaulo if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { 1188214501Srpaulo /* 1189214501Srpaulo * See ATH_WPS_IE comment in the beginning of the file for a 1190214501Srpaulo * possible cause for the failure.. 1191214501Srpaulo */ 1192214501Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", 1193214501Srpaulo __func__, strerror(errno)); 1194214501Srpaulo goto no_ie; 1195214501Srpaulo } 1196252190Srpaulo wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", 1197214501Srpaulo ie.wpa_ie, IEEE80211_MAX_OPT_IE); 1198252190Srpaulo wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", 1199214501Srpaulo ie.rsn_ie, IEEE80211_MAX_OPT_IE); 1200252190Srpaulo#ifdef ATH_WPS_IE 1201252190Srpaulo wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", 1202252190Srpaulo ie.wps_ie, IEEE80211_MAX_OPT_IE); 1203252190Srpaulo#endif /* ATH_WPS_IE */ 1204214501Srpaulo iebuf = ie.wpa_ie; 1205252190Srpaulo /* atheros seems to return some random data if WPA/RSN IE is not set. 1206214501Srpaulo * Assume the IE was not included if the IE type is unknown. */ 1207214501Srpaulo if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) 1208214501Srpaulo iebuf[1] = 0; 1209214501Srpaulo if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { 1210252190Srpaulo /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not 1211214501Srpaulo * set. This is needed for WPA2. */ 1212214501Srpaulo iebuf = ie.rsn_ie; 1213214501Srpaulo if (iebuf[0] != WLAN_EID_RSN) 1214214501Srpaulo iebuf[1] = 0; 1215214501Srpaulo } 1216214501Srpaulo 1217214501Srpaulo ielen = iebuf[1]; 1218252190Srpaulo 1219252190Srpaulo#ifdef ATH_WPS_IE 1220252190Srpaulo /* if WPS IE is present, preference is given to WPS */ 1221346563Scy if (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie.wps_ie[1] > 0) { 1222252190Srpaulo iebuf = ie.wps_ie; 1223252190Srpaulo ielen = ie.wps_ie[1]; 1224252190Srpaulo } 1225252190Srpaulo#endif /* ATH_WPS_IE */ 1226252190Srpaulo 1227214501Srpaulo if (ielen == 0) 1228214501Srpaulo iebuf = NULL; 1229214501Srpaulo else 1230214501Srpaulo ielen += 2; 1231214501Srpaulo 1232214501Srpaulono_ie: 1233252190Srpaulo drv_event_assoc(hapd, addr, iebuf, ielen, 0); 1234214501Srpaulo 1235324714Scy if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { 1236214501Srpaulo /* Cached accounting data is not valid anymore. */ 1237324714Scy os_memset(drv->acct_mac, 0, ETH_ALEN); 1238324714Scy os_memset(&drv->acct_data, 0, sizeof(drv->acct_data)); 1239214501Srpaulo } 1240214501Srpaulo} 1241214501Srpaulo 1242214501Srpaulostatic void 1243252190Srpauloatheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, 1244214501Srpaulo char *custom, char *end) 1245214501Srpaulo{ 1246289284Srpaulo#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ 1247214501Srpaulo wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); 1248214501Srpaulo 1249324714Scy if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { 1250214501Srpaulo char *pos; 1251214501Srpaulo u8 addr[ETH_ALEN]; 1252324714Scy pos = os_strstr(custom, "addr="); 1253214501Srpaulo if (pos == NULL) { 1254214501Srpaulo wpa_printf(MSG_DEBUG, 1255214501Srpaulo "MLME-MICHAELMICFAILURE.indication " 1256214501Srpaulo "without sender address ignored"); 1257214501Srpaulo return; 1258214501Srpaulo } 1259214501Srpaulo pos += 5; 1260214501Srpaulo if (hwaddr_aton(pos, addr) == 0) { 1261214501Srpaulo union wpa_event_data data; 1262214501Srpaulo os_memset(&data, 0, sizeof(data)); 1263214501Srpaulo data.michael_mic_failure.unicast = 1; 1264214501Srpaulo data.michael_mic_failure.src = addr; 1265214501Srpaulo wpa_supplicant_event(drv->hapd, 1266214501Srpaulo EVENT_MICHAEL_MIC_FAILURE, &data); 1267214501Srpaulo } else { 1268214501Srpaulo wpa_printf(MSG_DEBUG, 1269214501Srpaulo "MLME-MICHAELMICFAILURE.indication " 1270214501Srpaulo "with invalid MAC address"); 1271214501Srpaulo } 1272214501Srpaulo } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { 1273214501Srpaulo char *key, *value; 1274214501Srpaulo u32 val; 1275214501Srpaulo key = custom; 1276324714Scy while ((key = os_strchr(key, '\n')) != NULL) { 1277214501Srpaulo key++; 1278324714Scy value = os_strchr(key, '='); 1279214501Srpaulo if (value == NULL) 1280214501Srpaulo continue; 1281214501Srpaulo *value++ = '\0'; 1282214501Srpaulo val = strtoul(value, NULL, 10); 1283324714Scy if (os_strcmp(key, "mac") == 0) 1284214501Srpaulo hwaddr_aton(value, drv->acct_mac); 1285324714Scy else if (os_strcmp(key, "rx_packets") == 0) 1286214501Srpaulo drv->acct_data.rx_packets = val; 1287324714Scy else if (os_strcmp(key, "tx_packets") == 0) 1288214501Srpaulo drv->acct_data.tx_packets = val; 1289324714Scy else if (os_strcmp(key, "rx_bytes") == 0) 1290214501Srpaulo drv->acct_data.rx_bytes = val; 1291324714Scy else if (os_strcmp(key, "tx_bytes") == 0) 1292214501Srpaulo drv->acct_data.tx_bytes = val; 1293214501Srpaulo key = value; 1294214501Srpaulo } 1295214501Srpaulo#ifdef CONFIG_WPS 1296324714Scy } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { 1297214501Srpaulo /* Some atheros kernels send push button as a wireless event */ 1298214501Srpaulo /* PROBLEM! this event is received for ALL BSSs ... 1299214501Srpaulo * so all are enabled for WPS... ugh. 1300214501Srpaulo */ 1301214501Srpaulo wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); 1302324714Scy } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) { 1303214501Srpaulo /* 1304214501Srpaulo * Atheros driver uses a hack to pass Probe Request frames as a 1305214501Srpaulo * binary data in the custom wireless event. The old way (using 1306214501Srpaulo * packet sniffing) didn't work when bridging. 1307214501Srpaulo * Format: "Manage.prob_req <frame len>" | zero padding | frame 1308214501Srpaulo */ 1309214501Srpaulo int len = atoi(custom + 16); 1310324714Scy if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1311214501Srpaulo wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event " 1312214501Srpaulo "length %d", len); 1313214501Srpaulo return; 1314214501Srpaulo } 1315252190Srpaulo atheros_raw_receive(drv, NULL, 1316252190Srpaulo (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1317289284Srpaulo#endif /* CONFIG_WPS */ 1318341618Scy#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1319324714Scy } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) { 1320252190Srpaulo /* Format: "Manage.assoc_req <frame len>" | zero padding | 1321252190Srpaulo * frame */ 1322252190Srpaulo int len = atoi(custom + 17); 1323324714Scy if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1324289284Srpaulo wpa_printf(MSG_DEBUG, 1325289284Srpaulo "Invalid Manage.assoc_req event length %d", 1326289284Srpaulo len); 1327252190Srpaulo return; 1328252190Srpaulo } 1329252190Srpaulo atheros_raw_receive(drv, NULL, 1330252190Srpaulo (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1331341618Scy } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { 1332289284Srpaulo /* Format: "Manage.auth <frame len>" | zero padding | frame */ 1333289284Srpaulo int len = atoi(custom + 12); 1334341618Scy if (len < 0 || 1335341618Scy MGMT_FRAM_TAG_SIZE + len > end - custom) { 1336289284Srpaulo wpa_printf(MSG_DEBUG, 1337289284Srpaulo "Invalid Manage.auth event length %d", len); 1338252190Srpaulo return; 1339252190Srpaulo } 1340252190Srpaulo atheros_raw_receive(drv, NULL, 1341252190Srpaulo (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1342341618Scy#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */ 1343289284Srpaulo#ifdef ATHEROS_USE_RAW_RECEIVE 1344341618Scy } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { 1345289284Srpaulo /* Format: "Manage.assoc_req <frame len>" | zero padding | frame 1346252190Srpaulo */ 1347289284Srpaulo int len = atoi(custom + 14); 1348324714Scy if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1349289284Srpaulo wpa_printf(MSG_DEBUG, 1350289284Srpaulo "Invalid Manage.action event length %d", 1351289284Srpaulo len); 1352252190Srpaulo return; 1353252190Srpaulo } 1354252190Srpaulo atheros_raw_receive(drv, NULL, 1355252190Srpaulo (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1356289284Srpaulo#endif /* ATHEROS_USE_RAW_RECEIVE */ 1357214501Srpaulo } 1358214501Srpaulo} 1359214501Srpaulo 1360341618Scy 1361341618Scystatic void send_action_cb_event(struct atheros_driver_data *drv, 1362341618Scy char *data, size_t data_len) 1363341618Scy{ 1364341618Scy union wpa_event_data event; 1365341618Scy struct ieee80211_send_action_cb *sa; 1366341618Scy const struct ieee80211_hdr *hdr; 1367341618Scy u16 fc; 1368341618Scy 1369341618Scy if (data_len < sizeof(*sa) + 24) { 1370341618Scy wpa_printf(MSG_DEBUG, 1371341618Scy "athr: Too short event message (data_len=%d sizeof(*sa)=%d)", 1372341618Scy (int) data_len, (int) sizeof(*sa)); 1373341618Scy wpa_hexdump(MSG_DEBUG, "athr: Short event message", 1374341618Scy data, data_len); 1375341618Scy return; 1376341618Scy } 1377341618Scy 1378341618Scy sa = (struct ieee80211_send_action_cb *) data; 1379341618Scy 1380341618Scy hdr = (const struct ieee80211_hdr *) (sa + 1); 1381341618Scy fc = le_to_host16(hdr->frame_control); 1382341618Scy 1383341618Scy os_memset(&event, 0, sizeof(event)); 1384341618Scy event.tx_status.type = WLAN_FC_GET_TYPE(fc); 1385341618Scy event.tx_status.stype = WLAN_FC_GET_STYPE(fc); 1386341618Scy event.tx_status.dst = sa->dst_addr; 1387341618Scy event.tx_status.data = (const u8 *) hdr; 1388341618Scy event.tx_status.data_len = data_len - sizeof(*sa); 1389341618Scy event.tx_status.ack = sa->ack; 1390341618Scy wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event); 1391341618Scy} 1392341618Scy 1393341618Scy 1394252190Srpaulo/* 1395252190Srpaulo* Handle size of data problem. WEXT only allows data of 256 bytes for custom 1396252190Srpaulo* events, and p2p data can be much bigger. So the athr driver sends a small 1397252190Srpaulo* event telling me to collect the big data with an ioctl. 1398252190Srpaulo* On the first event, send all pending events to supplicant. 1399252190Srpaulo*/ 1400252190Srpaulostatic void fetch_pending_big_events(struct atheros_driver_data *drv) 1401252190Srpaulo{ 1402252190Srpaulo union wpa_event_data event; 1403252190Srpaulo const struct ieee80211_mgmt *mgmt; 1404252190Srpaulo u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */ 1405252190Srpaulo u16 fc, stype; 1406252190Srpaulo struct iwreq iwr; 1407252190Srpaulo size_t data_len; 1408252190Srpaulo u32 freq, frame_type; 1409252190Srpaulo 1410252190Srpaulo while (1) { 1411252190Srpaulo os_memset(&iwr, 0, sizeof(iwr)); 1412281681Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1413252190Srpaulo 1414252190Srpaulo iwr.u.data.pointer = (void *) tbuf; 1415252190Srpaulo iwr.u.data.length = sizeof(tbuf); 1416252190Srpaulo iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME; 1417252190Srpaulo 1418252190Srpaulo if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) 1419252190Srpaulo < 0) { 1420252190Srpaulo if (errno == ENOSPC) { 1421252190Srpaulo wpa_printf(MSG_DEBUG, "%s:%d exit", 1422252190Srpaulo __func__, __LINE__); 1423252190Srpaulo return; 1424252190Srpaulo } 1425252190Srpaulo wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM[" 1426252190Srpaulo "P2P_FETCH_FRAME] failed: %s", 1427252190Srpaulo __func__, strerror(errno)); 1428252190Srpaulo return; 1429252190Srpaulo } 1430252190Srpaulo data_len = iwr.u.data.length; 1431252190Srpaulo wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data", 1432252190Srpaulo (u8 *) tbuf, data_len); 1433252190Srpaulo if (data_len < sizeof(freq) + sizeof(frame_type) + 24) { 1434252190Srpaulo wpa_printf(MSG_DEBUG, "athr: frame too short"); 1435252190Srpaulo continue; 1436252190Srpaulo } 1437252190Srpaulo os_memcpy(&freq, tbuf, sizeof(freq)); 1438252190Srpaulo os_memcpy(&frame_type, &tbuf[sizeof(freq)], 1439252190Srpaulo sizeof(frame_type)); 1440252190Srpaulo mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)]; 1441252190Srpaulo data_len -= sizeof(freq) + sizeof(frame_type); 1442252190Srpaulo 1443252190Srpaulo if (frame_type == IEEE80211_EV_RX_MGMT) { 1444252190Srpaulo fc = le_to_host16(mgmt->frame_control); 1445252190Srpaulo stype = WLAN_FC_GET_STYPE(fc); 1446252190Srpaulo 1447252190Srpaulo wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u " 1448252190Srpaulo "freq=%u len=%u", stype, freq, (int) data_len); 1449252190Srpaulo 1450252190Srpaulo if (stype == WLAN_FC_STYPE_ACTION) { 1451252190Srpaulo os_memset(&event, 0, sizeof(event)); 1452252190Srpaulo event.rx_mgmt.frame = (const u8 *) mgmt; 1453252190Srpaulo event.rx_mgmt.frame_len = data_len; 1454252190Srpaulo wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, 1455252190Srpaulo &event); 1456252190Srpaulo continue; 1457252190Srpaulo } 1458341618Scy } else if (frame_type == IEEE80211_EV_P2P_SEND_ACTION_CB) { 1459341618Scy wpa_printf(MSG_DEBUG, 1460341618Scy "%s: ACTION_CB frame_type=%u len=%zu", 1461341618Scy __func__, frame_type, data_len); 1462341618Scy send_action_cb_event(drv, (void *) mgmt, data_len); 1463252190Srpaulo } else { 1464252190Srpaulo wpa_printf(MSG_DEBUG, "athr: %s unknown type %d", 1465252190Srpaulo __func__, frame_type); 1466252190Srpaulo continue; 1467252190Srpaulo } 1468252190Srpaulo } 1469252190Srpaulo} 1470252190Srpaulo 1471214501Srpaulostatic void 1472252190Srpauloatheros_wireless_event_atheros_custom(struct atheros_driver_data *drv, 1473252190Srpaulo int opcode, char *buf, int len) 1474252190Srpaulo{ 1475252190Srpaulo switch (opcode) { 1476341618Scy case IEEE80211_EV_P2P_SEND_ACTION_CB: 1477341618Scy wpa_printf(MSG_DEBUG, "WEXT: EV_P2P_SEND_ACTION_CB"); 1478341618Scy fetch_pending_big_events(drv); 1479341618Scy break; 1480252190Srpaulo case IEEE80211_EV_RX_MGMT: 1481252190Srpaulo wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT"); 1482252190Srpaulo fetch_pending_big_events(drv); 1483252190Srpaulo break; 1484252190Srpaulo default: 1485252190Srpaulo break; 1486252190Srpaulo } 1487252190Srpaulo} 1488252190Srpaulo 1489252190Srpaulostatic void 1490252190Srpauloatheros_wireless_event_wireless(struct atheros_driver_data *drv, 1491324714Scy char *data, unsigned int len) 1492214501Srpaulo{ 1493214501Srpaulo struct iw_event iwe_buf, *iwe = &iwe_buf; 1494214501Srpaulo char *pos, *end, *custom, *buf; 1495214501Srpaulo 1496214501Srpaulo pos = data; 1497214501Srpaulo end = data + len; 1498214501Srpaulo 1499324714Scy while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { 1500214501Srpaulo /* Event data may be unaligned, so make a local, aligned copy 1501214501Srpaulo * before processing. */ 1502324714Scy os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); 1503214501Srpaulo wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", 1504214501Srpaulo iwe->cmd, iwe->len); 1505324714Scy if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) 1506214501Srpaulo return; 1507214501Srpaulo 1508214501Srpaulo custom = pos + IW_EV_POINT_LEN; 1509214501Srpaulo if (drv->we_version > 18 && 1510214501Srpaulo (iwe->cmd == IWEVMICHAELMICFAILURE || 1511214501Srpaulo iwe->cmd == IWEVASSOCREQIE || 1512214501Srpaulo iwe->cmd == IWEVCUSTOM)) { 1513214501Srpaulo /* WE-19 removed the pointer from struct iw_point */ 1514214501Srpaulo char *dpos = (char *) &iwe_buf.u.data.length; 1515214501Srpaulo int dlen = dpos - (char *) &iwe_buf; 1516324714Scy os_memcpy(dpos, pos + IW_EV_LCP_LEN, 1517324714Scy sizeof(struct iw_event) - dlen); 1518214501Srpaulo } else { 1519324714Scy os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); 1520214501Srpaulo custom += IW_EV_POINT_OFF; 1521214501Srpaulo } 1522214501Srpaulo 1523214501Srpaulo switch (iwe->cmd) { 1524214501Srpaulo case IWEVEXPIRED: 1525214501Srpaulo drv_event_disassoc(drv->hapd, 1526214501Srpaulo (u8 *) iwe->u.addr.sa_data); 1527214501Srpaulo break; 1528214501Srpaulo case IWEVREGISTERED: 1529252190Srpaulo atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data); 1530214501Srpaulo break; 1531214501Srpaulo case IWEVASSOCREQIE: 1532214501Srpaulo /* Driver hack.. Use IWEVASSOCREQIE to bypass 1533214501Srpaulo * IWEVCUSTOM size limitations. Need to handle this 1534214501Srpaulo * just like IWEVCUSTOM. 1535214501Srpaulo */ 1536214501Srpaulo case IWEVCUSTOM: 1537324714Scy if (iwe->u.data.length > end - custom) 1538214501Srpaulo return; 1539324714Scy buf = os_malloc(iwe->u.data.length + 1); 1540214501Srpaulo if (buf == NULL) 1541214501Srpaulo return; /* XXX */ 1542324714Scy os_memcpy(buf, custom, iwe->u.data.length); 1543214501Srpaulo buf[iwe->u.data.length] = '\0'; 1544252190Srpaulo 1545252190Srpaulo if (iwe->u.data.flags != 0) { 1546252190Srpaulo atheros_wireless_event_atheros_custom( 1547252190Srpaulo drv, (int) iwe->u.data.flags, 1548252190Srpaulo buf, len); 1549252190Srpaulo } else { 1550252190Srpaulo atheros_wireless_event_wireless_custom( 1551252190Srpaulo drv, buf, buf + iwe->u.data.length); 1552252190Srpaulo } 1553324714Scy os_free(buf); 1554214501Srpaulo break; 1555214501Srpaulo } 1556214501Srpaulo 1557214501Srpaulo pos += iwe->len; 1558214501Srpaulo } 1559214501Srpaulo} 1560214501Srpaulo 1561214501Srpaulo 1562214501Srpaulostatic void 1563252190Srpauloatheros_wireless_event_rtm_newlink(void *ctx, 1564214501Srpaulo struct ifinfomsg *ifi, u8 *buf, size_t len) 1565214501Srpaulo{ 1566252190Srpaulo struct atheros_driver_data *drv = ctx; 1567214501Srpaulo int attrlen, rta_len; 1568214501Srpaulo struct rtattr *attr; 1569214501Srpaulo 1570214501Srpaulo if (ifi->ifi_index != drv->ifindex) 1571214501Srpaulo return; 1572214501Srpaulo 1573214501Srpaulo attrlen = len; 1574214501Srpaulo attr = (struct rtattr *) buf; 1575214501Srpaulo 1576214501Srpaulo rta_len = RTA_ALIGN(sizeof(struct rtattr)); 1577214501Srpaulo while (RTA_OK(attr, attrlen)) { 1578214501Srpaulo if (attr->rta_type == IFLA_WIRELESS) { 1579252190Srpaulo atheros_wireless_event_wireless( 1580214501Srpaulo drv, ((char *) attr) + rta_len, 1581214501Srpaulo attr->rta_len - rta_len); 1582214501Srpaulo } 1583214501Srpaulo attr = RTA_NEXT(attr, attrlen); 1584214501Srpaulo } 1585214501Srpaulo} 1586214501Srpaulo 1587214501Srpaulo 1588214501Srpaulostatic int 1589252190Srpauloatheros_get_we_version(struct atheros_driver_data *drv) 1590214501Srpaulo{ 1591214501Srpaulo struct iw_range *range; 1592214501Srpaulo struct iwreq iwr; 1593214501Srpaulo int minlen; 1594214501Srpaulo size_t buflen; 1595214501Srpaulo 1596214501Srpaulo drv->we_version = 0; 1597214501Srpaulo 1598214501Srpaulo /* 1599214501Srpaulo * Use larger buffer than struct iw_range in order to allow the 1600214501Srpaulo * structure to grow in the future. 1601214501Srpaulo */ 1602214501Srpaulo buflen = sizeof(struct iw_range) + 500; 1603214501Srpaulo range = os_zalloc(buflen); 1604214501Srpaulo if (range == NULL) 1605214501Srpaulo return -1; 1606214501Srpaulo 1607324714Scy os_memset(&iwr, 0, sizeof(iwr)); 1608214501Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1609214501Srpaulo iwr.u.data.pointer = (caddr_t) range; 1610214501Srpaulo iwr.u.data.length = buflen; 1611214501Srpaulo 1612214501Srpaulo minlen = ((char *) &range->enc_capa) - (char *) range + 1613214501Srpaulo sizeof(range->enc_capa); 1614214501Srpaulo 1615214501Srpaulo if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { 1616281681Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", 1617281681Srpaulo strerror(errno)); 1618281681Srpaulo os_free(range); 1619214501Srpaulo return -1; 1620214501Srpaulo } else if (iwr.u.data.length >= minlen && 1621214501Srpaulo range->we_version_compiled >= 18) { 1622214501Srpaulo wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " 1623214501Srpaulo "WE(source)=%d enc_capa=0x%x", 1624214501Srpaulo range->we_version_compiled, 1625214501Srpaulo range->we_version_source, 1626214501Srpaulo range->enc_capa); 1627214501Srpaulo drv->we_version = range->we_version_compiled; 1628214501Srpaulo } 1629214501Srpaulo 1630252190Srpaulo os_free(range); 1631214501Srpaulo return 0; 1632214501Srpaulo} 1633214501Srpaulo 1634214501Srpaulo 1635214501Srpaulostatic int 1636252190Srpauloatheros_wireless_event_init(struct atheros_driver_data *drv) 1637214501Srpaulo{ 1638214501Srpaulo struct netlink_config *cfg; 1639214501Srpaulo 1640252190Srpaulo atheros_get_we_version(drv); 1641214501Srpaulo 1642214501Srpaulo cfg = os_zalloc(sizeof(*cfg)); 1643214501Srpaulo if (cfg == NULL) 1644214501Srpaulo return -1; 1645214501Srpaulo cfg->ctx = drv; 1646252190Srpaulo cfg->newlink_cb = atheros_wireless_event_rtm_newlink; 1647214501Srpaulo drv->netlink = netlink_init(cfg); 1648214501Srpaulo if (drv->netlink == NULL) { 1649214501Srpaulo os_free(cfg); 1650214501Srpaulo return -1; 1651214501Srpaulo } 1652214501Srpaulo 1653214501Srpaulo return 0; 1654214501Srpaulo} 1655214501Srpaulo 1656214501Srpaulo 1657214501Srpaulostatic int 1658252190Srpauloatheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, 1659252190Srpaulo int encrypt, const u8 *own_addr, u32 flags) 1660214501Srpaulo{ 1661252190Srpaulo struct atheros_driver_data *drv = priv; 1662214501Srpaulo unsigned char buf[3000]; 1663214501Srpaulo unsigned char *bp = buf; 1664214501Srpaulo struct l2_ethhdr *eth; 1665214501Srpaulo size_t len; 1666214501Srpaulo int status; 1667214501Srpaulo 1668214501Srpaulo /* 1669214501Srpaulo * Prepend the Ethernet header. If the caller left us 1670214501Srpaulo * space at the front we could just insert it but since 1671214501Srpaulo * we don't know we copy to a local buffer. Given the frequency 1672214501Srpaulo * and size of frames this probably doesn't matter. 1673214501Srpaulo */ 1674214501Srpaulo len = data_len + sizeof(struct l2_ethhdr); 1675214501Srpaulo if (len > sizeof(buf)) { 1676324714Scy bp = os_malloc(len); 1677214501Srpaulo if (bp == NULL) { 1678281681Srpaulo wpa_printf(MSG_INFO, 1679281681Srpaulo "EAPOL frame discarded, cannot malloc temp buffer of size %lu!", 1680281681Srpaulo (unsigned long) len); 1681214501Srpaulo return -1; 1682214501Srpaulo } 1683214501Srpaulo } 1684214501Srpaulo eth = (struct l2_ethhdr *) bp; 1685324714Scy os_memcpy(eth->h_dest, addr, ETH_ALEN); 1686324714Scy os_memcpy(eth->h_source, own_addr, ETH_ALEN); 1687214501Srpaulo eth->h_proto = host_to_be16(ETH_P_EAPOL); 1688324714Scy os_memcpy(eth + 1, data, data_len); 1689214501Srpaulo 1690214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); 1691214501Srpaulo 1692214501Srpaulo status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); 1693214501Srpaulo 1694214501Srpaulo if (bp != buf) 1695324714Scy os_free(bp); 1696214501Srpaulo return status; 1697214501Srpaulo} 1698214501Srpaulo 1699214501Srpaulostatic void 1700214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 1701214501Srpaulo{ 1702252190Srpaulo struct atheros_driver_data *drv = ctx; 1703214501Srpaulo drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), 1704214501Srpaulo len - sizeof(struct l2_ethhdr)); 1705214501Srpaulo} 1706214501Srpaulo 1707341618Scy 1708341618Scystatic void atheros_read_fils_cap(struct atheros_driver_data *drv) 1709341618Scy{ 1710341618Scy int fils = 0; 1711341618Scy 1712341618Scy#ifdef CONFIG_FILS 1713341618Scy /* TODO: Would be better to have #ifdef on the IEEE80211_PARAM_* value 1714341618Scy * to automatically check this against the driver header files. */ 1715341618Scy if (get80211param(drv, IEEE80211_PARAM_ENABLE_FILS, &fils) < 0) { 1716341618Scy wpa_printf(MSG_DEBUG, 1717341618Scy "%s: Failed to get FILS capability from driver", 1718341618Scy __func__); 1719341618Scy /* Assume driver does not support FILS */ 1720341618Scy fils = 0; 1721341618Scy } 1722341618Scy#endif /* CONFIG_FILS */ 1723341618Scy drv->fils_en = fils; 1724341618Scy wpa_printf(MSG_DEBUG, "atheros: fils_en=%d", drv->fils_en); 1725341618Scy} 1726341618Scy 1727341618Scy 1728214501Srpaulostatic void * 1729252190Srpauloatheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) 1730214501Srpaulo{ 1731252190Srpaulo struct atheros_driver_data *drv; 1732214501Srpaulo struct ifreq ifr; 1733214501Srpaulo struct iwreq iwr; 1734214501Srpaulo char brname[IFNAMSIZ]; 1735214501Srpaulo 1736252190Srpaulo drv = os_zalloc(sizeof(struct atheros_driver_data)); 1737214501Srpaulo if (drv == NULL) { 1738281681Srpaulo wpa_printf(MSG_INFO, 1739281681Srpaulo "Could not allocate memory for atheros driver data"); 1740214501Srpaulo return NULL; 1741214501Srpaulo } 1742214501Srpaulo 1743214501Srpaulo drv->hapd = hapd; 1744214501Srpaulo drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); 1745214501Srpaulo if (drv->ioctl_sock < 0) { 1746281681Srpaulo wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", 1747281681Srpaulo strerror(errno)); 1748214501Srpaulo goto bad; 1749214501Srpaulo } 1750324714Scy os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); 1751214501Srpaulo 1752324714Scy os_memset(&ifr, 0, sizeof(ifr)); 1753214501Srpaulo os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); 1754214501Srpaulo if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { 1755281681Srpaulo wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", 1756281681Srpaulo strerror(errno)); 1757214501Srpaulo goto bad; 1758214501Srpaulo } 1759214501Srpaulo drv->ifindex = ifr.ifr_ifindex; 1760214501Srpaulo 1761214501Srpaulo drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, 1762214501Srpaulo handle_read, drv, 1); 1763214501Srpaulo if (drv->sock_xmit == NULL) 1764214501Srpaulo goto bad; 1765214501Srpaulo if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) 1766214501Srpaulo goto bad; 1767252190Srpaulo os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN); 1768214501Srpaulo if (params->bridge[0]) { 1769214501Srpaulo wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", 1770214501Srpaulo params->bridge[0]); 1771214501Srpaulo drv->sock_recv = l2_packet_init(params->bridge[0], NULL, 1772214501Srpaulo ETH_P_EAPOL, handle_read, drv, 1773214501Srpaulo 1); 1774214501Srpaulo if (drv->sock_recv == NULL) 1775214501Srpaulo goto bad; 1776214501Srpaulo } else if (linux_br_get(brname, drv->iface) == 0) { 1777214501Srpaulo wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " 1778214501Srpaulo "EAPOL receive", brname); 1779214501Srpaulo drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, 1780214501Srpaulo handle_read, drv, 1); 1781214501Srpaulo if (drv->sock_recv == NULL) 1782214501Srpaulo goto bad; 1783214501Srpaulo } else 1784214501Srpaulo drv->sock_recv = drv->sock_xmit; 1785214501Srpaulo 1786324714Scy os_memset(&iwr, 0, sizeof(iwr)); 1787214501Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1788214501Srpaulo 1789214501Srpaulo iwr.u.mode = IW_MODE_MASTER; 1790214501Srpaulo 1791214501Srpaulo if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { 1792281681Srpaulo wpa_printf(MSG_ERROR, 1793281681Srpaulo "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s", 1794281681Srpaulo strerror(errno)); 1795214501Srpaulo goto bad; 1796214501Srpaulo } 1797214501Srpaulo 1798214501Srpaulo /* mark down during setup */ 1799214501Srpaulo linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); 1800252190Srpaulo atheros_set_privacy(drv, 0); /* default to no privacy */ 1801214501Srpaulo 1802252190Srpaulo if (atheros_receive_pkt(drv)) 1803252190Srpaulo goto bad; 1804214501Srpaulo 1805252190Srpaulo if (atheros_wireless_event_init(drv)) 1806214501Srpaulo goto bad; 1807214501Srpaulo 1808341618Scy /* Read FILS capability from the driver */ 1809341618Scy atheros_read_fils_cap(drv); 1810341618Scy 1811214501Srpaulo return drv; 1812214501Srpaulobad: 1813252190Srpaulo atheros_reset_appfilter(drv); 1814252190Srpaulo if (drv->sock_raw) 1815252190Srpaulo l2_packet_deinit(drv->sock_raw); 1816214501Srpaulo if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) 1817214501Srpaulo l2_packet_deinit(drv->sock_recv); 1818214501Srpaulo if (drv->sock_xmit != NULL) 1819214501Srpaulo l2_packet_deinit(drv->sock_xmit); 1820214501Srpaulo if (drv->ioctl_sock >= 0) 1821214501Srpaulo close(drv->ioctl_sock); 1822289284Srpaulo os_free(drv); 1823214501Srpaulo return NULL; 1824214501Srpaulo} 1825214501Srpaulo 1826214501Srpaulo 1827214501Srpaulostatic void 1828252190Srpauloatheros_deinit(void *priv) 1829214501Srpaulo{ 1830252190Srpaulo struct atheros_driver_data *drv = priv; 1831214501Srpaulo 1832252190Srpaulo atheros_reset_appfilter(drv); 1833289284Srpaulo 1834289284Srpaulo if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) { 1835324714Scy atheros_set_opt_ie(priv, NULL, 0); 1836289284Srpaulo wpabuf_free(drv->wpa_ie); 1837289284Srpaulo wpabuf_free(drv->wps_beacon_ie); 1838289284Srpaulo wpabuf_free(drv->wps_probe_resp_ie); 1839289284Srpaulo } 1840214501Srpaulo netlink_deinit(drv->netlink); 1841214501Srpaulo (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); 1842214501Srpaulo if (drv->ioctl_sock >= 0) 1843214501Srpaulo close(drv->ioctl_sock); 1844214501Srpaulo if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) 1845214501Srpaulo l2_packet_deinit(drv->sock_recv); 1846214501Srpaulo if (drv->sock_xmit != NULL) 1847214501Srpaulo l2_packet_deinit(drv->sock_xmit); 1848214501Srpaulo if (drv->sock_raw) 1849214501Srpaulo l2_packet_deinit(drv->sock_raw); 1850289284Srpaulo os_free(drv); 1851214501Srpaulo} 1852214501Srpaulo 1853214501Srpaulostatic int 1854252190Srpauloatheros_set_ssid(void *priv, const u8 *buf, int len) 1855214501Srpaulo{ 1856252190Srpaulo struct atheros_driver_data *drv = priv; 1857214501Srpaulo struct iwreq iwr; 1858214501Srpaulo 1859324714Scy os_memset(&iwr, 0, sizeof(iwr)); 1860214501Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1861214501Srpaulo iwr.u.essid.flags = 1; /* SSID active */ 1862214501Srpaulo iwr.u.essid.pointer = (caddr_t) buf; 1863341618Scy iwr.u.essid.length = len; 1864214501Srpaulo 1865214501Srpaulo if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { 1866281681Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s", 1867281681Srpaulo len, strerror(errno)); 1868214501Srpaulo return -1; 1869214501Srpaulo } 1870214501Srpaulo return 0; 1871214501Srpaulo} 1872214501Srpaulo 1873214501Srpaulostatic int 1874252190Srpauloatheros_get_ssid(void *priv, u8 *buf, int len) 1875214501Srpaulo{ 1876252190Srpaulo struct atheros_driver_data *drv = priv; 1877214501Srpaulo struct iwreq iwr; 1878214501Srpaulo int ret = 0; 1879214501Srpaulo 1880324714Scy os_memset(&iwr, 0, sizeof(iwr)); 1881214501Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1882214501Srpaulo iwr.u.essid.pointer = (caddr_t) buf; 1883252190Srpaulo iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? 1884252190Srpaulo IW_ESSID_MAX_SIZE : len; 1885214501Srpaulo 1886214501Srpaulo if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { 1887281681Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", 1888281681Srpaulo strerror(errno)); 1889214501Srpaulo ret = -1; 1890214501Srpaulo } else 1891214501Srpaulo ret = iwr.u.essid.length; 1892214501Srpaulo 1893214501Srpaulo return ret; 1894214501Srpaulo} 1895214501Srpaulo 1896214501Srpaulostatic int 1897252190Srpauloatheros_set_countermeasures(void *priv, int enabled) 1898214501Srpaulo{ 1899252190Srpaulo struct atheros_driver_data *drv = priv; 1900214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 1901214501Srpaulo return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); 1902214501Srpaulo} 1903214501Srpaulo 1904214501Srpaulostatic int 1905252190Srpauloatheros_commit(void *priv) 1906214501Srpaulo{ 1907252190Srpaulo struct atheros_driver_data *drv = priv; 1908214501Srpaulo return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); 1909214501Srpaulo} 1910214501Srpaulo 1911252190Srpaulostatic int atheros_set_authmode(void *priv, int auth_algs) 1912252190Srpaulo{ 1913252190Srpaulo int authmode; 1914252190Srpaulo 1915252190Srpaulo if ((auth_algs & WPA_AUTH_ALG_OPEN) && 1916252190Srpaulo (auth_algs & WPA_AUTH_ALG_SHARED)) 1917252190Srpaulo authmode = IEEE80211_AUTH_AUTO; 1918252190Srpaulo else if (auth_algs & WPA_AUTH_ALG_OPEN) 1919252190Srpaulo authmode = IEEE80211_AUTH_OPEN; 1920252190Srpaulo else if (auth_algs & WPA_AUTH_ALG_SHARED) 1921252190Srpaulo authmode = IEEE80211_AUTH_SHARED; 1922252190Srpaulo else 1923252190Srpaulo return -1; 1924252190Srpaulo 1925252190Srpaulo return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode); 1926252190Srpaulo} 1927252190Srpaulo 1928252190Srpaulostatic int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) 1929252190Srpaulo{ 1930252190Srpaulo /* 1931252190Srpaulo * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x, 1932252190Srpaulo * set_generic_elem, and hapd_set_ssid. 1933252190Srpaulo */ 1934252190Srpaulo 1935252190Srpaulo wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x " 1936252190Srpaulo "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x " 1937252190Srpaulo "wpa_version=0x%x privacy=%d interworking=%d", 1938252190Srpaulo params->pairwise_ciphers, params->group_cipher, 1939252190Srpaulo params->key_mgmt_suites, params->auth_algs, 1940252190Srpaulo params->wpa_version, params->privacy, params->interworking); 1941252190Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID", 1942252190Srpaulo params->ssid, params->ssid_len); 1943252190Srpaulo if (params->hessid) 1944252190Srpaulo wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR, 1945252190Srpaulo MAC2STR(params->hessid)); 1946252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies", 1947252190Srpaulo params->beacon_ies); 1948252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies", 1949252190Srpaulo params->proberesp_ies); 1950252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", 1951252190Srpaulo params->assocresp_ies); 1952252190Srpaulo 1953281681Srpaulo#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN)) 1954281681Srpaulo if (params->osen) { 1955281681Srpaulo struct wpa_bss_params bss_params; 1956281681Srpaulo 1957281681Srpaulo os_memset(&bss_params, 0, sizeof(struct wpa_bss_params)); 1958281681Srpaulo bss_params.enabled = 1; 1959281681Srpaulo bss_params.wpa = 2; 1960281681Srpaulo bss_params.wpa_pairwise = WPA_CIPHER_CCMP; 1961281681Srpaulo bss_params.wpa_group = WPA_CIPHER_CCMP; 1962281681Srpaulo bss_params.ieee802_1x = 1; 1963281681Srpaulo 1964281681Srpaulo if (atheros_set_privacy(priv, 1) || 1965281681Srpaulo set80211param(priv, IEEE80211_PARAM_OSEN, 1)) 1966281681Srpaulo return -1; 1967281681Srpaulo 1968281681Srpaulo return atheros_set_ieee8021x(priv, &bss_params); 1969281681Srpaulo } 1970281681Srpaulo#endif /* CONFIG_HS20 && IEEE80211_PARAM_OSEN */ 1971281681Srpaulo 1972252190Srpaulo return 0; 1973252190Srpaulo} 1974252190Srpaulo 1975252190Srpaulo 1976341618Scy#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1977252190Srpaulo 1978252190Srpaulostatic int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, 1979324714Scy int noack, unsigned int freq, 1980324714Scy const u16 *csa_offs, size_t csa_offs_len) 1981252190Srpaulo{ 1982252190Srpaulo struct atheros_driver_data *drv = priv; 1983252190Srpaulo u8 buf[1510]; 1984252190Srpaulo const struct ieee80211_mgmt *mgmt; 1985252190Srpaulo struct ieee80211req_mgmtbuf *mgmt_frm; 1986252190Srpaulo 1987252190Srpaulo mgmt = (const struct ieee80211_mgmt *) frm; 1988252190Srpaulo wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__, 1989252190Srpaulo (unsigned long) data_len, MAC2STR(mgmt->da)); 1990252190Srpaulo mgmt_frm = (struct ieee80211req_mgmtbuf *) buf; 1991324714Scy os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); 1992252190Srpaulo mgmt_frm->buflen = data_len; 1993252190Srpaulo if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) { 1994252190Srpaulo wpa_printf(MSG_INFO, "atheros: Too long frame for " 1995252190Srpaulo "atheros_send_mgmt (%u)", (unsigned int) data_len); 1996252190Srpaulo return -1; 1997252190Srpaulo } 1998252190Srpaulo os_memcpy(&mgmt_frm->buf[0], frm, data_len); 1999252190Srpaulo return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm, 2000252190Srpaulo sizeof(struct ieee80211req_mgmtbuf) + data_len); 2001252190Srpaulo} 2002341618Scy#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 2003252190Srpaulo 2004252190Srpaulo 2005289284Srpaulo#ifdef CONFIG_IEEE80211R 2006289284Srpaulo 2007252190Srpaulostatic int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie, 2008252190Srpaulo size_t tspec_ielen) 2009252190Srpaulo{ 2010252190Srpaulo struct atheros_driver_data *drv = priv; 2011252190Srpaulo int retv; 2012252190Srpaulo struct ieee80211req_res req; 2013252190Srpaulo struct ieee80211req_res_addts *addts = &req.u.addts; 2014252190Srpaulo 2015252190Srpaulo wpa_printf(MSG_DEBUG, "%s", __func__); 2016252190Srpaulo req.type = IEEE80211_RESREQ_ADDTS; 2017252190Srpaulo os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); 2018252190Srpaulo os_memcpy(addts->tspecie, tspec_ie, tspec_ielen); 2019252190Srpaulo retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, 2020252190Srpaulo sizeof(struct ieee80211req_res)); 2021252190Srpaulo if (retv < 0) { 2022252190Srpaulo wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED " 2023252190Srpaulo "retv = %d", __func__, retv); 2024252190Srpaulo return -1; 2025252190Srpaulo } 2026252190Srpaulo os_memcpy(tspec_ie, addts->tspecie, tspec_ielen); 2027252190Srpaulo return addts->status; 2028252190Srpaulo} 2029252190Srpaulo 2030252190Srpaulo 2031252190Srpaulostatic int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg) 2032252190Srpaulo{ 2033252190Srpaulo struct atheros_driver_data *drv = priv; 2034252190Srpaulo struct ieee80211req_res req; 2035252190Srpaulo struct ieee80211req_res_addnode *addnode = &req.u.addnode; 2036252190Srpaulo 2037252190Srpaulo wpa_printf(MSG_DEBUG, "%s", __func__); 2038252190Srpaulo req.type = IEEE80211_RESREQ_ADDNODE; 2039252190Srpaulo os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); 2040252190Srpaulo addnode->auth_alg = auth_alg; 2041252190Srpaulo return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, 2042252190Srpaulo sizeof(struct ieee80211req_res)); 2043252190Srpaulo} 2044252190Srpaulo 2045252190Srpaulo#endif /* CONFIG_IEEE80211R */ 2046252190Srpaulo 2047252190Srpaulo 2048252190Srpaulo/* Use only to set a big param, get will not work. */ 2049252190Srpaulostatic int 2050252190Srpauloset80211big(struct atheros_driver_data *drv, int op, const void *data, int len) 2051252190Srpaulo{ 2052252190Srpaulo struct iwreq iwr; 2053252190Srpaulo 2054252190Srpaulo os_memset(&iwr, 0, sizeof(iwr)); 2055252190Srpaulo os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 2056252190Srpaulo 2057252190Srpaulo iwr.u.data.pointer = (void *) data; 2058252190Srpaulo iwr.u.data.length = len; 2059252190Srpaulo iwr.u.data.flags = op; 2060252190Srpaulo wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x", 2061252190Srpaulo __func__, op, op, athr_get_param_name(op), len); 2062252190Srpaulo 2063252190Srpaulo if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) { 2064252190Srpaulo wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d " 2065252190Srpaulo "value=0x%x,0x%x failed: %d (%s)", 2066252190Srpaulo __func__, op, athr_get_ioctl_name(op), iwr.u.mode, 2067252190Srpaulo iwr.u.mode, iwr.u.data.length, 2068252190Srpaulo iwr.u.data.flags, errno, strerror(errno)); 2069252190Srpaulo return -1; 2070252190Srpaulo } 2071252190Srpaulo return 0; 2072252190Srpaulo} 2073252190Srpaulo 2074252190Srpaulo 2075252190Srpaulostatic int atheros_send_action(void *priv, unsigned int freq, 2076252190Srpaulo unsigned int wait, 2077252190Srpaulo const u8 *dst, const u8 *src, 2078252190Srpaulo const u8 *bssid, 2079252190Srpaulo const u8 *data, size_t data_len, int no_cck) 2080252190Srpaulo{ 2081252190Srpaulo struct atheros_driver_data *drv = priv; 2082252190Srpaulo struct ieee80211_p2p_send_action *act; 2083252190Srpaulo int res; 2084252190Srpaulo 2085252190Srpaulo act = os_zalloc(sizeof(*act) + data_len); 2086252190Srpaulo if (act == NULL) 2087252190Srpaulo return -1; 2088252190Srpaulo act->freq = freq; 2089252190Srpaulo os_memcpy(act->dst_addr, dst, ETH_ALEN); 2090252190Srpaulo os_memcpy(act->src_addr, src, ETH_ALEN); 2091252190Srpaulo os_memcpy(act->bssid, bssid, ETH_ALEN); 2092252190Srpaulo os_memcpy(act + 1, data, data_len); 2093252190Srpaulo wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src=" 2094252190Srpaulo MACSTR ", bssid=" MACSTR, 2095252190Srpaulo __func__, act->freq, wait, MAC2STR(act->dst_addr), 2096252190Srpaulo MAC2STR(act->src_addr), MAC2STR(act->bssid)); 2097252190Srpaulo wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act)); 2098252190Srpaulo wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len); 2099252190Srpaulo 2100252190Srpaulo res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION, 2101252190Srpaulo act, sizeof(*act) + data_len); 2102252190Srpaulo os_free(act); 2103252190Srpaulo return res; 2104252190Srpaulo} 2105252190Srpaulo 2106252190Srpaulo 2107281681Srpaulo#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) 2108252190Srpaulostatic int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer, 2109252190Srpaulo u8 *ie, u16 *len, enum wnm_oper oper) 2110252190Srpaulo{ 2111252190Srpaulo#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */ 2112252190Srpaulo u8 buf[IEEE80211_APPIE_MAX]; 2113252190Srpaulo struct ieee80211req_getset_appiebuf *tfs_ie; 2114252190Srpaulo u16 val; 2115252190Srpaulo 2116252190Srpaulo wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR, 2117252190Srpaulo drv->iface, oper, MAC2STR(peer)); 2118252190Srpaulo 2119252190Srpaulo switch (oper) { 2120252190Srpaulo case WNM_SLEEP_TFS_REQ_IE_SET: 2121252190Srpaulo if (*len > IEEE80211_APPIE_MAX - 2122252190Srpaulo sizeof(struct ieee80211req_getset_appiebuf)) { 2123252190Srpaulo wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large"); 2124252190Srpaulo return -1; 2125252190Srpaulo } 2126252190Srpaulo tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2127252190Srpaulo tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2128252190Srpaulo tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len; 2129252190Srpaulo 2130252190Srpaulo /* Command header for driver */ 2131252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2132252190Srpaulo val = oper; 2133252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2134252190Srpaulo val = *len; 2135252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2136252190Srpaulo 2137252190Srpaulo /* copy the ie */ 2138252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len); 2139252190Srpaulo 2140252190Srpaulo if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, 2141252190Srpaulo IEEE80211_APPIE_MAX)) { 2142252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " 2143252190Srpaulo "%s", __func__, strerror(errno)); 2144252190Srpaulo return -1; 2145252190Srpaulo } 2146252190Srpaulo break; 2147252190Srpaulo case WNM_SLEEP_TFS_RESP_IE_ADD: 2148252190Srpaulo tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2149252190Srpaulo tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2150252190Srpaulo tfs_ie->app_buflen = IEEE80211_APPIE_MAX - 2151252190Srpaulo sizeof(struct ieee80211req_getset_appiebuf); 2152252190Srpaulo /* Command header for driver */ 2153252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2154252190Srpaulo val = oper; 2155252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2156252190Srpaulo val = 0; 2157252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2158252190Srpaulo 2159252190Srpaulo if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie, 2160252190Srpaulo IEEE80211_APPIE_MAX)) { 2161252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: " 2162252190Srpaulo "%s", __func__, strerror(errno)); 2163252190Srpaulo return -1; 2164252190Srpaulo } 2165252190Srpaulo 2166252190Srpaulo *len = tfs_ie->app_buflen; 2167252190Srpaulo os_memcpy(ie, &(tfs_ie->app_buf[0]), *len); 2168252190Srpaulo wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0], 2169252190Srpaulo *len); 2170252190Srpaulo break; 2171252190Srpaulo case WNM_SLEEP_TFS_RESP_IE_NONE: 2172252190Srpaulo *len = 0; 2173252190Srpaulo break; 2174252190Srpaulo case WNM_SLEEP_TFS_IE_DEL: 2175252190Srpaulo tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2176252190Srpaulo tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2177252190Srpaulo tfs_ie->app_buflen = IEEE80211_APPIE_MAX - 2178252190Srpaulo sizeof(struct ieee80211req_getset_appiebuf); 2179252190Srpaulo /* Command header for driver */ 2180252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2181252190Srpaulo val = oper; 2182252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2183252190Srpaulo val = 0; 2184252190Srpaulo os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2185252190Srpaulo 2186252190Srpaulo if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, 2187252190Srpaulo IEEE80211_APPIE_MAX)) { 2188252190Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " 2189252190Srpaulo "%s", __func__, strerror(errno)); 2190252190Srpaulo return -1; 2191252190Srpaulo } 2192252190Srpaulo break; 2193252190Srpaulo default: 2194252190Srpaulo wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper); 2195252190Srpaulo break; 2196252190Srpaulo } 2197252190Srpaulo 2198252190Srpaulo return 0; 2199252190Srpaulo} 2200252190Srpaulo 2201252190Srpaulo 2202252190Srpaulostatic int atheros_wnm_sleep(struct atheros_driver_data *drv, 2203252190Srpaulo const u8 *peer, enum wnm_oper oper) 2204252190Srpaulo{ 2205252190Srpaulo u8 *data, *pos; 2206252190Srpaulo size_t dlen; 2207252190Srpaulo int ret; 2208252190Srpaulo u16 val; 2209252190Srpaulo 2210252190Srpaulo wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR, 2211252190Srpaulo oper, MAC2STR(peer)); 2212252190Srpaulo 2213252190Srpaulo dlen = ETH_ALEN + 2 + 2; 2214252190Srpaulo data = os_malloc(dlen); 2215252190Srpaulo if (data == NULL) 2216252190Srpaulo return -1; 2217252190Srpaulo 2218252190Srpaulo /* Command header for driver */ 2219252190Srpaulo pos = data; 2220252190Srpaulo os_memcpy(pos, peer, ETH_ALEN); 2221252190Srpaulo pos += ETH_ALEN; 2222252190Srpaulo 2223252190Srpaulo val = oper; 2224252190Srpaulo os_memcpy(pos, &val, 2); 2225252190Srpaulo pos += 2; 2226252190Srpaulo 2227252190Srpaulo val = 0; 2228252190Srpaulo os_memcpy(pos, &val, 2); 2229252190Srpaulo 2230252190Srpaulo ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM); 2231252190Srpaulo 2232252190Srpaulo os_free(data); 2233252190Srpaulo 2234252190Srpaulo return ret; 2235252190Srpaulo} 2236252190Srpaulo 2237252190Srpaulo 2238252190Srpaulostatic int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer, 2239252190Srpaulo u8 *buf, u16 *buf_len) 2240252190Srpaulo{ 2241252190Srpaulo struct atheros_driver_data *drv = priv; 2242252190Srpaulo 2243252190Srpaulo switch (oper) { 2244252190Srpaulo case WNM_SLEEP_ENTER_CONFIRM: 2245252190Srpaulo case WNM_SLEEP_ENTER_FAIL: 2246252190Srpaulo case WNM_SLEEP_EXIT_CONFIRM: 2247252190Srpaulo case WNM_SLEEP_EXIT_FAIL: 2248252190Srpaulo return atheros_wnm_sleep(drv, peer, oper); 2249252190Srpaulo case WNM_SLEEP_TFS_REQ_IE_SET: 2250252190Srpaulo case WNM_SLEEP_TFS_RESP_IE_ADD: 2251252190Srpaulo case WNM_SLEEP_TFS_RESP_IE_NONE: 2252252190Srpaulo case WNM_SLEEP_TFS_IE_DEL: 2253252190Srpaulo return athr_wnm_tfs(drv, peer, buf, buf_len, oper); 2254252190Srpaulo default: 2255252190Srpaulo wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d", 2256252190Srpaulo oper); 2257252190Srpaulo return -1; 2258252190Srpaulo } 2259252190Srpaulo} 2260281681Srpaulo#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ 2261252190Srpaulo 2262252190Srpaulo 2263214501Srpauloconst struct wpa_driver_ops wpa_driver_atheros_ops = { 2264214501Srpaulo .name = "atheros", 2265252190Srpaulo .hapd_init = atheros_init, 2266252190Srpaulo .hapd_deinit = atheros_deinit, 2267252190Srpaulo .set_ieee8021x = atheros_set_ieee8021x, 2268252190Srpaulo .set_privacy = atheros_set_privacy, 2269252190Srpaulo .set_key = atheros_set_key, 2270252190Srpaulo .get_seqnum = atheros_get_seqnum, 2271252190Srpaulo .flush = atheros_flush, 2272252190Srpaulo .set_generic_elem = atheros_set_opt_ie, 2273252190Srpaulo .sta_set_flags = atheros_sta_set_flags, 2274252190Srpaulo .read_sta_data = atheros_read_sta_driver_data, 2275252190Srpaulo .hapd_send_eapol = atheros_send_eapol, 2276252190Srpaulo .sta_disassoc = atheros_sta_disassoc, 2277252190Srpaulo .sta_deauth = atheros_sta_deauth, 2278252190Srpaulo .hapd_set_ssid = atheros_set_ssid, 2279252190Srpaulo .hapd_get_ssid = atheros_get_ssid, 2280252190Srpaulo .set_countermeasures = atheros_set_countermeasures, 2281252190Srpaulo .sta_clear_stats = atheros_sta_clear_stats, 2282252190Srpaulo .commit = atheros_commit, 2283252190Srpaulo .set_ap_wps_ie = atheros_set_ap_wps_ie, 2284252190Srpaulo .set_authmode = atheros_set_authmode, 2285252190Srpaulo .set_ap = atheros_set_ap, 2286341618Scy#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 2287252190Srpaulo .sta_assoc = atheros_sta_assoc, 2288252190Srpaulo .sta_auth = atheros_sta_auth, 2289252190Srpaulo .send_mlme = atheros_send_mgmt, 2290341618Scy#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 2291289284Srpaulo#ifdef CONFIG_IEEE80211R 2292252190Srpaulo .add_tspec = atheros_add_tspec, 2293252190Srpaulo .add_sta_node = atheros_add_sta_node, 2294252190Srpaulo#endif /* CONFIG_IEEE80211R */ 2295252190Srpaulo .send_action = atheros_send_action, 2296281681Srpaulo#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) 2297252190Srpaulo .wnm_oper = atheros_wnm_oper, 2298281681Srpaulo#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ 2299281681Srpaulo .set_qos_map = atheros_set_qos_map, 2300214501Srpaulo}; 2301