1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * hostapd / Driver interaction with Atheros driver 3e5b75505Sopenharmony_ci * Copyright (c) 2004, Sam Leffler <sam@errno.com> 4e5b75505Sopenharmony_ci * Copyright (c) 2004, Video54 Technologies 5e5b75505Sopenharmony_ci * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> 6e5b75505Sopenharmony_ci * Copyright (c) 2009, Atheros Communications 7e5b75505Sopenharmony_ci * 8e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 9e5b75505Sopenharmony_ci * See README for more details. 10e5b75505Sopenharmony_ci */ 11e5b75505Sopenharmony_ci 12e5b75505Sopenharmony_ci#include "includes.h" 13e5b75505Sopenharmony_ci#include <net/if.h> 14e5b75505Sopenharmony_ci#include <sys/ioctl.h> 15e5b75505Sopenharmony_ci 16e5b75505Sopenharmony_ci#include "common.h" 17e5b75505Sopenharmony_ci#include "eloop.h" 18e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 19e5b75505Sopenharmony_ci#include "l2_packet/l2_packet.h" 20e5b75505Sopenharmony_ci#include "p2p/p2p.h" 21e5b75505Sopenharmony_ci 22e5b75505Sopenharmony_ci#include "common.h" 23e5b75505Sopenharmony_ci#ifndef _BYTE_ORDER 24e5b75505Sopenharmony_ci#ifdef WORDS_BIGENDIAN 25e5b75505Sopenharmony_ci#define _BYTE_ORDER _BIG_ENDIAN 26e5b75505Sopenharmony_ci#else 27e5b75505Sopenharmony_ci#define _BYTE_ORDER _LITTLE_ENDIAN 28e5b75505Sopenharmony_ci#endif 29e5b75505Sopenharmony_ci#endif /* _BYTE_ORDER */ 30e5b75505Sopenharmony_ci 31e5b75505Sopenharmony_ci/* 32e5b75505Sopenharmony_ci * Note, the ATH_WPS_IE setting must match with the driver build.. If the 33e5b75505Sopenharmony_ci * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail. 34e5b75505Sopenharmony_ci */ 35e5b75505Sopenharmony_ci#define ATH_WPS_IE 36e5b75505Sopenharmony_ci 37e5b75505Sopenharmony_ci#include "ieee80211_external.h" 38e5b75505Sopenharmony_ci 39e5b75505Sopenharmony_ci/* Avoid conflicting definition from the driver header files with 40e5b75505Sopenharmony_ci * common/wpa_common.h */ 41e5b75505Sopenharmony_ci#undef WPA_OUI_TYPE 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_ci 44e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 45e5b75505Sopenharmony_ci#include <netpacket/packet.h> 46e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 47e5b75505Sopenharmony_ci 48e5b75505Sopenharmony_ci#ifndef ETH_P_80211_RAW 49e5b75505Sopenharmony_ci#define ETH_P_80211_RAW 0x0019 50e5b75505Sopenharmony_ci#endif 51e5b75505Sopenharmony_ci 52e5b75505Sopenharmony_ci#include "linux_wext.h" 53e5b75505Sopenharmony_ci 54e5b75505Sopenharmony_ci#include "driver.h" 55e5b75505Sopenharmony_ci#include "eloop.h" 56e5b75505Sopenharmony_ci#include "priv_netlink.h" 57e5b75505Sopenharmony_ci#include "l2_packet/l2_packet.h" 58e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 59e5b75505Sopenharmony_ci#include "netlink.h" 60e5b75505Sopenharmony_ci#include "linux_ioctl.h" 61e5b75505Sopenharmony_ci 62e5b75505Sopenharmony_ci#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS) 63e5b75505Sopenharmony_ci#define ATHEROS_USE_RAW_RECEIVE 64e5b75505Sopenharmony_ci#endif 65e5b75505Sopenharmony_ci 66e5b75505Sopenharmony_ci 67e5b75505Sopenharmony_cistruct atheros_driver_data { 68e5b75505Sopenharmony_ci struct hostapd_data *hapd; /* back pointer */ 69e5b75505Sopenharmony_ci 70e5b75505Sopenharmony_ci char iface[IFNAMSIZ + 1]; 71e5b75505Sopenharmony_ci int ifindex; 72e5b75505Sopenharmony_ci struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ 73e5b75505Sopenharmony_ci struct l2_packet_data *sock_recv; /* raw packet recv socket */ 74e5b75505Sopenharmony_ci int ioctl_sock; /* socket for ioctl() use */ 75e5b75505Sopenharmony_ci struct netlink_data *netlink; 76e5b75505Sopenharmony_ci int we_version; 77e5b75505Sopenharmony_ci int fils_en; /* FILS enable/disable in driver */ 78e5b75505Sopenharmony_ci u8 acct_mac[ETH_ALEN]; 79e5b75505Sopenharmony_ci struct hostap_sta_driver_data acct_data; 80e5b75505Sopenharmony_ci 81e5b75505Sopenharmony_ci struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ 82e5b75505Sopenharmony_ci struct wpabuf *wpa_ie; 83e5b75505Sopenharmony_ci struct wpabuf *wps_beacon_ie; 84e5b75505Sopenharmony_ci struct wpabuf *wps_probe_resp_ie; 85e5b75505Sopenharmony_ci u8 own_addr[ETH_ALEN]; 86e5b75505Sopenharmony_ci}; 87e5b75505Sopenharmony_ci 88e5b75505Sopenharmony_cistatic int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 89e5b75505Sopenharmony_ci u16 reason_code); 90e5b75505Sopenharmony_cistatic int atheros_set_privacy(void *priv, int enabled); 91e5b75505Sopenharmony_ci 92e5b75505Sopenharmony_cistatic const char * athr_get_ioctl_name(int op) 93e5b75505Sopenharmony_ci{ 94e5b75505Sopenharmony_ci switch (op) { 95e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETPARAM: 96e5b75505Sopenharmony_ci return "SETPARAM"; 97e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETPARAM: 98e5b75505Sopenharmony_ci return "GETPARAM"; 99e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETKEY: 100e5b75505Sopenharmony_ci return "SETKEY"; 101e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETWMMPARAMS: 102e5b75505Sopenharmony_ci return "SETWMMPARAMS"; 103e5b75505Sopenharmony_ci case IEEE80211_IOCTL_DELKEY: 104e5b75505Sopenharmony_ci return "DELKEY"; 105e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETWMMPARAMS: 106e5b75505Sopenharmony_ci return "GETWMMPARAMS"; 107e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETMLME: 108e5b75505Sopenharmony_ci return "SETMLME"; 109e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETCHANINFO: 110e5b75505Sopenharmony_ci return "GETCHANINFO"; 111e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETOPTIE: 112e5b75505Sopenharmony_ci return "SETOPTIE"; 113e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETOPTIE: 114e5b75505Sopenharmony_ci return "GETOPTIE"; 115e5b75505Sopenharmony_ci case IEEE80211_IOCTL_ADDMAC: 116e5b75505Sopenharmony_ci return "ADDMAC"; 117e5b75505Sopenharmony_ci case IEEE80211_IOCTL_DELMAC: 118e5b75505Sopenharmony_ci return "DELMAC"; 119e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETCHANLIST: 120e5b75505Sopenharmony_ci return "GETCHANLIST"; 121e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETCHANLIST: 122e5b75505Sopenharmony_ci return "SETCHANLIST"; 123e5b75505Sopenharmony_ci case IEEE80211_IOCTL_KICKMAC: 124e5b75505Sopenharmony_ci return "KICKMAC"; 125e5b75505Sopenharmony_ci case IEEE80211_IOCTL_CHANSWITCH: 126e5b75505Sopenharmony_ci return "CHANSWITCH"; 127e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETMODE: 128e5b75505Sopenharmony_ci return "GETMODE"; 129e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SETMODE: 130e5b75505Sopenharmony_ci return "SETMODE"; 131e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GET_APPIEBUF: 132e5b75505Sopenharmony_ci return "GET_APPIEBUF"; 133e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SET_APPIEBUF: 134e5b75505Sopenharmony_ci return "SET_APPIEBUF"; 135e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SET_ACPARAMS: 136e5b75505Sopenharmony_ci return "SET_ACPARAMS"; 137e5b75505Sopenharmony_ci case IEEE80211_IOCTL_FILTERFRAME: 138e5b75505Sopenharmony_ci return "FILTERFRAME"; 139e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SET_RTPARAMS: 140e5b75505Sopenharmony_ci return "SET_RTPARAMS"; 141e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SET_MEDENYENTRY: 142e5b75505Sopenharmony_ci return "SET_MEDENYENTRY"; 143e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GET_MACADDR: 144e5b75505Sopenharmony_ci return "GET_MACADDR"; 145e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SET_HBRPARAMS: 146e5b75505Sopenharmony_ci return "SET_HBRPARAMS"; 147e5b75505Sopenharmony_ci case IEEE80211_IOCTL_SET_RXTIMEOUT: 148e5b75505Sopenharmony_ci return "SET_RXTIMEOUT"; 149e5b75505Sopenharmony_ci case IEEE80211_IOCTL_STA_STATS: 150e5b75505Sopenharmony_ci return "STA_STATS"; 151e5b75505Sopenharmony_ci case IEEE80211_IOCTL_GETWPAIE: 152e5b75505Sopenharmony_ci return "GETWPAIE"; 153e5b75505Sopenharmony_ci default: 154e5b75505Sopenharmony_ci return "??"; 155e5b75505Sopenharmony_ci } 156e5b75505Sopenharmony_ci} 157e5b75505Sopenharmony_ci 158e5b75505Sopenharmony_ci 159e5b75505Sopenharmony_cistatic const char * athr_get_param_name(int op) 160e5b75505Sopenharmony_ci{ 161e5b75505Sopenharmony_ci switch (op) { 162e5b75505Sopenharmony_ci case IEEE80211_IOC_MCASTCIPHER: 163e5b75505Sopenharmony_ci return "MCASTCIPHER"; 164e5b75505Sopenharmony_ci case IEEE80211_PARAM_MCASTKEYLEN: 165e5b75505Sopenharmony_ci return "MCASTKEYLEN"; 166e5b75505Sopenharmony_ci case IEEE80211_PARAM_UCASTCIPHERS: 167e5b75505Sopenharmony_ci return "UCASTCIPHERS"; 168e5b75505Sopenharmony_ci case IEEE80211_PARAM_KEYMGTALGS: 169e5b75505Sopenharmony_ci return "KEYMGTALGS"; 170e5b75505Sopenharmony_ci case IEEE80211_PARAM_RSNCAPS: 171e5b75505Sopenharmony_ci return "RSNCAPS"; 172e5b75505Sopenharmony_ci case IEEE80211_PARAM_WPA: 173e5b75505Sopenharmony_ci return "WPA"; 174e5b75505Sopenharmony_ci case IEEE80211_PARAM_AUTHMODE: 175e5b75505Sopenharmony_ci return "AUTHMODE"; 176e5b75505Sopenharmony_ci case IEEE80211_PARAM_PRIVACY: 177e5b75505Sopenharmony_ci return "PRIVACY"; 178e5b75505Sopenharmony_ci case IEEE80211_PARAM_COUNTERMEASURES: 179e5b75505Sopenharmony_ci return "COUNTERMEASURES"; 180e5b75505Sopenharmony_ci default: 181e5b75505Sopenharmony_ci return "??"; 182e5b75505Sopenharmony_ci } 183e5b75505Sopenharmony_ci} 184e5b75505Sopenharmony_ci 185e5b75505Sopenharmony_ci 186e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 187e5b75505Sopenharmony_cistatic int 188e5b75505Sopenharmony_ciget80211param(struct atheros_driver_data *drv, int op, int *data) 189e5b75505Sopenharmony_ci{ 190e5b75505Sopenharmony_ci struct iwreq iwr; 191e5b75505Sopenharmony_ci 192e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 193e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 194e5b75505Sopenharmony_ci iwr.u.mode = op; 195e5b75505Sopenharmony_ci 196e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_GETPARAM, &iwr) < 0) 197e5b75505Sopenharmony_ci return -1; 198e5b75505Sopenharmony_ci 199e5b75505Sopenharmony_ci *data = iwr.u.mode; 200e5b75505Sopenharmony_ci return 0; 201e5b75505Sopenharmony_ci} 202e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 203e5b75505Sopenharmony_ci 204e5b75505Sopenharmony_ci 205e5b75505Sopenharmony_cistatic int 206e5b75505Sopenharmony_ciset80211priv(struct atheros_driver_data *drv, int op, void *data, int len) 207e5b75505Sopenharmony_ci{ 208e5b75505Sopenharmony_ci struct iwreq iwr; 209e5b75505Sopenharmony_ci int do_inline = len < IFNAMSIZ; 210e5b75505Sopenharmony_ci 211e5b75505Sopenharmony_ci /* Certain ioctls must use the non-inlined method */ 212e5b75505Sopenharmony_ci if (op == IEEE80211_IOCTL_SET_APPIEBUF || 213e5b75505Sopenharmony_ci op == IEEE80211_IOCTL_FILTERFRAME) 214e5b75505Sopenharmony_ci do_inline = 0; 215e5b75505Sopenharmony_ci 216e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 217e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 218e5b75505Sopenharmony_ci if (do_inline) { 219e5b75505Sopenharmony_ci /* 220e5b75505Sopenharmony_ci * Argument data fits inline; put it there. 221e5b75505Sopenharmony_ci */ 222e5b75505Sopenharmony_ci os_memcpy(iwr.u.name, data, len); 223e5b75505Sopenharmony_ci } else { 224e5b75505Sopenharmony_ci /* 225e5b75505Sopenharmony_ci * Argument data too big for inline transfer; setup a 226e5b75505Sopenharmony_ci * parameter block instead; the kernel will transfer 227e5b75505Sopenharmony_ci * the data for the driver. 228e5b75505Sopenharmony_ci */ 229e5b75505Sopenharmony_ci iwr.u.data.pointer = data; 230e5b75505Sopenharmony_ci iwr.u.data.length = len; 231e5b75505Sopenharmony_ci } 232e5b75505Sopenharmony_ci 233e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { 234e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x " 235e5b75505Sopenharmony_ci "(%s) len=%d failed: %d (%s)", 236e5b75505Sopenharmony_ci __func__, drv->iface, op, 237e5b75505Sopenharmony_ci athr_get_ioctl_name(op), 238e5b75505Sopenharmony_ci len, errno, strerror(errno)); 239e5b75505Sopenharmony_ci return -1; 240e5b75505Sopenharmony_ci } 241e5b75505Sopenharmony_ci return 0; 242e5b75505Sopenharmony_ci} 243e5b75505Sopenharmony_ci 244e5b75505Sopenharmony_cistatic int 245e5b75505Sopenharmony_ciset80211param(struct atheros_driver_data *drv, int op, int arg) 246e5b75505Sopenharmony_ci{ 247e5b75505Sopenharmony_ci struct iwreq iwr; 248e5b75505Sopenharmony_ci 249e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 250e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 251e5b75505Sopenharmony_ci iwr.u.mode = op; 252e5b75505Sopenharmony_ci os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg)); 253e5b75505Sopenharmony_ci 254e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { 255e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 256e5b75505Sopenharmony_ci "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s", 257e5b75505Sopenharmony_ci __func__, drv->iface, op, athr_get_param_name(op), 258e5b75505Sopenharmony_ci arg, strerror(errno)); 259e5b75505Sopenharmony_ci return -1; 260e5b75505Sopenharmony_ci } 261e5b75505Sopenharmony_ci return 0; 262e5b75505Sopenharmony_ci} 263e5b75505Sopenharmony_ci 264e5b75505Sopenharmony_ci#ifndef CONFIG_NO_STDOUT_DEBUG 265e5b75505Sopenharmony_cistatic const char * 266e5b75505Sopenharmony_ciether_sprintf(const u8 *addr) 267e5b75505Sopenharmony_ci{ 268e5b75505Sopenharmony_ci static char buf[sizeof(MACSTR)]; 269e5b75505Sopenharmony_ci 270e5b75505Sopenharmony_ci if (addr != NULL) 271e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 272e5b75505Sopenharmony_ci else 273e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0); 274e5b75505Sopenharmony_ci return buf; 275e5b75505Sopenharmony_ci} 276e5b75505Sopenharmony_ci#endif /* CONFIG_NO_STDOUT_DEBUG */ 277e5b75505Sopenharmony_ci 278e5b75505Sopenharmony_ci/* 279e5b75505Sopenharmony_ci * Configure WPA parameters. 280e5b75505Sopenharmony_ci */ 281e5b75505Sopenharmony_cistatic int 282e5b75505Sopenharmony_ciatheros_configure_wpa(struct atheros_driver_data *drv, 283e5b75505Sopenharmony_ci struct wpa_bss_params *params) 284e5b75505Sopenharmony_ci{ 285e5b75505Sopenharmony_ci int v; 286e5b75505Sopenharmony_ci 287e5b75505Sopenharmony_ci switch (params->wpa_group) { 288e5b75505Sopenharmony_ci case WPA_CIPHER_CCMP: 289e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_AES_CCM; 290e5b75505Sopenharmony_ci break; 291e5b75505Sopenharmony_ci#ifdef ATH_GCM_SUPPORT 292e5b75505Sopenharmony_ci case WPA_CIPHER_CCMP_256: 293e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_AES_CCM_256; 294e5b75505Sopenharmony_ci break; 295e5b75505Sopenharmony_ci case WPA_CIPHER_GCMP: 296e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_AES_GCM; 297e5b75505Sopenharmony_ci break; 298e5b75505Sopenharmony_ci case WPA_CIPHER_GCMP_256: 299e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_AES_GCM_256; 300e5b75505Sopenharmony_ci break; 301e5b75505Sopenharmony_ci#endif /* ATH_GCM_SUPPORT */ 302e5b75505Sopenharmony_ci case WPA_CIPHER_TKIP: 303e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_TKIP; 304e5b75505Sopenharmony_ci break; 305e5b75505Sopenharmony_ci case WPA_CIPHER_WEP104: 306e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_WEP; 307e5b75505Sopenharmony_ci break; 308e5b75505Sopenharmony_ci case WPA_CIPHER_WEP40: 309e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_WEP; 310e5b75505Sopenharmony_ci break; 311e5b75505Sopenharmony_ci case WPA_CIPHER_NONE: 312e5b75505Sopenharmony_ci v = IEEE80211_CIPHER_NONE; 313e5b75505Sopenharmony_ci break; 314e5b75505Sopenharmony_ci default: 315e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Unknown group key cipher %u", 316e5b75505Sopenharmony_ci params->wpa_group); 317e5b75505Sopenharmony_ci return -1; 318e5b75505Sopenharmony_ci } 319e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); 320e5b75505Sopenharmony_ci if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { 321e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v); 322e5b75505Sopenharmony_ci return -1; 323e5b75505Sopenharmony_ci } 324e5b75505Sopenharmony_ci if (v == IEEE80211_CIPHER_WEP) { 325e5b75505Sopenharmony_ci /* key length is done only for specific ciphers */ 326e5b75505Sopenharmony_ci v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); 327e5b75505Sopenharmony_ci if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { 328e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 329e5b75505Sopenharmony_ci "Unable to set group key length to %u", v); 330e5b75505Sopenharmony_ci return -1; 331e5b75505Sopenharmony_ci } 332e5b75505Sopenharmony_ci } 333e5b75505Sopenharmony_ci 334e5b75505Sopenharmony_ci v = 0; 335e5b75505Sopenharmony_ci if (params->wpa_pairwise & WPA_CIPHER_CCMP) 336e5b75505Sopenharmony_ci v |= 1<<IEEE80211_CIPHER_AES_CCM; 337e5b75505Sopenharmony_ci#ifdef ATH_GCM_SUPPORT 338e5b75505Sopenharmony_ci if (params->wpa_pairwise & WPA_CIPHER_CCMP_256) 339e5b75505Sopenharmony_ci v |= 1<<IEEE80211_CIPHER_AES_CCM_256; 340e5b75505Sopenharmony_ci if (params->wpa_pairwise & WPA_CIPHER_GCMP) 341e5b75505Sopenharmony_ci v |= 1<<IEEE80211_CIPHER_AES_GCM; 342e5b75505Sopenharmony_ci if (params->wpa_pairwise & WPA_CIPHER_GCMP_256) 343e5b75505Sopenharmony_ci v |= 1<<IEEE80211_CIPHER_AES_GCM_256; 344e5b75505Sopenharmony_ci#endif /* ATH_GCM_SUPPORT */ 345e5b75505Sopenharmony_ci if (params->wpa_pairwise & WPA_CIPHER_TKIP) 346e5b75505Sopenharmony_ci v |= 1<<IEEE80211_CIPHER_TKIP; 347e5b75505Sopenharmony_ci if (params->wpa_pairwise & WPA_CIPHER_NONE) 348e5b75505Sopenharmony_ci v |= 1<<IEEE80211_CIPHER_NONE; 349e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v); 350e5b75505Sopenharmony_ci if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) { 351e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 352e5b75505Sopenharmony_ci "Unable to set pairwise key ciphers to 0x%x", v); 353e5b75505Sopenharmony_ci return -1; 354e5b75505Sopenharmony_ci } 355e5b75505Sopenharmony_ci 356e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x", 357e5b75505Sopenharmony_ci __func__, params->wpa_key_mgmt); 358e5b75505Sopenharmony_ci if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, 359e5b75505Sopenharmony_ci params->wpa_key_mgmt)) { 360e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 361e5b75505Sopenharmony_ci "Unable to set key management algorithms to 0x%x", 362e5b75505Sopenharmony_ci params->wpa_key_mgmt); 363e5b75505Sopenharmony_ci return -1; 364e5b75505Sopenharmony_ci } 365e5b75505Sopenharmony_ci 366e5b75505Sopenharmony_ci v = 0; 367e5b75505Sopenharmony_ci if (params->rsn_preauth) 368e5b75505Sopenharmony_ci v |= BIT(0); 369e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 370e5b75505Sopenharmony_ci if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 371e5b75505Sopenharmony_ci v |= BIT(7); 372e5b75505Sopenharmony_ci if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) 373e5b75505Sopenharmony_ci v |= BIT(6); 374e5b75505Sopenharmony_ci } 375e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 376e5b75505Sopenharmony_ci 377e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v); 378e5b75505Sopenharmony_ci if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { 379e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", 380e5b75505Sopenharmony_ci v); 381e5b75505Sopenharmony_ci return -1; 382e5b75505Sopenharmony_ci } 383e5b75505Sopenharmony_ci 384e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); 385e5b75505Sopenharmony_ci if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { 386e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); 387e5b75505Sopenharmony_ci return -1; 388e5b75505Sopenharmony_ci } 389e5b75505Sopenharmony_ci return 0; 390e5b75505Sopenharmony_ci} 391e5b75505Sopenharmony_ci 392e5b75505Sopenharmony_cistatic int 393e5b75505Sopenharmony_ciatheros_set_ieee8021x(void *priv, struct wpa_bss_params *params) 394e5b75505Sopenharmony_ci{ 395e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 396e5b75505Sopenharmony_ci 397e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); 398e5b75505Sopenharmony_ci 399e5b75505Sopenharmony_ci if (!params->enabled) { 400e5b75505Sopenharmony_ci /* XXX restore state */ 401e5b75505Sopenharmony_ci if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, 402e5b75505Sopenharmony_ci IEEE80211_AUTH_AUTO) < 0) 403e5b75505Sopenharmony_ci return -1; 404e5b75505Sopenharmony_ci /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ 405e5b75505Sopenharmony_ci return atheros_set_privacy(drv, 0); 406e5b75505Sopenharmony_ci } 407e5b75505Sopenharmony_ci if (!params->wpa && !params->ieee802_1x) { 408e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!"); 409e5b75505Sopenharmony_ci return -1; 410e5b75505Sopenharmony_ci } 411e5b75505Sopenharmony_ci if (params->wpa && atheros_configure_wpa(drv, params) != 0) { 412e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "Error configuring WPA state!"); 413e5b75505Sopenharmony_ci return -1; 414e5b75505Sopenharmony_ci } 415e5b75505Sopenharmony_ci if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, 416e5b75505Sopenharmony_ci (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { 417e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!"); 418e5b75505Sopenharmony_ci return -1; 419e5b75505Sopenharmony_ci } 420e5b75505Sopenharmony_ci 421e5b75505Sopenharmony_ci return 0; 422e5b75505Sopenharmony_ci} 423e5b75505Sopenharmony_ci 424e5b75505Sopenharmony_cistatic int 425e5b75505Sopenharmony_ciatheros_set_privacy(void *priv, int enabled) 426e5b75505Sopenharmony_ci{ 427e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 428e5b75505Sopenharmony_ci 429e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 430e5b75505Sopenharmony_ci 431e5b75505Sopenharmony_ci return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); 432e5b75505Sopenharmony_ci} 433e5b75505Sopenharmony_ci 434e5b75505Sopenharmony_cistatic int 435e5b75505Sopenharmony_ciatheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) 436e5b75505Sopenharmony_ci{ 437e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 438e5b75505Sopenharmony_ci struct ieee80211req_mlme mlme; 439e5b75505Sopenharmony_ci int ret; 440e5b75505Sopenharmony_ci 441e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", 442e5b75505Sopenharmony_ci __func__, ether_sprintf(addr), authorized); 443e5b75505Sopenharmony_ci 444e5b75505Sopenharmony_ci if (authorized) 445e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_AUTHORIZE; 446e5b75505Sopenharmony_ci else 447e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; 448e5b75505Sopenharmony_ci mlme.im_reason = 0; 449e5b75505Sopenharmony_ci os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 450e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 451e5b75505Sopenharmony_ci if (ret < 0) { 452e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, 453e5b75505Sopenharmony_ci __func__, authorized ? "" : "un", MAC2STR(addr)); 454e5b75505Sopenharmony_ci } 455e5b75505Sopenharmony_ci 456e5b75505Sopenharmony_ci return ret; 457e5b75505Sopenharmony_ci} 458e5b75505Sopenharmony_ci 459e5b75505Sopenharmony_cistatic int 460e5b75505Sopenharmony_ciatheros_sta_set_flags(void *priv, const u8 *addr, 461e5b75505Sopenharmony_ci unsigned int total_flags, unsigned int flags_or, 462e5b75505Sopenharmony_ci unsigned int flags_and) 463e5b75505Sopenharmony_ci{ 464e5b75505Sopenharmony_ci /* For now, only support setting Authorized flag */ 465e5b75505Sopenharmony_ci if (flags_or & WPA_STA_AUTHORIZED) 466e5b75505Sopenharmony_ci return atheros_set_sta_authorized(priv, addr, 1); 467e5b75505Sopenharmony_ci if (!(flags_and & WPA_STA_AUTHORIZED)) 468e5b75505Sopenharmony_ci return atheros_set_sta_authorized(priv, addr, 0); 469e5b75505Sopenharmony_ci return 0; 470e5b75505Sopenharmony_ci} 471e5b75505Sopenharmony_ci 472e5b75505Sopenharmony_cistatic int 473e5b75505Sopenharmony_ciatheros_del_key(void *priv, const u8 *addr, int key_idx) 474e5b75505Sopenharmony_ci{ 475e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 476e5b75505Sopenharmony_ci struct ieee80211req_del_key wk; 477e5b75505Sopenharmony_ci int ret; 478e5b75505Sopenharmony_ci 479e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", 480e5b75505Sopenharmony_ci __func__, ether_sprintf(addr), key_idx); 481e5b75505Sopenharmony_ci 482e5b75505Sopenharmony_ci os_memset(&wk, 0, sizeof(wk)); 483e5b75505Sopenharmony_ci if (addr != NULL) { 484e5b75505Sopenharmony_ci os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); 485e5b75505Sopenharmony_ci wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; 486e5b75505Sopenharmony_ci } else { 487e5b75505Sopenharmony_ci wk.idk_keyix = key_idx; 488e5b75505Sopenharmony_ci } 489e5b75505Sopenharmony_ci 490e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); 491e5b75505Sopenharmony_ci if (ret < 0) { 492e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" 493e5b75505Sopenharmony_ci " key_idx %d)", __func__, ether_sprintf(addr), 494e5b75505Sopenharmony_ci key_idx); 495e5b75505Sopenharmony_ci } 496e5b75505Sopenharmony_ci 497e5b75505Sopenharmony_ci return ret; 498e5b75505Sopenharmony_ci} 499e5b75505Sopenharmony_ci 500e5b75505Sopenharmony_cistatic int 501e5b75505Sopenharmony_ciatheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, 502e5b75505Sopenharmony_ci const u8 *addr, int key_idx, int set_tx, const u8 *seq, 503e5b75505Sopenharmony_ci size_t seq_len, const u8 *key, size_t key_len) 504e5b75505Sopenharmony_ci{ 505e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 506e5b75505Sopenharmony_ci struct ieee80211req_key wk; 507e5b75505Sopenharmony_ci u_int8_t cipher; 508e5b75505Sopenharmony_ci int ret; 509e5b75505Sopenharmony_ci 510e5b75505Sopenharmony_ci if (alg == WPA_ALG_NONE) 511e5b75505Sopenharmony_ci return atheros_del_key(drv, addr, key_idx); 512e5b75505Sopenharmony_ci 513e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", 514e5b75505Sopenharmony_ci __func__, alg, ether_sprintf(addr), key_idx); 515e5b75505Sopenharmony_ci 516e5b75505Sopenharmony_ci switch (alg) { 517e5b75505Sopenharmony_ci case WPA_ALG_WEP: 518e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_WEP; 519e5b75505Sopenharmony_ci break; 520e5b75505Sopenharmony_ci case WPA_ALG_TKIP: 521e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_TKIP; 522e5b75505Sopenharmony_ci break; 523e5b75505Sopenharmony_ci case WPA_ALG_CCMP: 524e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_CCM; 525e5b75505Sopenharmony_ci break; 526e5b75505Sopenharmony_ci#ifdef ATH_GCM_SUPPORT 527e5b75505Sopenharmony_ci case WPA_ALG_CCMP_256: 528e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_CCM_256; 529e5b75505Sopenharmony_ci break; 530e5b75505Sopenharmony_ci case WPA_ALG_GCMP: 531e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_GCM; 532e5b75505Sopenharmony_ci break; 533e5b75505Sopenharmony_ci case WPA_ALG_GCMP_256: 534e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_GCM_256; 535e5b75505Sopenharmony_ci break; 536e5b75505Sopenharmony_ci#endif /* ATH_GCM_SUPPORT */ 537e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 538e5b75505Sopenharmony_ci case WPA_ALG_IGTK: 539e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_CMAC; 540e5b75505Sopenharmony_ci break; 541e5b75505Sopenharmony_ci#ifdef ATH_GCM_SUPPORT 542e5b75505Sopenharmony_ci case WPA_ALG_BIP_CMAC_256: 543e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_CMAC_256; 544e5b75505Sopenharmony_ci break; 545e5b75505Sopenharmony_ci case WPA_ALG_BIP_GMAC_128: 546e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_GMAC; 547e5b75505Sopenharmony_ci break; 548e5b75505Sopenharmony_ci case WPA_ALG_BIP_GMAC_256: 549e5b75505Sopenharmony_ci cipher = IEEE80211_CIPHER_AES_GMAC_256; 550e5b75505Sopenharmony_ci break; 551e5b75505Sopenharmony_ci#endif /* ATH_GCM_SUPPORT */ 552e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 553e5b75505Sopenharmony_ci default: 554e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d", 555e5b75505Sopenharmony_ci __func__, alg); 556e5b75505Sopenharmony_ci return -1; 557e5b75505Sopenharmony_ci } 558e5b75505Sopenharmony_ci 559e5b75505Sopenharmony_ci if (key_len > sizeof(wk.ik_keydata)) { 560e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__, 561e5b75505Sopenharmony_ci (unsigned long) key_len); 562e5b75505Sopenharmony_ci return -3; 563e5b75505Sopenharmony_ci } 564e5b75505Sopenharmony_ci 565e5b75505Sopenharmony_ci os_memset(&wk, 0, sizeof(wk)); 566e5b75505Sopenharmony_ci wk.ik_type = cipher; 567e5b75505Sopenharmony_ci wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; 568e5b75505Sopenharmony_ci if (addr == NULL || is_broadcast_ether_addr(addr)) { 569e5b75505Sopenharmony_ci os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 570e5b75505Sopenharmony_ci wk.ik_keyix = key_idx; 571e5b75505Sopenharmony_ci if (set_tx) 572e5b75505Sopenharmony_ci wk.ik_flags |= IEEE80211_KEY_DEFAULT; 573e5b75505Sopenharmony_ci } else { 574e5b75505Sopenharmony_ci os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 575e5b75505Sopenharmony_ci wk.ik_keyix = IEEE80211_KEYIX_NONE; 576e5b75505Sopenharmony_ci } 577e5b75505Sopenharmony_ci wk.ik_keylen = key_len; 578e5b75505Sopenharmony_ci os_memcpy(wk.ik_keydata, key, key_len); 579e5b75505Sopenharmony_ci 580e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); 581e5b75505Sopenharmony_ci if (ret < 0) { 582e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" 583e5b75505Sopenharmony_ci " key_idx %d alg %d key_len %lu set_tx %d)", 584e5b75505Sopenharmony_ci __func__, ether_sprintf(wk.ik_macaddr), key_idx, 585e5b75505Sopenharmony_ci alg, (unsigned long) key_len, set_tx); 586e5b75505Sopenharmony_ci } 587e5b75505Sopenharmony_ci 588e5b75505Sopenharmony_ci return ret; 589e5b75505Sopenharmony_ci} 590e5b75505Sopenharmony_ci 591e5b75505Sopenharmony_ci 592e5b75505Sopenharmony_cistatic int 593e5b75505Sopenharmony_ciatheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, 594e5b75505Sopenharmony_ci u8 *seq) 595e5b75505Sopenharmony_ci{ 596e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 597e5b75505Sopenharmony_ci struct ieee80211req_key wk; 598e5b75505Sopenharmony_ci 599e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", 600e5b75505Sopenharmony_ci __func__, ether_sprintf(addr), idx); 601e5b75505Sopenharmony_ci 602e5b75505Sopenharmony_ci os_memset(&wk, 0, sizeof(wk)); 603e5b75505Sopenharmony_ci if (addr == NULL) 604e5b75505Sopenharmony_ci os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 605e5b75505Sopenharmony_ci else 606e5b75505Sopenharmony_ci os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 607e5b75505Sopenharmony_ci wk.ik_keyix = idx; 608e5b75505Sopenharmony_ci 609e5b75505Sopenharmony_ci if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { 610e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " 611e5b75505Sopenharmony_ci "(addr " MACSTR " key_idx %d)", 612e5b75505Sopenharmony_ci __func__, MAC2STR(wk.ik_macaddr), idx); 613e5b75505Sopenharmony_ci return -1; 614e5b75505Sopenharmony_ci } 615e5b75505Sopenharmony_ci 616e5b75505Sopenharmony_ci#ifdef WORDS_BIGENDIAN 617e5b75505Sopenharmony_ci { 618e5b75505Sopenharmony_ci /* 619e5b75505Sopenharmony_ci * wk.ik_keytsc is in host byte order (big endian), need to 620e5b75505Sopenharmony_ci * swap it to match with the byte order used in WPA. 621e5b75505Sopenharmony_ci */ 622e5b75505Sopenharmony_ci int i; 623e5b75505Sopenharmony_ci#ifndef WPA_KEY_RSC_LEN 624e5b75505Sopenharmony_ci#define WPA_KEY_RSC_LEN 8 625e5b75505Sopenharmony_ci#endif 626e5b75505Sopenharmony_ci u8 tmp[WPA_KEY_RSC_LEN]; 627e5b75505Sopenharmony_ci os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 628e5b75505Sopenharmony_ci for (i = 0; i < WPA_KEY_RSC_LEN; i++) { 629e5b75505Sopenharmony_ci seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; 630e5b75505Sopenharmony_ci } 631e5b75505Sopenharmony_ci } 632e5b75505Sopenharmony_ci#else /* WORDS_BIGENDIAN */ 633e5b75505Sopenharmony_ci os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 634e5b75505Sopenharmony_ci#endif /* WORDS_BIGENDIAN */ 635e5b75505Sopenharmony_ci return 0; 636e5b75505Sopenharmony_ci} 637e5b75505Sopenharmony_ci 638e5b75505Sopenharmony_ci 639e5b75505Sopenharmony_cistatic int 640e5b75505Sopenharmony_ciatheros_flush(void *priv) 641e5b75505Sopenharmony_ci{ 642e5b75505Sopenharmony_ci u8 allsta[IEEE80211_ADDR_LEN]; 643e5b75505Sopenharmony_ci os_memset(allsta, 0xff, IEEE80211_ADDR_LEN); 644e5b75505Sopenharmony_ci return atheros_sta_deauth(priv, NULL, allsta, 645e5b75505Sopenharmony_ci IEEE80211_REASON_AUTH_LEAVE); 646e5b75505Sopenharmony_ci} 647e5b75505Sopenharmony_ci 648e5b75505Sopenharmony_ci 649e5b75505Sopenharmony_cistatic int 650e5b75505Sopenharmony_ciatheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, 651e5b75505Sopenharmony_ci const u8 *addr) 652e5b75505Sopenharmony_ci{ 653e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 654e5b75505Sopenharmony_ci struct ieee80211req_sta_stats stats; 655e5b75505Sopenharmony_ci 656e5b75505Sopenharmony_ci os_memset(data, 0, sizeof(*data)); 657e5b75505Sopenharmony_ci 658e5b75505Sopenharmony_ci /* 659e5b75505Sopenharmony_ci * Fetch statistics for station from the system. 660e5b75505Sopenharmony_ci */ 661e5b75505Sopenharmony_ci os_memset(&stats, 0, sizeof(stats)); 662e5b75505Sopenharmony_ci os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); 663e5b75505Sopenharmony_ci if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, 664e5b75505Sopenharmony_ci &stats, sizeof(stats))) { 665e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " 666e5b75505Sopenharmony_ci MACSTR ")", __func__, MAC2STR(addr)); 667e5b75505Sopenharmony_ci if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { 668e5b75505Sopenharmony_ci os_memcpy(data, &drv->acct_data, sizeof(*data)); 669e5b75505Sopenharmony_ci return 0; 670e5b75505Sopenharmony_ci } 671e5b75505Sopenharmony_ci 672e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 673e5b75505Sopenharmony_ci "Failed to get station stats information element"); 674e5b75505Sopenharmony_ci return -1; 675e5b75505Sopenharmony_ci } 676e5b75505Sopenharmony_ci 677e5b75505Sopenharmony_ci data->rx_packets = stats.is_stats.ns_rx_data; 678e5b75505Sopenharmony_ci data->rx_bytes = stats.is_stats.ns_rx_bytes; 679e5b75505Sopenharmony_ci data->tx_packets = stats.is_stats.ns_tx_data; 680e5b75505Sopenharmony_ci data->tx_bytes = stats.is_stats.ns_tx_bytes; 681e5b75505Sopenharmony_ci return 0; 682e5b75505Sopenharmony_ci} 683e5b75505Sopenharmony_ci 684e5b75505Sopenharmony_ci 685e5b75505Sopenharmony_cistatic int 686e5b75505Sopenharmony_ciatheros_sta_clear_stats(void *priv, const u8 *addr) 687e5b75505Sopenharmony_ci{ 688e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 689e5b75505Sopenharmony_ci struct ieee80211req_mlme mlme; 690e5b75505Sopenharmony_ci int ret; 691e5b75505Sopenharmony_ci 692e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); 693e5b75505Sopenharmony_ci 694e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_CLEAR_STATS; 695e5b75505Sopenharmony_ci os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 696e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, 697e5b75505Sopenharmony_ci sizeof(mlme)); 698e5b75505Sopenharmony_ci if (ret < 0) { 699e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " 700e5b75505Sopenharmony_ci MACSTR ")", __func__, MAC2STR(addr)); 701e5b75505Sopenharmony_ci } 702e5b75505Sopenharmony_ci 703e5b75505Sopenharmony_ci return ret; 704e5b75505Sopenharmony_ci} 705e5b75505Sopenharmony_ci 706e5b75505Sopenharmony_ci 707e5b75505Sopenharmony_cistatic int 708e5b75505Sopenharmony_ciatheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) 709e5b75505Sopenharmony_ci{ 710e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 711e5b75505Sopenharmony_ci u8 buf[512]; 712e5b75505Sopenharmony_ci struct ieee80211req_getset_appiebuf *app_ie; 713e5b75505Sopenharmony_ci 714e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, 715e5b75505Sopenharmony_ci (unsigned long) ie_len); 716e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len); 717e5b75505Sopenharmony_ci 718e5b75505Sopenharmony_ci wpabuf_free(drv->wpa_ie); 719e5b75505Sopenharmony_ci if (ie) 720e5b75505Sopenharmony_ci drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); 721e5b75505Sopenharmony_ci else 722e5b75505Sopenharmony_ci drv->wpa_ie = NULL; 723e5b75505Sopenharmony_ci 724e5b75505Sopenharmony_ci app_ie = (struct ieee80211req_getset_appiebuf *) buf; 725e5b75505Sopenharmony_ci if (ie) 726e5b75505Sopenharmony_ci os_memcpy(&(app_ie->app_buf[0]), ie, ie_len); 727e5b75505Sopenharmony_ci app_ie->app_buflen = ie_len; 728e5b75505Sopenharmony_ci 729e5b75505Sopenharmony_ci app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON; 730e5b75505Sopenharmony_ci 731e5b75505Sopenharmony_ci /* append WPS IE for Beacon */ 732e5b75505Sopenharmony_ci if (drv->wps_beacon_ie != NULL) { 733e5b75505Sopenharmony_ci os_memcpy(&(app_ie->app_buf[ie_len]), 734e5b75505Sopenharmony_ci wpabuf_head(drv->wps_beacon_ie), 735e5b75505Sopenharmony_ci wpabuf_len(drv->wps_beacon_ie)); 736e5b75505Sopenharmony_ci app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); 737e5b75505Sopenharmony_ci } 738e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)", 739e5b75505Sopenharmony_ci app_ie->app_buf, app_ie->app_buflen); 740e5b75505Sopenharmony_ci set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, 741e5b75505Sopenharmony_ci sizeof(struct ieee80211req_getset_appiebuf) + 742e5b75505Sopenharmony_ci app_ie->app_buflen); 743e5b75505Sopenharmony_ci 744e5b75505Sopenharmony_ci /* append WPS IE for Probe Response */ 745e5b75505Sopenharmony_ci app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP; 746e5b75505Sopenharmony_ci if (drv->wps_probe_resp_ie != NULL) { 747e5b75505Sopenharmony_ci os_memcpy(&(app_ie->app_buf[ie_len]), 748e5b75505Sopenharmony_ci wpabuf_head(drv->wps_probe_resp_ie), 749e5b75505Sopenharmony_ci wpabuf_len(drv->wps_probe_resp_ie)); 750e5b75505Sopenharmony_ci app_ie->app_buflen = ie_len + 751e5b75505Sopenharmony_ci wpabuf_len(drv->wps_probe_resp_ie); 752e5b75505Sopenharmony_ci } else 753e5b75505Sopenharmony_ci app_ie->app_buflen = ie_len; 754e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)", 755e5b75505Sopenharmony_ci app_ie->app_buf, app_ie->app_buflen); 756e5b75505Sopenharmony_ci set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, 757e5b75505Sopenharmony_ci sizeof(struct ieee80211req_getset_appiebuf) + 758e5b75505Sopenharmony_ci app_ie->app_buflen); 759e5b75505Sopenharmony_ci return 0; 760e5b75505Sopenharmony_ci} 761e5b75505Sopenharmony_ci 762e5b75505Sopenharmony_cistatic int 763e5b75505Sopenharmony_ciatheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 764e5b75505Sopenharmony_ci u16 reason_code) 765e5b75505Sopenharmony_ci{ 766e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 767e5b75505Sopenharmony_ci struct ieee80211req_mlme mlme; 768e5b75505Sopenharmony_ci int ret; 769e5b75505Sopenharmony_ci 770e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", 771e5b75505Sopenharmony_ci __func__, ether_sprintf(addr), reason_code); 772e5b75505Sopenharmony_ci 773e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_DEAUTH; 774e5b75505Sopenharmony_ci mlme.im_reason = reason_code; 775e5b75505Sopenharmony_ci os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 776e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 777e5b75505Sopenharmony_ci if (ret < 0) { 778e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR 779e5b75505Sopenharmony_ci " reason %d)", 780e5b75505Sopenharmony_ci __func__, MAC2STR(addr), reason_code); 781e5b75505Sopenharmony_ci } 782e5b75505Sopenharmony_ci 783e5b75505Sopenharmony_ci return ret; 784e5b75505Sopenharmony_ci} 785e5b75505Sopenharmony_ci 786e5b75505Sopenharmony_cistatic int 787e5b75505Sopenharmony_ciatheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, 788e5b75505Sopenharmony_ci u16 reason_code) 789e5b75505Sopenharmony_ci{ 790e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 791e5b75505Sopenharmony_ci struct ieee80211req_mlme mlme; 792e5b75505Sopenharmony_ci int ret; 793e5b75505Sopenharmony_ci 794e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", 795e5b75505Sopenharmony_ci __func__, ether_sprintf(addr), reason_code); 796e5b75505Sopenharmony_ci 797e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_DISASSOC; 798e5b75505Sopenharmony_ci mlme.im_reason = reason_code; 799e5b75505Sopenharmony_ci os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 800e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 801e5b75505Sopenharmony_ci if (ret < 0) { 802e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " 803e5b75505Sopenharmony_ci MACSTR " reason %d)", 804e5b75505Sopenharmony_ci __func__, MAC2STR(addr), reason_code); 805e5b75505Sopenharmony_ci } 806e5b75505Sopenharmony_ci 807e5b75505Sopenharmony_ci return ret; 808e5b75505Sopenharmony_ci} 809e5b75505Sopenharmony_ci 810e5b75505Sopenharmony_cistatic int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, 811e5b75505Sopenharmony_ci u8 qos_map_set_len) 812e5b75505Sopenharmony_ci{ 813e5b75505Sopenharmony_ci#ifdef CONFIG_ATHEROS_QOS_MAP 814e5b75505Sopenharmony_ci struct atheros_driver_data *drv = ctx; 815e5b75505Sopenharmony_ci struct ieee80211req_athdbg req; 816e5b75505Sopenharmony_ci struct ieee80211_qos_map *qos_map = &req.data.qos_map; 817e5b75505Sopenharmony_ci struct iwreq iwr; 818e5b75505Sopenharmony_ci int i, up_start; 819e5b75505Sopenharmony_ci 820e5b75505Sopenharmony_ci if (qos_map_set_len < 16 || qos_map_set_len > 58 || 821e5b75505Sopenharmony_ci qos_map_set_len & 1) { 822e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Invalid QoS Map"); 823e5b75505Sopenharmony_ci return -1; 824e5b75505Sopenharmony_ci } else { 825e5b75505Sopenharmony_ci os_memset(&req, 0, sizeof(struct ieee80211req_athdbg)); 826e5b75505Sopenharmony_ci req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF; 827e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 828e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name)); 829e5b75505Sopenharmony_ci iwr.u.data.pointer = (void *) &req; 830e5b75505Sopenharmony_ci iwr.u.data.length = sizeof(struct ieee80211req_athdbg); 831e5b75505Sopenharmony_ci } 832e5b75505Sopenharmony_ci 833e5b75505Sopenharmony_ci qos_map->valid = 1; 834e5b75505Sopenharmony_ci qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; 835e5b75505Sopenharmony_ci if (qos_map->num_dscp_except) { 836e5b75505Sopenharmony_ci for (i = 0; i < qos_map->num_dscp_except; i++) { 837e5b75505Sopenharmony_ci qos_map->dscp_exception[i].dscp = qos_map_set[i * 2]; 838e5b75505Sopenharmony_ci qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1]; 839e5b75505Sopenharmony_ci } 840e5b75505Sopenharmony_ci } 841e5b75505Sopenharmony_ci 842e5b75505Sopenharmony_ci up_start = qos_map_set_len - 16; 843e5b75505Sopenharmony_ci for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) { 844e5b75505Sopenharmony_ci qos_map->up[i].low = qos_map_set[up_start + (i * 2)]; 845e5b75505Sopenharmony_ci qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1]; 846e5b75505Sopenharmony_ci } 847e5b75505Sopenharmony_ci 848e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) { 849e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 850e5b75505Sopenharmony_ci "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s", 851e5b75505Sopenharmony_ci __func__, drv->iface, strerror(errno)); 852e5b75505Sopenharmony_ci return -1; 853e5b75505Sopenharmony_ci } 854e5b75505Sopenharmony_ci#endif /* CONFIG_ATHEROS_QOS_MAP */ 855e5b75505Sopenharmony_ci 856e5b75505Sopenharmony_ci return 0; 857e5b75505Sopenharmony_ci} 858e5b75505Sopenharmony_ci 859e5b75505Sopenharmony_ci#ifdef ATHEROS_USE_RAW_RECEIVE 860e5b75505Sopenharmony_cistatic void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, 861e5b75505Sopenharmony_ci size_t len) 862e5b75505Sopenharmony_ci{ 863e5b75505Sopenharmony_ci struct atheros_driver_data *drv = ctx; 864e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt; 865e5b75505Sopenharmony_ci union wpa_event_data event; 866e5b75505Sopenharmony_ci u16 fc, stype; 867e5b75505Sopenharmony_ci int ielen; 868e5b75505Sopenharmony_ci const u8 *iebuf; 869e5b75505Sopenharmony_ci 870e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN) 871e5b75505Sopenharmony_ci return; 872e5b75505Sopenharmony_ci 873e5b75505Sopenharmony_ci mgmt = (const struct ieee80211_mgmt *) buf; 874e5b75505Sopenharmony_ci 875e5b75505Sopenharmony_ci fc = le_to_host16(mgmt->frame_control); 876e5b75505Sopenharmony_ci 877e5b75505Sopenharmony_ci if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) 878e5b75505Sopenharmony_ci return; 879e5b75505Sopenharmony_ci 880e5b75505Sopenharmony_ci stype = WLAN_FC_GET_STYPE(fc); 881e5b75505Sopenharmony_ci 882e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, 883e5b75505Sopenharmony_ci (int) len); 884e5b75505Sopenharmony_ci 885e5b75505Sopenharmony_ci if (stype == WLAN_FC_STYPE_PROBE_REQ) { 886e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN) 887e5b75505Sopenharmony_ci return; 888e5b75505Sopenharmony_ci 889e5b75505Sopenharmony_ci os_memset(&event, 0, sizeof(event)); 890e5b75505Sopenharmony_ci event.rx_probe_req.sa = mgmt->sa; 891e5b75505Sopenharmony_ci event.rx_probe_req.da = mgmt->da; 892e5b75505Sopenharmony_ci event.rx_probe_req.bssid = mgmt->bssid; 893e5b75505Sopenharmony_ci event.rx_probe_req.ie = buf + IEEE80211_HDRLEN; 894e5b75505Sopenharmony_ci event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN; 895e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); 896e5b75505Sopenharmony_ci return; 897e5b75505Sopenharmony_ci } 898e5b75505Sopenharmony_ci 899e5b75505Sopenharmony_ci if (stype == WLAN_FC_STYPE_ACTION && 900e5b75505Sopenharmony_ci (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 || 901e5b75505Sopenharmony_ci is_broadcast_ether_addr(mgmt->bssid))) { 902e5b75505Sopenharmony_ci os_memset(&event, 0, sizeof(event)); 903e5b75505Sopenharmony_ci event.rx_mgmt.frame = buf; 904e5b75505Sopenharmony_ci event.rx_mgmt.frame_len = len; 905e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); 906e5b75505Sopenharmony_ci return; 907e5b75505Sopenharmony_ci } 908e5b75505Sopenharmony_ci 909e5b75505Sopenharmony_ci if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { 910e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", 911e5b75505Sopenharmony_ci __func__); 912e5b75505Sopenharmony_ci return; 913e5b75505Sopenharmony_ci } 914e5b75505Sopenharmony_ci 915e5b75505Sopenharmony_ci switch (stype) { 916e5b75505Sopenharmony_ci case WLAN_FC_STYPE_ASSOC_REQ: 917e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)) 918e5b75505Sopenharmony_ci break; 919e5b75505Sopenharmony_ci ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); 920e5b75505Sopenharmony_ci iebuf = mgmt->u.assoc_req.variable; 921e5b75505Sopenharmony_ci drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0); 922e5b75505Sopenharmony_ci break; 923e5b75505Sopenharmony_ci case WLAN_FC_STYPE_REASSOC_REQ: 924e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)) 925e5b75505Sopenharmony_ci break; 926e5b75505Sopenharmony_ci ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); 927e5b75505Sopenharmony_ci iebuf = mgmt->u.reassoc_req.variable; 928e5b75505Sopenharmony_ci drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); 929e5b75505Sopenharmony_ci break; 930e5b75505Sopenharmony_ci case WLAN_FC_STYPE_AUTH: 931e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) 932e5b75505Sopenharmony_ci break; 933e5b75505Sopenharmony_ci os_memset(&event, 0, sizeof(event)); 934e5b75505Sopenharmony_ci if (le_to_host16(mgmt->u.auth.auth_alg) == WLAN_AUTH_SAE) { 935e5b75505Sopenharmony_ci event.rx_mgmt.frame = buf; 936e5b75505Sopenharmony_ci event.rx_mgmt.frame_len = len; 937e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); 938e5b75505Sopenharmony_ci break; 939e5b75505Sopenharmony_ci } 940e5b75505Sopenharmony_ci os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); 941e5b75505Sopenharmony_ci os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN); 942e5b75505Sopenharmony_ci event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); 943e5b75505Sopenharmony_ci event.auth.status_code = 944e5b75505Sopenharmony_ci le_to_host16(mgmt->u.auth.status_code); 945e5b75505Sopenharmony_ci event.auth.auth_transaction = 946e5b75505Sopenharmony_ci le_to_host16(mgmt->u.auth.auth_transaction); 947e5b75505Sopenharmony_ci event.auth.ies = mgmt->u.auth.variable; 948e5b75505Sopenharmony_ci event.auth.ies_len = len - IEEE80211_HDRLEN - 949e5b75505Sopenharmony_ci sizeof(mgmt->u.auth); 950e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event); 951e5b75505Sopenharmony_ci break; 952e5b75505Sopenharmony_ci default: 953e5b75505Sopenharmony_ci break; 954e5b75505Sopenharmony_ci } 955e5b75505Sopenharmony_ci} 956e5b75505Sopenharmony_ci#endif /* ATHEROS_USE_RAW_RECEIVE */ 957e5b75505Sopenharmony_ci 958e5b75505Sopenharmony_cistatic int atheros_receive_pkt(struct atheros_driver_data *drv) 959e5b75505Sopenharmony_ci{ 960e5b75505Sopenharmony_ci int ret = 0; 961e5b75505Sopenharmony_ci struct ieee80211req_set_filter filt; 962e5b75505Sopenharmony_ci 963e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s Enter", __func__); 964e5b75505Sopenharmony_ci filt.app_filterype = 0; 965e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 966e5b75505Sopenharmony_ci filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ; 967e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 968e5b75505Sopenharmony_ci#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) 969e5b75505Sopenharmony_ci filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | 970e5b75505Sopenharmony_ci IEEE80211_FILTER_TYPE_AUTH | 971e5b75505Sopenharmony_ci IEEE80211_FILTER_TYPE_ACTION); 972e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 973e5b75505Sopenharmony_ci#ifdef CONFIG_WNM 974e5b75505Sopenharmony_ci filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; 975e5b75505Sopenharmony_ci#endif /* CONFIG_WNM */ 976e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 977e5b75505Sopenharmony_ci filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; 978e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 979e5b75505Sopenharmony_ci if (filt.app_filterype) { 980e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, 981e5b75505Sopenharmony_ci sizeof(struct ieee80211req_set_filter)); 982e5b75505Sopenharmony_ci if (ret) 983e5b75505Sopenharmony_ci return ret; 984e5b75505Sopenharmony_ci } 985e5b75505Sopenharmony_ci 986e5b75505Sopenharmony_ci#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) 987e5b75505Sopenharmony_ci drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, 988e5b75505Sopenharmony_ci atheros_raw_receive, drv, 1); 989e5b75505Sopenharmony_ci if (drv->sock_raw == NULL) 990e5b75505Sopenharmony_ci return -1; 991e5b75505Sopenharmony_ci#endif /* CONFIG_WPS || CONFIG_IEEE80211R || CONFIG_FILS */ 992e5b75505Sopenharmony_ci return ret; 993e5b75505Sopenharmony_ci} 994e5b75505Sopenharmony_ci 995e5b75505Sopenharmony_cistatic int atheros_reset_appfilter(struct atheros_driver_data *drv) 996e5b75505Sopenharmony_ci{ 997e5b75505Sopenharmony_ci struct ieee80211req_set_filter filt; 998e5b75505Sopenharmony_ci filt.app_filterype = 0; 999e5b75505Sopenharmony_ci return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, 1000e5b75505Sopenharmony_ci sizeof(struct ieee80211req_set_filter)); 1001e5b75505Sopenharmony_ci} 1002e5b75505Sopenharmony_ci 1003e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 1004e5b75505Sopenharmony_cistatic int 1005e5b75505Sopenharmony_ciatheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) 1006e5b75505Sopenharmony_ci{ 1007e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1008e5b75505Sopenharmony_ci u8 buf[512]; 1009e5b75505Sopenharmony_ci struct ieee80211req_getset_appiebuf *beac_ie; 1010e5b75505Sopenharmony_ci 1011e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__, 1012e5b75505Sopenharmony_ci (unsigned long) len, frametype); 1013e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len); 1014e5b75505Sopenharmony_ci 1015e5b75505Sopenharmony_ci beac_ie = (struct ieee80211req_getset_appiebuf *) buf; 1016e5b75505Sopenharmony_ci beac_ie->app_frmtype = frametype; 1017e5b75505Sopenharmony_ci beac_ie->app_buflen = len; 1018e5b75505Sopenharmony_ci if (ie) 1019e5b75505Sopenharmony_ci os_memcpy(&(beac_ie->app_buf[0]), ie, len); 1020e5b75505Sopenharmony_ci 1021e5b75505Sopenharmony_ci /* append the WPA/RSN IE if it is set already */ 1022e5b75505Sopenharmony_ci if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || 1023e5b75505Sopenharmony_ci (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && 1024e5b75505Sopenharmony_ci (drv->wpa_ie != NULL)) { 1025e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE", 1026e5b75505Sopenharmony_ci drv->wpa_ie); 1027e5b75505Sopenharmony_ci os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), 1028e5b75505Sopenharmony_ci wpabuf_len(drv->wpa_ie)); 1029e5b75505Sopenharmony_ci beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); 1030e5b75505Sopenharmony_ci } 1031e5b75505Sopenharmony_ci 1032e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF", 1033e5b75505Sopenharmony_ci beac_ie->app_buf, beac_ie->app_buflen); 1034e5b75505Sopenharmony_ci return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, 1035e5b75505Sopenharmony_ci sizeof(struct ieee80211req_getset_appiebuf) + 1036e5b75505Sopenharmony_ci beac_ie->app_buflen); 1037e5b75505Sopenharmony_ci} 1038e5b75505Sopenharmony_ci 1039e5b75505Sopenharmony_cistatic int 1040e5b75505Sopenharmony_ciatheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, 1041e5b75505Sopenharmony_ci const struct wpabuf *proberesp, 1042e5b75505Sopenharmony_ci const struct wpabuf *assocresp) 1043e5b75505Sopenharmony_ci{ 1044e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1045e5b75505Sopenharmony_ci 1046e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon); 1047e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp", 1048e5b75505Sopenharmony_ci proberesp); 1049e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp", 1050e5b75505Sopenharmony_ci assocresp); 1051e5b75505Sopenharmony_ci wpabuf_free(drv->wps_beacon_ie); 1052e5b75505Sopenharmony_ci drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; 1053e5b75505Sopenharmony_ci wpabuf_free(drv->wps_probe_resp_ie); 1054e5b75505Sopenharmony_ci drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL; 1055e5b75505Sopenharmony_ci 1056e5b75505Sopenharmony_ci atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, 1057e5b75505Sopenharmony_ci assocresp ? wpabuf_len(assocresp) : 0, 1058e5b75505Sopenharmony_ci IEEE80211_APPIE_FRAME_ASSOC_RESP); 1059e5b75505Sopenharmony_ci if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, 1060e5b75505Sopenharmony_ci beacon ? wpabuf_len(beacon) : 0, 1061e5b75505Sopenharmony_ci IEEE80211_APPIE_FRAME_BEACON)) 1062e5b75505Sopenharmony_ci return -1; 1063e5b75505Sopenharmony_ci return atheros_set_wps_ie(priv, 1064e5b75505Sopenharmony_ci proberesp ? wpabuf_head(proberesp) : NULL, 1065e5b75505Sopenharmony_ci proberesp ? wpabuf_len(proberesp): 0, 1066e5b75505Sopenharmony_ci IEEE80211_APPIE_FRAME_PROBE_RESP); 1067e5b75505Sopenharmony_ci} 1068e5b75505Sopenharmony_ci#else /* CONFIG_WPS */ 1069e5b75505Sopenharmony_ci#define atheros_set_ap_wps_ie NULL 1070e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 1071e5b75505Sopenharmony_ci 1072e5b75505Sopenharmony_ci#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1073e5b75505Sopenharmony_cistatic int 1074e5b75505Sopenharmony_ciatheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params) 1075e5b75505Sopenharmony_ci{ 1076e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1077e5b75505Sopenharmony_ci struct ieee80211req_mlme mlme; 1078e5b75505Sopenharmony_ci int ret; 1079e5b75505Sopenharmony_ci 1080e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d", 1081e5b75505Sopenharmony_ci __func__, ether_sprintf(params->addr), params->status); 1082e5b75505Sopenharmony_ci 1083e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 1084e5b75505Sopenharmony_ci /* Copy FILS AAD parameters if the driver supports FILS */ 1085e5b75505Sopenharmony_ci if (params->fils_auth && drv->fils_en) { 1086e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: im_op IEEE80211_MLME_AUTH_FILS", 1087e5b75505Sopenharmony_ci __func__); 1088e5b75505Sopenharmony_ci os_memcpy(mlme.fils_aad.ANonce, params->fils_anonce, 1089e5b75505Sopenharmony_ci IEEE80211_FILS_NONCE_LEN); 1090e5b75505Sopenharmony_ci os_memcpy(mlme.fils_aad.SNonce, params->fils_snonce, 1091e5b75505Sopenharmony_ci IEEE80211_FILS_NONCE_LEN); 1092e5b75505Sopenharmony_ci os_memcpy(mlme.fils_aad.kek, params->fils_kek, 1093e5b75505Sopenharmony_ci IEEE80211_MAX_WPA_KEK_LEN); 1094e5b75505Sopenharmony_ci mlme.fils_aad.kek_len = params->fils_kek_len; 1095e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_AUTH_FILS; 1096e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: ANonce", 1097e5b75505Sopenharmony_ci mlme.fils_aad.ANonce, FILS_NONCE_LEN); 1098e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: SNonce", 1099e5b75505Sopenharmony_ci mlme.fils_aad.SNonce, FILS_NONCE_LEN); 1100e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", 1101e5b75505Sopenharmony_ci mlme.fils_aad.kek, mlme.fils_aad.kek_len); 1102e5b75505Sopenharmony_ci } else { 1103e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_AUTH; 1104e5b75505Sopenharmony_ci } 1105e5b75505Sopenharmony_ci#else /* CONFIG_FILS */ 1106e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_AUTH; 1107e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 1108e5b75505Sopenharmony_ci 1109e5b75505Sopenharmony_ci mlme.im_reason = params->status; 1110e5b75505Sopenharmony_ci mlme.im_seq = params->seq; 1111e5b75505Sopenharmony_ci os_memcpy(mlme.im_macaddr, params->addr, IEEE80211_ADDR_LEN); 1112e5b75505Sopenharmony_ci mlme.im_optie_len = params->len; 1113e5b75505Sopenharmony_ci if (params->len) { 1114e5b75505Sopenharmony_ci if (params->len < IEEE80211_MAX_OPT_IE) { 1115e5b75505Sopenharmony_ci os_memcpy(mlme.im_optie, params->ie, params->len); 1116e5b75505Sopenharmony_ci } else { 1117e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " 1118e5b75505Sopenharmony_ci "opt_ie STA (addr " MACSTR " reason %d, " 1119e5b75505Sopenharmony_ci "ie_len %d)", 1120e5b75505Sopenharmony_ci __func__, MAC2STR(params->addr), 1121e5b75505Sopenharmony_ci params->status, (int) params->len); 1122e5b75505Sopenharmony_ci return -1; 1123e5b75505Sopenharmony_ci } 1124e5b75505Sopenharmony_ci } 1125e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 1126e5b75505Sopenharmony_ci if (ret < 0) { 1127e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR 1128e5b75505Sopenharmony_ci " reason %d)", 1129e5b75505Sopenharmony_ci __func__, MAC2STR(params->addr), params->status); 1130e5b75505Sopenharmony_ci } 1131e5b75505Sopenharmony_ci return ret; 1132e5b75505Sopenharmony_ci} 1133e5b75505Sopenharmony_ci 1134e5b75505Sopenharmony_cistatic int 1135e5b75505Sopenharmony_ciatheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, 1136e5b75505Sopenharmony_ci int reassoc, u16 status_code, const u8 *ie, size_t len) 1137e5b75505Sopenharmony_ci{ 1138e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1139e5b75505Sopenharmony_ci struct ieee80211req_mlme mlme; 1140e5b75505Sopenharmony_ci int ret; 1141e5b75505Sopenharmony_ci 1142e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d", 1143e5b75505Sopenharmony_ci __func__, ether_sprintf(addr), status_code, reassoc); 1144e5b75505Sopenharmony_ci 1145e5b75505Sopenharmony_ci if (reassoc) 1146e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_REASSOC; 1147e5b75505Sopenharmony_ci else 1148e5b75505Sopenharmony_ci mlme.im_op = IEEE80211_MLME_ASSOC; 1149e5b75505Sopenharmony_ci mlme.im_reason = status_code; 1150e5b75505Sopenharmony_ci os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 1151e5b75505Sopenharmony_ci mlme.im_optie_len = len; 1152e5b75505Sopenharmony_ci if (len) { 1153e5b75505Sopenharmony_ci if (len < IEEE80211_MAX_OPT_IE) { 1154e5b75505Sopenharmony_ci os_memcpy(mlme.im_optie, ie, len); 1155e5b75505Sopenharmony_ci } else { 1156e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " 1157e5b75505Sopenharmony_ci "opt_ie STA (addr " MACSTR " reason %d, " 1158e5b75505Sopenharmony_ci "ie_len %d)", 1159e5b75505Sopenharmony_ci __func__, MAC2STR(addr), status_code, 1160e5b75505Sopenharmony_ci (int) len); 1161e5b75505Sopenharmony_ci return -1; 1162e5b75505Sopenharmony_ci } 1163e5b75505Sopenharmony_ci } 1164e5b75505Sopenharmony_ci ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); 1165e5b75505Sopenharmony_ci if (ret < 0) { 1166e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR 1167e5b75505Sopenharmony_ci " reason %d)", 1168e5b75505Sopenharmony_ci __func__, MAC2STR(addr), status_code); 1169e5b75505Sopenharmony_ci } 1170e5b75505Sopenharmony_ci return ret; 1171e5b75505Sopenharmony_ci} 1172e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 1173e5b75505Sopenharmony_ci 1174e5b75505Sopenharmony_cistatic void 1175e5b75505Sopenharmony_ciatheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) 1176e5b75505Sopenharmony_ci{ 1177e5b75505Sopenharmony_ci struct hostapd_data *hapd = drv->hapd; 1178e5b75505Sopenharmony_ci struct ieee80211req_wpaie ie; 1179e5b75505Sopenharmony_ci int ielen = 0; 1180e5b75505Sopenharmony_ci u8 *iebuf = NULL; 1181e5b75505Sopenharmony_ci 1182e5b75505Sopenharmony_ci /* 1183e5b75505Sopenharmony_ci * Fetch negotiated WPA/RSN parameters from the system. 1184e5b75505Sopenharmony_ci */ 1185e5b75505Sopenharmony_ci os_memset(&ie, 0, sizeof(ie)); 1186e5b75505Sopenharmony_ci os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); 1187e5b75505Sopenharmony_ci if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { 1188e5b75505Sopenharmony_ci /* 1189e5b75505Sopenharmony_ci * See ATH_WPS_IE comment in the beginning of the file for a 1190e5b75505Sopenharmony_ci * possible cause for the failure.. 1191e5b75505Sopenharmony_ci */ 1192e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", 1193e5b75505Sopenharmony_ci __func__, strerror(errno)); 1194e5b75505Sopenharmony_ci goto no_ie; 1195e5b75505Sopenharmony_ci } 1196e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", 1197e5b75505Sopenharmony_ci ie.wpa_ie, IEEE80211_MAX_OPT_IE); 1198e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", 1199e5b75505Sopenharmony_ci ie.rsn_ie, IEEE80211_MAX_OPT_IE); 1200e5b75505Sopenharmony_ci#ifdef ATH_WPS_IE 1201e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", 1202e5b75505Sopenharmony_ci ie.wps_ie, IEEE80211_MAX_OPT_IE); 1203e5b75505Sopenharmony_ci#endif /* ATH_WPS_IE */ 1204e5b75505Sopenharmony_ci iebuf = ie.wpa_ie; 1205e5b75505Sopenharmony_ci /* atheros seems to return some random data if WPA/RSN IE is not set. 1206e5b75505Sopenharmony_ci * Assume the IE was not included if the IE type is unknown. */ 1207e5b75505Sopenharmony_ci if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) 1208e5b75505Sopenharmony_ci iebuf[1] = 0; 1209e5b75505Sopenharmony_ci if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { 1210e5b75505Sopenharmony_ci /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not 1211e5b75505Sopenharmony_ci * set. This is needed for WPA2. */ 1212e5b75505Sopenharmony_ci iebuf = ie.rsn_ie; 1213e5b75505Sopenharmony_ci if (iebuf[0] != WLAN_EID_RSN) 1214e5b75505Sopenharmony_ci iebuf[1] = 0; 1215e5b75505Sopenharmony_ci } 1216e5b75505Sopenharmony_ci 1217e5b75505Sopenharmony_ci ielen = iebuf[1]; 1218e5b75505Sopenharmony_ci 1219e5b75505Sopenharmony_ci#ifdef ATH_WPS_IE 1220e5b75505Sopenharmony_ci /* if WPS IE is present, preference is given to WPS */ 1221e5b75505Sopenharmony_ci if (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie.wps_ie[1] > 0) { 1222e5b75505Sopenharmony_ci iebuf = ie.wps_ie; 1223e5b75505Sopenharmony_ci ielen = ie.wps_ie[1]; 1224e5b75505Sopenharmony_ci } 1225e5b75505Sopenharmony_ci#endif /* ATH_WPS_IE */ 1226e5b75505Sopenharmony_ci 1227e5b75505Sopenharmony_ci if (ielen == 0) 1228e5b75505Sopenharmony_ci iebuf = NULL; 1229e5b75505Sopenharmony_ci else 1230e5b75505Sopenharmony_ci ielen += 2; 1231e5b75505Sopenharmony_ci 1232e5b75505Sopenharmony_cino_ie: 1233e5b75505Sopenharmony_ci drv_event_assoc(hapd, addr, iebuf, ielen, 0); 1234e5b75505Sopenharmony_ci 1235e5b75505Sopenharmony_ci if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { 1236e5b75505Sopenharmony_ci /* Cached accounting data is not valid anymore. */ 1237e5b75505Sopenharmony_ci os_memset(drv->acct_mac, 0, ETH_ALEN); 1238e5b75505Sopenharmony_ci os_memset(&drv->acct_data, 0, sizeof(drv->acct_data)); 1239e5b75505Sopenharmony_ci } 1240e5b75505Sopenharmony_ci} 1241e5b75505Sopenharmony_ci 1242e5b75505Sopenharmony_cistatic void 1243e5b75505Sopenharmony_ciatheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, 1244e5b75505Sopenharmony_ci char *custom, char *end) 1245e5b75505Sopenharmony_ci{ 1246e5b75505Sopenharmony_ci#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ 1247e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); 1248e5b75505Sopenharmony_ci 1249e5b75505Sopenharmony_ci if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { 1250e5b75505Sopenharmony_ci char *pos; 1251e5b75505Sopenharmony_ci u8 addr[ETH_ALEN]; 1252e5b75505Sopenharmony_ci pos = os_strstr(custom, "addr="); 1253e5b75505Sopenharmony_ci if (pos == NULL) { 1254e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1255e5b75505Sopenharmony_ci "MLME-MICHAELMICFAILURE.indication " 1256e5b75505Sopenharmony_ci "without sender address ignored"); 1257e5b75505Sopenharmony_ci return; 1258e5b75505Sopenharmony_ci } 1259e5b75505Sopenharmony_ci pos += 5; 1260e5b75505Sopenharmony_ci if (hwaddr_aton(pos, addr) == 0) { 1261e5b75505Sopenharmony_ci union wpa_event_data data; 1262e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 1263e5b75505Sopenharmony_ci data.michael_mic_failure.unicast = 1; 1264e5b75505Sopenharmony_ci data.michael_mic_failure.src = addr; 1265e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, 1266e5b75505Sopenharmony_ci EVENT_MICHAEL_MIC_FAILURE, &data); 1267e5b75505Sopenharmony_ci } else { 1268e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1269e5b75505Sopenharmony_ci "MLME-MICHAELMICFAILURE.indication " 1270e5b75505Sopenharmony_ci "with invalid MAC address"); 1271e5b75505Sopenharmony_ci } 1272e5b75505Sopenharmony_ci } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { 1273e5b75505Sopenharmony_ci char *key, *value; 1274e5b75505Sopenharmony_ci u32 val; 1275e5b75505Sopenharmony_ci key = custom; 1276e5b75505Sopenharmony_ci while ((key = os_strchr(key, '\n')) != NULL) { 1277e5b75505Sopenharmony_ci key++; 1278e5b75505Sopenharmony_ci value = os_strchr(key, '='); 1279e5b75505Sopenharmony_ci if (value == NULL) 1280e5b75505Sopenharmony_ci continue; 1281e5b75505Sopenharmony_ci *value++ = '\0'; 1282e5b75505Sopenharmony_ci val = strtoul(value, NULL, 10); 1283e5b75505Sopenharmony_ci if (os_strcmp(key, "mac") == 0) 1284e5b75505Sopenharmony_ci hwaddr_aton(value, drv->acct_mac); 1285e5b75505Sopenharmony_ci else if (os_strcmp(key, "rx_packets") == 0) 1286e5b75505Sopenharmony_ci drv->acct_data.rx_packets = val; 1287e5b75505Sopenharmony_ci else if (os_strcmp(key, "tx_packets") == 0) 1288e5b75505Sopenharmony_ci drv->acct_data.tx_packets = val; 1289e5b75505Sopenharmony_ci else if (os_strcmp(key, "rx_bytes") == 0) 1290e5b75505Sopenharmony_ci drv->acct_data.rx_bytes = val; 1291e5b75505Sopenharmony_ci else if (os_strcmp(key, "tx_bytes") == 0) 1292e5b75505Sopenharmony_ci drv->acct_data.tx_bytes = val; 1293e5b75505Sopenharmony_ci key = value; 1294e5b75505Sopenharmony_ci } 1295e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 1296e5b75505Sopenharmony_ci } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { 1297e5b75505Sopenharmony_ci /* Some atheros kernels send push button as a wireless event */ 1298e5b75505Sopenharmony_ci /* PROBLEM! this event is received for ALL BSSs ... 1299e5b75505Sopenharmony_ci * so all are enabled for WPS... ugh. 1300e5b75505Sopenharmony_ci */ 1301e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); 1302e5b75505Sopenharmony_ci } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) { 1303e5b75505Sopenharmony_ci /* 1304e5b75505Sopenharmony_ci * Atheros driver uses a hack to pass Probe Request frames as a 1305e5b75505Sopenharmony_ci * binary data in the custom wireless event. The old way (using 1306e5b75505Sopenharmony_ci * packet sniffing) didn't work when bridging. 1307e5b75505Sopenharmony_ci * Format: "Manage.prob_req <frame len>" | zero padding | frame 1308e5b75505Sopenharmony_ci */ 1309e5b75505Sopenharmony_ci int len = atoi(custom + 16); 1310e5b75505Sopenharmony_ci if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1311e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event " 1312e5b75505Sopenharmony_ci "length %d", len); 1313e5b75505Sopenharmony_ci return; 1314e5b75505Sopenharmony_ci } 1315e5b75505Sopenharmony_ci atheros_raw_receive(drv, NULL, 1316e5b75505Sopenharmony_ci (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1317e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 1318e5b75505Sopenharmony_ci#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1319e5b75505Sopenharmony_ci } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) { 1320e5b75505Sopenharmony_ci /* Format: "Manage.assoc_req <frame len>" | zero padding | 1321e5b75505Sopenharmony_ci * frame */ 1322e5b75505Sopenharmony_ci int len = atoi(custom + 17); 1323e5b75505Sopenharmony_ci if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1324e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1325e5b75505Sopenharmony_ci "Invalid Manage.assoc_req event length %d", 1326e5b75505Sopenharmony_ci len); 1327e5b75505Sopenharmony_ci return; 1328e5b75505Sopenharmony_ci } 1329e5b75505Sopenharmony_ci atheros_raw_receive(drv, NULL, 1330e5b75505Sopenharmony_ci (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1331e5b75505Sopenharmony_ci } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { 1332e5b75505Sopenharmony_ci /* Format: "Manage.auth <frame len>" | zero padding | frame */ 1333e5b75505Sopenharmony_ci int len = atoi(custom + 12); 1334e5b75505Sopenharmony_ci if (len < 0 || 1335e5b75505Sopenharmony_ci MGMT_FRAM_TAG_SIZE + len > end - custom) { 1336e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1337e5b75505Sopenharmony_ci "Invalid Manage.auth event length %d", len); 1338e5b75505Sopenharmony_ci return; 1339e5b75505Sopenharmony_ci } 1340e5b75505Sopenharmony_ci atheros_raw_receive(drv, NULL, 1341e5b75505Sopenharmony_ci (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1342e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */ 1343e5b75505Sopenharmony_ci#ifdef ATHEROS_USE_RAW_RECEIVE 1344e5b75505Sopenharmony_ci } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { 1345e5b75505Sopenharmony_ci /* Format: "Manage.assoc_req <frame len>" | zero padding | frame 1346e5b75505Sopenharmony_ci */ 1347e5b75505Sopenharmony_ci int len = atoi(custom + 14); 1348e5b75505Sopenharmony_ci if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { 1349e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1350e5b75505Sopenharmony_ci "Invalid Manage.action event length %d", 1351e5b75505Sopenharmony_ci len); 1352e5b75505Sopenharmony_ci return; 1353e5b75505Sopenharmony_ci } 1354e5b75505Sopenharmony_ci atheros_raw_receive(drv, NULL, 1355e5b75505Sopenharmony_ci (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); 1356e5b75505Sopenharmony_ci#endif /* ATHEROS_USE_RAW_RECEIVE */ 1357e5b75505Sopenharmony_ci } 1358e5b75505Sopenharmony_ci} 1359e5b75505Sopenharmony_ci 1360e5b75505Sopenharmony_ci 1361e5b75505Sopenharmony_cistatic void send_action_cb_event(struct atheros_driver_data *drv, 1362e5b75505Sopenharmony_ci char *data, size_t data_len) 1363e5b75505Sopenharmony_ci{ 1364e5b75505Sopenharmony_ci union wpa_event_data event; 1365e5b75505Sopenharmony_ci struct ieee80211_send_action_cb *sa; 1366e5b75505Sopenharmony_ci const struct ieee80211_hdr *hdr; 1367e5b75505Sopenharmony_ci u16 fc; 1368e5b75505Sopenharmony_ci 1369e5b75505Sopenharmony_ci if (data_len < sizeof(*sa) + 24) { 1370e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1371e5b75505Sopenharmony_ci "athr: Too short event message (data_len=%d sizeof(*sa)=%d)", 1372e5b75505Sopenharmony_ci (int) data_len, (int) sizeof(*sa)); 1373e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "athr: Short event message", 1374e5b75505Sopenharmony_ci data, data_len); 1375e5b75505Sopenharmony_ci return; 1376e5b75505Sopenharmony_ci } 1377e5b75505Sopenharmony_ci 1378e5b75505Sopenharmony_ci sa = (struct ieee80211_send_action_cb *) data; 1379e5b75505Sopenharmony_ci 1380e5b75505Sopenharmony_ci hdr = (const struct ieee80211_hdr *) (sa + 1); 1381e5b75505Sopenharmony_ci fc = le_to_host16(hdr->frame_control); 1382e5b75505Sopenharmony_ci 1383e5b75505Sopenharmony_ci os_memset(&event, 0, sizeof(event)); 1384e5b75505Sopenharmony_ci event.tx_status.type = WLAN_FC_GET_TYPE(fc); 1385e5b75505Sopenharmony_ci event.tx_status.stype = WLAN_FC_GET_STYPE(fc); 1386e5b75505Sopenharmony_ci event.tx_status.dst = sa->dst_addr; 1387e5b75505Sopenharmony_ci event.tx_status.data = (const u8 *) hdr; 1388e5b75505Sopenharmony_ci event.tx_status.data_len = data_len - sizeof(*sa); 1389e5b75505Sopenharmony_ci event.tx_status.ack = sa->ack; 1390e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event); 1391e5b75505Sopenharmony_ci} 1392e5b75505Sopenharmony_ci 1393e5b75505Sopenharmony_ci 1394e5b75505Sopenharmony_ci/* 1395e5b75505Sopenharmony_ci* Handle size of data problem. WEXT only allows data of 256 bytes for custom 1396e5b75505Sopenharmony_ci* events, and p2p data can be much bigger. So the athr driver sends a small 1397e5b75505Sopenharmony_ci* event telling me to collect the big data with an ioctl. 1398e5b75505Sopenharmony_ci* On the first event, send all pending events to supplicant. 1399e5b75505Sopenharmony_ci*/ 1400e5b75505Sopenharmony_cistatic void fetch_pending_big_events(struct atheros_driver_data *drv) 1401e5b75505Sopenharmony_ci{ 1402e5b75505Sopenharmony_ci union wpa_event_data event; 1403e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt; 1404e5b75505Sopenharmony_ci u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */ 1405e5b75505Sopenharmony_ci u16 fc, stype; 1406e5b75505Sopenharmony_ci struct iwreq iwr; 1407e5b75505Sopenharmony_ci size_t data_len; 1408e5b75505Sopenharmony_ci u32 freq, frame_type; 1409e5b75505Sopenharmony_ci 1410e5b75505Sopenharmony_ci while (1) { 1411e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1412e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1413e5b75505Sopenharmony_ci 1414e5b75505Sopenharmony_ci iwr.u.data.pointer = (void *) tbuf; 1415e5b75505Sopenharmony_ci iwr.u.data.length = sizeof(tbuf); 1416e5b75505Sopenharmony_ci iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME; 1417e5b75505Sopenharmony_ci 1418e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) 1419e5b75505Sopenharmony_ci < 0) { 1420e5b75505Sopenharmony_ci if (errno == ENOSPC) { 1421e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s:%d exit", 1422e5b75505Sopenharmony_ci __func__, __LINE__); 1423e5b75505Sopenharmony_ci return; 1424e5b75505Sopenharmony_ci } 1425e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM[" 1426e5b75505Sopenharmony_ci "P2P_FETCH_FRAME] failed: %s", 1427e5b75505Sopenharmony_ci __func__, strerror(errno)); 1428e5b75505Sopenharmony_ci return; 1429e5b75505Sopenharmony_ci } 1430e5b75505Sopenharmony_ci data_len = iwr.u.data.length; 1431e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data", 1432e5b75505Sopenharmony_ci (u8 *) tbuf, data_len); 1433e5b75505Sopenharmony_ci if (data_len < sizeof(freq) + sizeof(frame_type) + 24) { 1434e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "athr: frame too short"); 1435e5b75505Sopenharmony_ci continue; 1436e5b75505Sopenharmony_ci } 1437e5b75505Sopenharmony_ci os_memcpy(&freq, tbuf, sizeof(freq)); 1438e5b75505Sopenharmony_ci os_memcpy(&frame_type, &tbuf[sizeof(freq)], 1439e5b75505Sopenharmony_ci sizeof(frame_type)); 1440e5b75505Sopenharmony_ci mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)]; 1441e5b75505Sopenharmony_ci data_len -= sizeof(freq) + sizeof(frame_type); 1442e5b75505Sopenharmony_ci 1443e5b75505Sopenharmony_ci if (frame_type == IEEE80211_EV_RX_MGMT) { 1444e5b75505Sopenharmony_ci fc = le_to_host16(mgmt->frame_control); 1445e5b75505Sopenharmony_ci stype = WLAN_FC_GET_STYPE(fc); 1446e5b75505Sopenharmony_ci 1447e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u " 1448e5b75505Sopenharmony_ci "freq=%u len=%u", stype, freq, (int) data_len); 1449e5b75505Sopenharmony_ci 1450e5b75505Sopenharmony_ci if (stype == WLAN_FC_STYPE_ACTION) { 1451e5b75505Sopenharmony_ci os_memset(&event, 0, sizeof(event)); 1452e5b75505Sopenharmony_ci event.rx_mgmt.frame = (const u8 *) mgmt; 1453e5b75505Sopenharmony_ci event.rx_mgmt.frame_len = data_len; 1454e5b75505Sopenharmony_ci wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, 1455e5b75505Sopenharmony_ci &event); 1456e5b75505Sopenharmony_ci continue; 1457e5b75505Sopenharmony_ci } 1458e5b75505Sopenharmony_ci } else if (frame_type == IEEE80211_EV_P2P_SEND_ACTION_CB) { 1459e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1460e5b75505Sopenharmony_ci "%s: ACTION_CB frame_type=%u len=%zu", 1461e5b75505Sopenharmony_ci __func__, frame_type, data_len); 1462e5b75505Sopenharmony_ci send_action_cb_event(drv, (void *) mgmt, data_len); 1463e5b75505Sopenharmony_ci } else { 1464e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "athr: %s unknown type %d", 1465e5b75505Sopenharmony_ci __func__, frame_type); 1466e5b75505Sopenharmony_ci continue; 1467e5b75505Sopenharmony_ci } 1468e5b75505Sopenharmony_ci } 1469e5b75505Sopenharmony_ci} 1470e5b75505Sopenharmony_ci 1471e5b75505Sopenharmony_cistatic void 1472e5b75505Sopenharmony_ciatheros_wireless_event_atheros_custom(struct atheros_driver_data *drv, 1473e5b75505Sopenharmony_ci int opcode, char *buf, int len) 1474e5b75505Sopenharmony_ci{ 1475e5b75505Sopenharmony_ci switch (opcode) { 1476e5b75505Sopenharmony_ci case IEEE80211_EV_P2P_SEND_ACTION_CB: 1477e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: EV_P2P_SEND_ACTION_CB"); 1478e5b75505Sopenharmony_ci fetch_pending_big_events(drv); 1479e5b75505Sopenharmony_ci break; 1480e5b75505Sopenharmony_ci case IEEE80211_EV_RX_MGMT: 1481e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT"); 1482e5b75505Sopenharmony_ci fetch_pending_big_events(drv); 1483e5b75505Sopenharmony_ci break; 1484e5b75505Sopenharmony_ci default: 1485e5b75505Sopenharmony_ci break; 1486e5b75505Sopenharmony_ci } 1487e5b75505Sopenharmony_ci} 1488e5b75505Sopenharmony_ci 1489e5b75505Sopenharmony_cistatic void 1490e5b75505Sopenharmony_ciatheros_wireless_event_wireless(struct atheros_driver_data *drv, 1491e5b75505Sopenharmony_ci char *data, unsigned int len) 1492e5b75505Sopenharmony_ci{ 1493e5b75505Sopenharmony_ci struct iw_event iwe_buf, *iwe = &iwe_buf; 1494e5b75505Sopenharmony_ci char *pos, *end, *custom, *buf; 1495e5b75505Sopenharmony_ci 1496e5b75505Sopenharmony_ci pos = data; 1497e5b75505Sopenharmony_ci end = data + len; 1498e5b75505Sopenharmony_ci 1499e5b75505Sopenharmony_ci while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { 1500e5b75505Sopenharmony_ci /* Event data may be unaligned, so make a local, aligned copy 1501e5b75505Sopenharmony_ci * before processing. */ 1502e5b75505Sopenharmony_ci os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); 1503e5b75505Sopenharmony_ci wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", 1504e5b75505Sopenharmony_ci iwe->cmd, iwe->len); 1505e5b75505Sopenharmony_ci if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) 1506e5b75505Sopenharmony_ci return; 1507e5b75505Sopenharmony_ci 1508e5b75505Sopenharmony_ci custom = pos + IW_EV_POINT_LEN; 1509e5b75505Sopenharmony_ci if (drv->we_version > 18 && 1510e5b75505Sopenharmony_ci (iwe->cmd == IWEVMICHAELMICFAILURE || 1511e5b75505Sopenharmony_ci iwe->cmd == IWEVASSOCREQIE || 1512e5b75505Sopenharmony_ci iwe->cmd == IWEVCUSTOM)) { 1513e5b75505Sopenharmony_ci /* WE-19 removed the pointer from struct iw_point */ 1514e5b75505Sopenharmony_ci char *dpos = (char *) &iwe_buf.u.data.length; 1515e5b75505Sopenharmony_ci int dlen = dpos - (char *) &iwe_buf; 1516e5b75505Sopenharmony_ci os_memcpy(dpos, pos + IW_EV_LCP_LEN, 1517e5b75505Sopenharmony_ci sizeof(struct iw_event) - dlen); 1518e5b75505Sopenharmony_ci } else { 1519e5b75505Sopenharmony_ci os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); 1520e5b75505Sopenharmony_ci custom += IW_EV_POINT_OFF; 1521e5b75505Sopenharmony_ci } 1522e5b75505Sopenharmony_ci 1523e5b75505Sopenharmony_ci switch (iwe->cmd) { 1524e5b75505Sopenharmony_ci case IWEVEXPIRED: 1525e5b75505Sopenharmony_ci drv_event_disassoc(drv->hapd, 1526e5b75505Sopenharmony_ci (u8 *) iwe->u.addr.sa_data); 1527e5b75505Sopenharmony_ci break; 1528e5b75505Sopenharmony_ci case IWEVREGISTERED: 1529e5b75505Sopenharmony_ci atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data); 1530e5b75505Sopenharmony_ci break; 1531e5b75505Sopenharmony_ci case IWEVASSOCREQIE: 1532e5b75505Sopenharmony_ci /* Driver hack.. Use IWEVASSOCREQIE to bypass 1533e5b75505Sopenharmony_ci * IWEVCUSTOM size limitations. Need to handle this 1534e5b75505Sopenharmony_ci * just like IWEVCUSTOM. 1535e5b75505Sopenharmony_ci */ 1536e5b75505Sopenharmony_ci case IWEVCUSTOM: 1537e5b75505Sopenharmony_ci if (iwe->u.data.length > end - custom) 1538e5b75505Sopenharmony_ci return; 1539e5b75505Sopenharmony_ci buf = os_malloc(iwe->u.data.length + 1); 1540e5b75505Sopenharmony_ci if (buf == NULL) 1541e5b75505Sopenharmony_ci return; /* XXX */ 1542e5b75505Sopenharmony_ci os_memcpy(buf, custom, iwe->u.data.length); 1543e5b75505Sopenharmony_ci buf[iwe->u.data.length] = '\0'; 1544e5b75505Sopenharmony_ci 1545e5b75505Sopenharmony_ci if (iwe->u.data.flags != 0) { 1546e5b75505Sopenharmony_ci atheros_wireless_event_atheros_custom( 1547e5b75505Sopenharmony_ci drv, (int) iwe->u.data.flags, 1548e5b75505Sopenharmony_ci buf, len); 1549e5b75505Sopenharmony_ci } else { 1550e5b75505Sopenharmony_ci atheros_wireless_event_wireless_custom( 1551e5b75505Sopenharmony_ci drv, buf, buf + iwe->u.data.length); 1552e5b75505Sopenharmony_ci } 1553e5b75505Sopenharmony_ci os_free(buf); 1554e5b75505Sopenharmony_ci break; 1555e5b75505Sopenharmony_ci } 1556e5b75505Sopenharmony_ci 1557e5b75505Sopenharmony_ci pos += iwe->len; 1558e5b75505Sopenharmony_ci } 1559e5b75505Sopenharmony_ci} 1560e5b75505Sopenharmony_ci 1561e5b75505Sopenharmony_ci 1562e5b75505Sopenharmony_cistatic void 1563e5b75505Sopenharmony_ciatheros_wireless_event_rtm_newlink(void *ctx, 1564e5b75505Sopenharmony_ci struct ifinfomsg *ifi, u8 *buf, size_t len) 1565e5b75505Sopenharmony_ci{ 1566e5b75505Sopenharmony_ci struct atheros_driver_data *drv = ctx; 1567e5b75505Sopenharmony_ci int attrlen, rta_len; 1568e5b75505Sopenharmony_ci struct rtattr *attr; 1569e5b75505Sopenharmony_ci 1570e5b75505Sopenharmony_ci if (ifi->ifi_index != drv->ifindex) 1571e5b75505Sopenharmony_ci return; 1572e5b75505Sopenharmony_ci 1573e5b75505Sopenharmony_ci attrlen = len; 1574e5b75505Sopenharmony_ci attr = (struct rtattr *) buf; 1575e5b75505Sopenharmony_ci 1576e5b75505Sopenharmony_ci rta_len = RTA_ALIGN(sizeof(struct rtattr)); 1577e5b75505Sopenharmony_ci while (RTA_OK(attr, attrlen)) { 1578e5b75505Sopenharmony_ci if (attr->rta_type == IFLA_WIRELESS) { 1579e5b75505Sopenharmony_ci atheros_wireless_event_wireless( 1580e5b75505Sopenharmony_ci drv, ((char *) attr) + rta_len, 1581e5b75505Sopenharmony_ci attr->rta_len - rta_len); 1582e5b75505Sopenharmony_ci } 1583e5b75505Sopenharmony_ci attr = RTA_NEXT(attr, attrlen); 1584e5b75505Sopenharmony_ci } 1585e5b75505Sopenharmony_ci} 1586e5b75505Sopenharmony_ci 1587e5b75505Sopenharmony_ci 1588e5b75505Sopenharmony_cistatic int 1589e5b75505Sopenharmony_ciatheros_get_we_version(struct atheros_driver_data *drv) 1590e5b75505Sopenharmony_ci{ 1591e5b75505Sopenharmony_ci struct iw_range *range; 1592e5b75505Sopenharmony_ci struct iwreq iwr; 1593e5b75505Sopenharmony_ci int minlen; 1594e5b75505Sopenharmony_ci size_t buflen; 1595e5b75505Sopenharmony_ci 1596e5b75505Sopenharmony_ci drv->we_version = 0; 1597e5b75505Sopenharmony_ci 1598e5b75505Sopenharmony_ci /* 1599e5b75505Sopenharmony_ci * Use larger buffer than struct iw_range in order to allow the 1600e5b75505Sopenharmony_ci * structure to grow in the future. 1601e5b75505Sopenharmony_ci */ 1602e5b75505Sopenharmony_ci buflen = sizeof(struct iw_range) + 500; 1603e5b75505Sopenharmony_ci range = os_zalloc(buflen); 1604e5b75505Sopenharmony_ci if (range == NULL) 1605e5b75505Sopenharmony_ci return -1; 1606e5b75505Sopenharmony_ci 1607e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1608e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1609e5b75505Sopenharmony_ci iwr.u.data.pointer = (caddr_t) range; 1610e5b75505Sopenharmony_ci iwr.u.data.length = buflen; 1611e5b75505Sopenharmony_ci 1612e5b75505Sopenharmony_ci minlen = ((char *) &range->enc_capa) - (char *) range + 1613e5b75505Sopenharmony_ci sizeof(range->enc_capa); 1614e5b75505Sopenharmony_ci 1615e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { 1616e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", 1617e5b75505Sopenharmony_ci strerror(errno)); 1618e5b75505Sopenharmony_ci os_free(range); 1619e5b75505Sopenharmony_ci return -1; 1620e5b75505Sopenharmony_ci } else if (iwr.u.data.length >= minlen && 1621e5b75505Sopenharmony_ci range->we_version_compiled >= 18) { 1622e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " 1623e5b75505Sopenharmony_ci "WE(source)=%d enc_capa=0x%x", 1624e5b75505Sopenharmony_ci range->we_version_compiled, 1625e5b75505Sopenharmony_ci range->we_version_source, 1626e5b75505Sopenharmony_ci range->enc_capa); 1627e5b75505Sopenharmony_ci drv->we_version = range->we_version_compiled; 1628e5b75505Sopenharmony_ci } 1629e5b75505Sopenharmony_ci 1630e5b75505Sopenharmony_ci os_free(range); 1631e5b75505Sopenharmony_ci return 0; 1632e5b75505Sopenharmony_ci} 1633e5b75505Sopenharmony_ci 1634e5b75505Sopenharmony_ci 1635e5b75505Sopenharmony_cistatic int 1636e5b75505Sopenharmony_ciatheros_wireless_event_init(struct atheros_driver_data *drv) 1637e5b75505Sopenharmony_ci{ 1638e5b75505Sopenharmony_ci struct netlink_config *cfg; 1639e5b75505Sopenharmony_ci 1640e5b75505Sopenharmony_ci atheros_get_we_version(drv); 1641e5b75505Sopenharmony_ci 1642e5b75505Sopenharmony_ci cfg = os_zalloc(sizeof(*cfg)); 1643e5b75505Sopenharmony_ci if (cfg == NULL) 1644e5b75505Sopenharmony_ci return -1; 1645e5b75505Sopenharmony_ci cfg->ctx = drv; 1646e5b75505Sopenharmony_ci cfg->newlink_cb = atheros_wireless_event_rtm_newlink; 1647e5b75505Sopenharmony_ci drv->netlink = netlink_init(cfg); 1648e5b75505Sopenharmony_ci if (drv->netlink == NULL) { 1649e5b75505Sopenharmony_ci os_free(cfg); 1650e5b75505Sopenharmony_ci return -1; 1651e5b75505Sopenharmony_ci } 1652e5b75505Sopenharmony_ci 1653e5b75505Sopenharmony_ci return 0; 1654e5b75505Sopenharmony_ci} 1655e5b75505Sopenharmony_ci 1656e5b75505Sopenharmony_ci 1657e5b75505Sopenharmony_cistatic int 1658e5b75505Sopenharmony_ciatheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, 1659e5b75505Sopenharmony_ci int encrypt, const u8 *own_addr, u32 flags) 1660e5b75505Sopenharmony_ci{ 1661e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1662e5b75505Sopenharmony_ci unsigned char buf[3000]; 1663e5b75505Sopenharmony_ci unsigned char *bp = buf; 1664e5b75505Sopenharmony_ci struct l2_ethhdr *eth; 1665e5b75505Sopenharmony_ci size_t len; 1666e5b75505Sopenharmony_ci int status; 1667e5b75505Sopenharmony_ci 1668e5b75505Sopenharmony_ci /* 1669e5b75505Sopenharmony_ci * Prepend the Ethernet header. If the caller left us 1670e5b75505Sopenharmony_ci * space at the front we could just insert it but since 1671e5b75505Sopenharmony_ci * we don't know we copy to a local buffer. Given the frequency 1672e5b75505Sopenharmony_ci * and size of frames this probably doesn't matter. 1673e5b75505Sopenharmony_ci */ 1674e5b75505Sopenharmony_ci len = data_len + sizeof(struct l2_ethhdr); 1675e5b75505Sopenharmony_ci if (len > sizeof(buf)) { 1676e5b75505Sopenharmony_ci bp = os_malloc(len); 1677e5b75505Sopenharmony_ci if (bp == NULL) { 1678e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1679e5b75505Sopenharmony_ci "EAPOL frame discarded, cannot malloc temp buffer of size %lu!", 1680e5b75505Sopenharmony_ci (unsigned long) len); 1681e5b75505Sopenharmony_ci return -1; 1682e5b75505Sopenharmony_ci } 1683e5b75505Sopenharmony_ci } 1684e5b75505Sopenharmony_ci eth = (struct l2_ethhdr *) bp; 1685e5b75505Sopenharmony_ci os_memcpy(eth->h_dest, addr, ETH_ALEN); 1686e5b75505Sopenharmony_ci os_memcpy(eth->h_source, own_addr, ETH_ALEN); 1687e5b75505Sopenharmony_ci eth->h_proto = host_to_be16(ETH_P_EAPOL); 1688e5b75505Sopenharmony_ci os_memcpy(eth + 1, data, data_len); 1689e5b75505Sopenharmony_ci 1690e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); 1691e5b75505Sopenharmony_ci 1692e5b75505Sopenharmony_ci status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); 1693e5b75505Sopenharmony_ci 1694e5b75505Sopenharmony_ci if (bp != buf) 1695e5b75505Sopenharmony_ci os_free(bp); 1696e5b75505Sopenharmony_ci return status; 1697e5b75505Sopenharmony_ci} 1698e5b75505Sopenharmony_ci 1699e5b75505Sopenharmony_cistatic void 1700e5b75505Sopenharmony_cihandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 1701e5b75505Sopenharmony_ci{ 1702e5b75505Sopenharmony_ci struct atheros_driver_data *drv = ctx; 1703e5b75505Sopenharmony_ci drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), 1704e5b75505Sopenharmony_ci len - sizeof(struct l2_ethhdr)); 1705e5b75505Sopenharmony_ci} 1706e5b75505Sopenharmony_ci 1707e5b75505Sopenharmony_ci 1708e5b75505Sopenharmony_cistatic void atheros_read_fils_cap(struct atheros_driver_data *drv) 1709e5b75505Sopenharmony_ci{ 1710e5b75505Sopenharmony_ci int fils = 0; 1711e5b75505Sopenharmony_ci 1712e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 1713e5b75505Sopenharmony_ci /* TODO: Would be better to have #ifdef on the IEEE80211_PARAM_* value 1714e5b75505Sopenharmony_ci * to automatically check this against the driver header files. */ 1715e5b75505Sopenharmony_ci if (get80211param(drv, IEEE80211_PARAM_ENABLE_FILS, &fils) < 0) { 1716e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1717e5b75505Sopenharmony_ci "%s: Failed to get FILS capability from driver", 1718e5b75505Sopenharmony_ci __func__); 1719e5b75505Sopenharmony_ci /* Assume driver does not support FILS */ 1720e5b75505Sopenharmony_ci fils = 0; 1721e5b75505Sopenharmony_ci } 1722e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 1723e5b75505Sopenharmony_ci drv->fils_en = fils; 1724e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: fils_en=%d", drv->fils_en); 1725e5b75505Sopenharmony_ci} 1726e5b75505Sopenharmony_ci 1727e5b75505Sopenharmony_ci 1728e5b75505Sopenharmony_cistatic void * 1729e5b75505Sopenharmony_ciatheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) 1730e5b75505Sopenharmony_ci{ 1731e5b75505Sopenharmony_ci struct atheros_driver_data *drv; 1732e5b75505Sopenharmony_ci struct ifreq ifr; 1733e5b75505Sopenharmony_ci struct iwreq iwr; 1734e5b75505Sopenharmony_ci char brname[IFNAMSIZ]; 1735e5b75505Sopenharmony_ci 1736e5b75505Sopenharmony_ci drv = os_zalloc(sizeof(struct atheros_driver_data)); 1737e5b75505Sopenharmony_ci if (drv == NULL) { 1738e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1739e5b75505Sopenharmony_ci "Could not allocate memory for atheros driver data"); 1740e5b75505Sopenharmony_ci return NULL; 1741e5b75505Sopenharmony_ci } 1742e5b75505Sopenharmony_ci 1743e5b75505Sopenharmony_ci drv->hapd = hapd; 1744e5b75505Sopenharmony_ci drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); 1745e5b75505Sopenharmony_ci if (drv->ioctl_sock < 0) { 1746e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", 1747e5b75505Sopenharmony_ci strerror(errno)); 1748e5b75505Sopenharmony_ci goto bad; 1749e5b75505Sopenharmony_ci } 1750e5b75505Sopenharmony_ci os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); 1751e5b75505Sopenharmony_ci 1752e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 1753e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); 1754e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { 1755e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", 1756e5b75505Sopenharmony_ci strerror(errno)); 1757e5b75505Sopenharmony_ci goto bad; 1758e5b75505Sopenharmony_ci } 1759e5b75505Sopenharmony_ci drv->ifindex = ifr.ifr_ifindex; 1760e5b75505Sopenharmony_ci 1761e5b75505Sopenharmony_ci drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, 1762e5b75505Sopenharmony_ci handle_read, drv, 1); 1763e5b75505Sopenharmony_ci if (drv->sock_xmit == NULL) 1764e5b75505Sopenharmony_ci goto bad; 1765e5b75505Sopenharmony_ci if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) 1766e5b75505Sopenharmony_ci goto bad; 1767e5b75505Sopenharmony_ci os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN); 1768e5b75505Sopenharmony_ci if (params->bridge[0]) { 1769e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", 1770e5b75505Sopenharmony_ci params->bridge[0]); 1771e5b75505Sopenharmony_ci drv->sock_recv = l2_packet_init(params->bridge[0], NULL, 1772e5b75505Sopenharmony_ci ETH_P_EAPOL, handle_read, drv, 1773e5b75505Sopenharmony_ci 1); 1774e5b75505Sopenharmony_ci if (drv->sock_recv == NULL) 1775e5b75505Sopenharmony_ci goto bad; 1776e5b75505Sopenharmony_ci } else if (linux_br_get(brname, drv->iface) == 0) { 1777e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " 1778e5b75505Sopenharmony_ci "EAPOL receive", brname); 1779e5b75505Sopenharmony_ci drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, 1780e5b75505Sopenharmony_ci handle_read, drv, 1); 1781e5b75505Sopenharmony_ci if (drv->sock_recv == NULL) 1782e5b75505Sopenharmony_ci goto bad; 1783e5b75505Sopenharmony_ci } else 1784e5b75505Sopenharmony_ci drv->sock_recv = drv->sock_xmit; 1785e5b75505Sopenharmony_ci 1786e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1787e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1788e5b75505Sopenharmony_ci 1789e5b75505Sopenharmony_ci iwr.u.mode = IW_MODE_MASTER; 1790e5b75505Sopenharmony_ci 1791e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { 1792e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1793e5b75505Sopenharmony_ci "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s", 1794e5b75505Sopenharmony_ci strerror(errno)); 1795e5b75505Sopenharmony_ci goto bad; 1796e5b75505Sopenharmony_ci } 1797e5b75505Sopenharmony_ci 1798e5b75505Sopenharmony_ci /* mark down during setup */ 1799e5b75505Sopenharmony_ci linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); 1800e5b75505Sopenharmony_ci atheros_set_privacy(drv, 0); /* default to no privacy */ 1801e5b75505Sopenharmony_ci 1802e5b75505Sopenharmony_ci if (atheros_receive_pkt(drv)) 1803e5b75505Sopenharmony_ci goto bad; 1804e5b75505Sopenharmony_ci 1805e5b75505Sopenharmony_ci if (atheros_wireless_event_init(drv)) 1806e5b75505Sopenharmony_ci goto bad; 1807e5b75505Sopenharmony_ci 1808e5b75505Sopenharmony_ci /* Read FILS capability from the driver */ 1809e5b75505Sopenharmony_ci atheros_read_fils_cap(drv); 1810e5b75505Sopenharmony_ci 1811e5b75505Sopenharmony_ci return drv; 1812e5b75505Sopenharmony_cibad: 1813e5b75505Sopenharmony_ci atheros_reset_appfilter(drv); 1814e5b75505Sopenharmony_ci if (drv->sock_raw) 1815e5b75505Sopenharmony_ci l2_packet_deinit(drv->sock_raw); 1816e5b75505Sopenharmony_ci if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) 1817e5b75505Sopenharmony_ci l2_packet_deinit(drv->sock_recv); 1818e5b75505Sopenharmony_ci if (drv->sock_xmit != NULL) 1819e5b75505Sopenharmony_ci l2_packet_deinit(drv->sock_xmit); 1820e5b75505Sopenharmony_ci if (drv->ioctl_sock >= 0) 1821e5b75505Sopenharmony_ci close(drv->ioctl_sock); 1822e5b75505Sopenharmony_ci os_free(drv); 1823e5b75505Sopenharmony_ci return NULL; 1824e5b75505Sopenharmony_ci} 1825e5b75505Sopenharmony_ci 1826e5b75505Sopenharmony_ci 1827e5b75505Sopenharmony_cistatic void 1828e5b75505Sopenharmony_ciatheros_deinit(void *priv) 1829e5b75505Sopenharmony_ci{ 1830e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1831e5b75505Sopenharmony_ci 1832e5b75505Sopenharmony_ci atheros_reset_appfilter(drv); 1833e5b75505Sopenharmony_ci 1834e5b75505Sopenharmony_ci if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) { 1835e5b75505Sopenharmony_ci atheros_set_opt_ie(priv, NULL, 0); 1836e5b75505Sopenharmony_ci wpabuf_free(drv->wpa_ie); 1837e5b75505Sopenharmony_ci wpabuf_free(drv->wps_beacon_ie); 1838e5b75505Sopenharmony_ci wpabuf_free(drv->wps_probe_resp_ie); 1839e5b75505Sopenharmony_ci } 1840e5b75505Sopenharmony_ci netlink_deinit(drv->netlink); 1841e5b75505Sopenharmony_ci (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); 1842e5b75505Sopenharmony_ci if (drv->ioctl_sock >= 0) 1843e5b75505Sopenharmony_ci close(drv->ioctl_sock); 1844e5b75505Sopenharmony_ci if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) 1845e5b75505Sopenharmony_ci l2_packet_deinit(drv->sock_recv); 1846e5b75505Sopenharmony_ci if (drv->sock_xmit != NULL) 1847e5b75505Sopenharmony_ci l2_packet_deinit(drv->sock_xmit); 1848e5b75505Sopenharmony_ci if (drv->sock_raw) 1849e5b75505Sopenharmony_ci l2_packet_deinit(drv->sock_raw); 1850e5b75505Sopenharmony_ci os_free(drv); 1851e5b75505Sopenharmony_ci} 1852e5b75505Sopenharmony_ci 1853e5b75505Sopenharmony_cistatic int 1854e5b75505Sopenharmony_ciatheros_set_ssid(void *priv, const u8 *buf, int len) 1855e5b75505Sopenharmony_ci{ 1856e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1857e5b75505Sopenharmony_ci struct iwreq iwr; 1858e5b75505Sopenharmony_ci 1859e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1860e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1861e5b75505Sopenharmony_ci iwr.u.essid.flags = 1; /* SSID active */ 1862e5b75505Sopenharmony_ci iwr.u.essid.pointer = (caddr_t) buf; 1863e5b75505Sopenharmony_ci iwr.u.essid.length = len; 1864e5b75505Sopenharmony_ci 1865e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { 1866e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s", 1867e5b75505Sopenharmony_ci len, strerror(errno)); 1868e5b75505Sopenharmony_ci return -1; 1869e5b75505Sopenharmony_ci } 1870e5b75505Sopenharmony_ci return 0; 1871e5b75505Sopenharmony_ci} 1872e5b75505Sopenharmony_ci 1873e5b75505Sopenharmony_cistatic int 1874e5b75505Sopenharmony_ciatheros_get_ssid(void *priv, u8 *buf, int len) 1875e5b75505Sopenharmony_ci{ 1876e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1877e5b75505Sopenharmony_ci struct iwreq iwr; 1878e5b75505Sopenharmony_ci int ret = 0; 1879e5b75505Sopenharmony_ci 1880e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 1881e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 1882e5b75505Sopenharmony_ci iwr.u.essid.pointer = (caddr_t) buf; 1883e5b75505Sopenharmony_ci iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? 1884e5b75505Sopenharmony_ci IW_ESSID_MAX_SIZE : len; 1885e5b75505Sopenharmony_ci 1886e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { 1887e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", 1888e5b75505Sopenharmony_ci strerror(errno)); 1889e5b75505Sopenharmony_ci ret = -1; 1890e5b75505Sopenharmony_ci } else 1891e5b75505Sopenharmony_ci ret = iwr.u.essid.length; 1892e5b75505Sopenharmony_ci 1893e5b75505Sopenharmony_ci return ret; 1894e5b75505Sopenharmony_ci} 1895e5b75505Sopenharmony_ci 1896e5b75505Sopenharmony_cistatic int 1897e5b75505Sopenharmony_ciatheros_set_countermeasures(void *priv, int enabled) 1898e5b75505Sopenharmony_ci{ 1899e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1900e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 1901e5b75505Sopenharmony_ci return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); 1902e5b75505Sopenharmony_ci} 1903e5b75505Sopenharmony_ci 1904e5b75505Sopenharmony_cistatic int 1905e5b75505Sopenharmony_ciatheros_commit(void *priv) 1906e5b75505Sopenharmony_ci{ 1907e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1908e5b75505Sopenharmony_ci return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); 1909e5b75505Sopenharmony_ci} 1910e5b75505Sopenharmony_ci 1911e5b75505Sopenharmony_cistatic int atheros_set_authmode(void *priv, int auth_algs) 1912e5b75505Sopenharmony_ci{ 1913e5b75505Sopenharmony_ci int authmode; 1914e5b75505Sopenharmony_ci 1915e5b75505Sopenharmony_ci if ((auth_algs & WPA_AUTH_ALG_OPEN) && 1916e5b75505Sopenharmony_ci (auth_algs & WPA_AUTH_ALG_SHARED)) 1917e5b75505Sopenharmony_ci authmode = IEEE80211_AUTH_AUTO; 1918e5b75505Sopenharmony_ci else if (auth_algs & WPA_AUTH_ALG_OPEN) 1919e5b75505Sopenharmony_ci authmode = IEEE80211_AUTH_OPEN; 1920e5b75505Sopenharmony_ci else if (auth_algs & WPA_AUTH_ALG_SHARED) 1921e5b75505Sopenharmony_ci authmode = IEEE80211_AUTH_SHARED; 1922e5b75505Sopenharmony_ci else 1923e5b75505Sopenharmony_ci return -1; 1924e5b75505Sopenharmony_ci 1925e5b75505Sopenharmony_ci return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode); 1926e5b75505Sopenharmony_ci} 1927e5b75505Sopenharmony_ci 1928e5b75505Sopenharmony_cistatic int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) 1929e5b75505Sopenharmony_ci{ 1930e5b75505Sopenharmony_ci /* 1931e5b75505Sopenharmony_ci * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x, 1932e5b75505Sopenharmony_ci * set_generic_elem, and hapd_set_ssid. 1933e5b75505Sopenharmony_ci */ 1934e5b75505Sopenharmony_ci 1935e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x " 1936e5b75505Sopenharmony_ci "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x " 1937e5b75505Sopenharmony_ci "wpa_version=0x%x privacy=%d interworking=%d", 1938e5b75505Sopenharmony_ci params->pairwise_ciphers, params->group_cipher, 1939e5b75505Sopenharmony_ci params->key_mgmt_suites, params->auth_algs, 1940e5b75505Sopenharmony_ci params->wpa_version, params->privacy, params->interworking); 1941e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID", 1942e5b75505Sopenharmony_ci params->ssid, params->ssid_len); 1943e5b75505Sopenharmony_ci if (params->hessid) 1944e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR, 1945e5b75505Sopenharmony_ci MAC2STR(params->hessid)); 1946e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies", 1947e5b75505Sopenharmony_ci params->beacon_ies); 1948e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies", 1949e5b75505Sopenharmony_ci params->proberesp_ies); 1950e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", 1951e5b75505Sopenharmony_ci params->assocresp_ies); 1952e5b75505Sopenharmony_ci 1953e5b75505Sopenharmony_ci#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN)) 1954e5b75505Sopenharmony_ci if (params->osen) { 1955e5b75505Sopenharmony_ci struct wpa_bss_params bss_params; 1956e5b75505Sopenharmony_ci 1957e5b75505Sopenharmony_ci os_memset(&bss_params, 0, sizeof(struct wpa_bss_params)); 1958e5b75505Sopenharmony_ci bss_params.enabled = 1; 1959e5b75505Sopenharmony_ci bss_params.wpa = 2; 1960e5b75505Sopenharmony_ci bss_params.wpa_pairwise = WPA_CIPHER_CCMP; 1961e5b75505Sopenharmony_ci bss_params.wpa_group = WPA_CIPHER_CCMP; 1962e5b75505Sopenharmony_ci bss_params.ieee802_1x = 1; 1963e5b75505Sopenharmony_ci 1964e5b75505Sopenharmony_ci if (atheros_set_privacy(priv, 1) || 1965e5b75505Sopenharmony_ci set80211param(priv, IEEE80211_PARAM_OSEN, 1)) 1966e5b75505Sopenharmony_ci return -1; 1967e5b75505Sopenharmony_ci 1968e5b75505Sopenharmony_ci return atheros_set_ieee8021x(priv, &bss_params); 1969e5b75505Sopenharmony_ci } 1970e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 && IEEE80211_PARAM_OSEN */ 1971e5b75505Sopenharmony_ci 1972e5b75505Sopenharmony_ci return 0; 1973e5b75505Sopenharmony_ci} 1974e5b75505Sopenharmony_ci 1975e5b75505Sopenharmony_ci 1976e5b75505Sopenharmony_ci#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 1977e5b75505Sopenharmony_ci 1978e5b75505Sopenharmony_cistatic int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, 1979e5b75505Sopenharmony_ci int noack, unsigned int freq, 1980e5b75505Sopenharmony_ci const u16 *csa_offs, size_t csa_offs_len) 1981e5b75505Sopenharmony_ci{ 1982e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 1983e5b75505Sopenharmony_ci u8 buf[1510]; 1984e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt; 1985e5b75505Sopenharmony_ci struct ieee80211req_mgmtbuf *mgmt_frm; 1986e5b75505Sopenharmony_ci 1987e5b75505Sopenharmony_ci mgmt = (const struct ieee80211_mgmt *) frm; 1988e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__, 1989e5b75505Sopenharmony_ci (unsigned long) data_len, MAC2STR(mgmt->da)); 1990e5b75505Sopenharmony_ci mgmt_frm = (struct ieee80211req_mgmtbuf *) buf; 1991e5b75505Sopenharmony_ci os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); 1992e5b75505Sopenharmony_ci mgmt_frm->buflen = data_len; 1993e5b75505Sopenharmony_ci if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) { 1994e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "atheros: Too long frame for " 1995e5b75505Sopenharmony_ci "atheros_send_mgmt (%u)", (unsigned int) data_len); 1996e5b75505Sopenharmony_ci return -1; 1997e5b75505Sopenharmony_ci } 1998e5b75505Sopenharmony_ci os_memcpy(&mgmt_frm->buf[0], frm, data_len); 1999e5b75505Sopenharmony_ci return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm, 2000e5b75505Sopenharmony_ci sizeof(struct ieee80211req_mgmtbuf) + data_len); 2001e5b75505Sopenharmony_ci} 2002e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 2003e5b75505Sopenharmony_ci 2004e5b75505Sopenharmony_ci 2005e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R 2006e5b75505Sopenharmony_ci 2007e5b75505Sopenharmony_cistatic int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie, 2008e5b75505Sopenharmony_ci size_t tspec_ielen) 2009e5b75505Sopenharmony_ci{ 2010e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 2011e5b75505Sopenharmony_ci int retv; 2012e5b75505Sopenharmony_ci struct ieee80211req_res req; 2013e5b75505Sopenharmony_ci struct ieee80211req_res_addts *addts = &req.u.addts; 2014e5b75505Sopenharmony_ci 2015e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __func__); 2016e5b75505Sopenharmony_ci req.type = IEEE80211_RESREQ_ADDTS; 2017e5b75505Sopenharmony_ci os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); 2018e5b75505Sopenharmony_ci os_memcpy(addts->tspecie, tspec_ie, tspec_ielen); 2019e5b75505Sopenharmony_ci retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, 2020e5b75505Sopenharmony_ci sizeof(struct ieee80211req_res)); 2021e5b75505Sopenharmony_ci if (retv < 0) { 2022e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED " 2023e5b75505Sopenharmony_ci "retv = %d", __func__, retv); 2024e5b75505Sopenharmony_ci return -1; 2025e5b75505Sopenharmony_ci } 2026e5b75505Sopenharmony_ci os_memcpy(tspec_ie, addts->tspecie, tspec_ielen); 2027e5b75505Sopenharmony_ci return addts->status; 2028e5b75505Sopenharmony_ci} 2029e5b75505Sopenharmony_ci 2030e5b75505Sopenharmony_ci 2031e5b75505Sopenharmony_cistatic int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg) 2032e5b75505Sopenharmony_ci{ 2033e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 2034e5b75505Sopenharmony_ci struct ieee80211req_res req; 2035e5b75505Sopenharmony_ci struct ieee80211req_res_addnode *addnode = &req.u.addnode; 2036e5b75505Sopenharmony_ci 2037e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s", __func__); 2038e5b75505Sopenharmony_ci req.type = IEEE80211_RESREQ_ADDNODE; 2039e5b75505Sopenharmony_ci os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); 2040e5b75505Sopenharmony_ci addnode->auth_alg = auth_alg; 2041e5b75505Sopenharmony_ci return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, 2042e5b75505Sopenharmony_ci sizeof(struct ieee80211req_res)); 2043e5b75505Sopenharmony_ci} 2044e5b75505Sopenharmony_ci 2045e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R */ 2046e5b75505Sopenharmony_ci 2047e5b75505Sopenharmony_ci 2048e5b75505Sopenharmony_ci/* Use only to set a big param, get will not work. */ 2049e5b75505Sopenharmony_cistatic int 2050e5b75505Sopenharmony_ciset80211big(struct atheros_driver_data *drv, int op, const void *data, int len) 2051e5b75505Sopenharmony_ci{ 2052e5b75505Sopenharmony_ci struct iwreq iwr; 2053e5b75505Sopenharmony_ci 2054e5b75505Sopenharmony_ci os_memset(&iwr, 0, sizeof(iwr)); 2055e5b75505Sopenharmony_ci os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); 2056e5b75505Sopenharmony_ci 2057e5b75505Sopenharmony_ci iwr.u.data.pointer = (void *) data; 2058e5b75505Sopenharmony_ci iwr.u.data.length = len; 2059e5b75505Sopenharmony_ci iwr.u.data.flags = op; 2060e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x", 2061e5b75505Sopenharmony_ci __func__, op, op, athr_get_param_name(op), len); 2062e5b75505Sopenharmony_ci 2063e5b75505Sopenharmony_ci if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) { 2064e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d " 2065e5b75505Sopenharmony_ci "value=0x%x,0x%x failed: %d (%s)", 2066e5b75505Sopenharmony_ci __func__, op, athr_get_ioctl_name(op), iwr.u.mode, 2067e5b75505Sopenharmony_ci iwr.u.mode, iwr.u.data.length, 2068e5b75505Sopenharmony_ci iwr.u.data.flags, errno, strerror(errno)); 2069e5b75505Sopenharmony_ci return -1; 2070e5b75505Sopenharmony_ci } 2071e5b75505Sopenharmony_ci return 0; 2072e5b75505Sopenharmony_ci} 2073e5b75505Sopenharmony_ci 2074e5b75505Sopenharmony_ci 2075e5b75505Sopenharmony_cistatic int atheros_send_action(void *priv, unsigned int freq, 2076e5b75505Sopenharmony_ci unsigned int wait, 2077e5b75505Sopenharmony_ci const u8 *dst, const u8 *src, 2078e5b75505Sopenharmony_ci const u8 *bssid, 2079e5b75505Sopenharmony_ci const u8 *data, size_t data_len, int no_cck) 2080e5b75505Sopenharmony_ci{ 2081e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 2082e5b75505Sopenharmony_ci struct ieee80211_p2p_send_action *act; 2083e5b75505Sopenharmony_ci int res; 2084e5b75505Sopenharmony_ci 2085e5b75505Sopenharmony_ci act = os_zalloc(sizeof(*act) + data_len); 2086e5b75505Sopenharmony_ci if (act == NULL) 2087e5b75505Sopenharmony_ci return -1; 2088e5b75505Sopenharmony_ci act->freq = freq; 2089e5b75505Sopenharmony_ci os_memcpy(act->dst_addr, dst, ETH_ALEN); 2090e5b75505Sopenharmony_ci os_memcpy(act->src_addr, src, ETH_ALEN); 2091e5b75505Sopenharmony_ci os_memcpy(act->bssid, bssid, ETH_ALEN); 2092e5b75505Sopenharmony_ci os_memcpy(act + 1, data, data_len); 2093e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src=" 2094e5b75505Sopenharmony_ci MACSTR ", bssid=" MACSTR, 2095e5b75505Sopenharmony_ci __func__, act->freq, wait, MAC2STR(act->dst_addr), 2096e5b75505Sopenharmony_ci MAC2STR(act->src_addr), MAC2STR(act->bssid)); 2097e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act)); 2098e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len); 2099e5b75505Sopenharmony_ci 2100e5b75505Sopenharmony_ci res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION, 2101e5b75505Sopenharmony_ci act, sizeof(*act) + data_len); 2102e5b75505Sopenharmony_ci os_free(act); 2103e5b75505Sopenharmony_ci return res; 2104e5b75505Sopenharmony_ci} 2105e5b75505Sopenharmony_ci 2106e5b75505Sopenharmony_ci 2107e5b75505Sopenharmony_ci#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) 2108e5b75505Sopenharmony_cistatic int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer, 2109e5b75505Sopenharmony_ci u8 *ie, u16 *len, enum wnm_oper oper) 2110e5b75505Sopenharmony_ci{ 2111e5b75505Sopenharmony_ci#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */ 2112e5b75505Sopenharmony_ci u8 buf[IEEE80211_APPIE_MAX]; 2113e5b75505Sopenharmony_ci struct ieee80211req_getset_appiebuf *tfs_ie; 2114e5b75505Sopenharmony_ci u16 val; 2115e5b75505Sopenharmony_ci 2116e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR, 2117e5b75505Sopenharmony_ci drv->iface, oper, MAC2STR(peer)); 2118e5b75505Sopenharmony_ci 2119e5b75505Sopenharmony_ci switch (oper) { 2120e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_REQ_IE_SET: 2121e5b75505Sopenharmony_ci if (*len > IEEE80211_APPIE_MAX - 2122e5b75505Sopenharmony_ci sizeof(struct ieee80211req_getset_appiebuf)) { 2123e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large"); 2124e5b75505Sopenharmony_ci return -1; 2125e5b75505Sopenharmony_ci } 2126e5b75505Sopenharmony_ci tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2127e5b75505Sopenharmony_ci tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2128e5b75505Sopenharmony_ci tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len; 2129e5b75505Sopenharmony_ci 2130e5b75505Sopenharmony_ci /* Command header for driver */ 2131e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2132e5b75505Sopenharmony_ci val = oper; 2133e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2134e5b75505Sopenharmony_ci val = *len; 2135e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2136e5b75505Sopenharmony_ci 2137e5b75505Sopenharmony_ci /* copy the ie */ 2138e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len); 2139e5b75505Sopenharmony_ci 2140e5b75505Sopenharmony_ci if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, 2141e5b75505Sopenharmony_ci IEEE80211_APPIE_MAX)) { 2142e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " 2143e5b75505Sopenharmony_ci "%s", __func__, strerror(errno)); 2144e5b75505Sopenharmony_ci return -1; 2145e5b75505Sopenharmony_ci } 2146e5b75505Sopenharmony_ci break; 2147e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_RESP_IE_ADD: 2148e5b75505Sopenharmony_ci tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2149e5b75505Sopenharmony_ci tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2150e5b75505Sopenharmony_ci tfs_ie->app_buflen = IEEE80211_APPIE_MAX - 2151e5b75505Sopenharmony_ci sizeof(struct ieee80211req_getset_appiebuf); 2152e5b75505Sopenharmony_ci /* Command header for driver */ 2153e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2154e5b75505Sopenharmony_ci val = oper; 2155e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2156e5b75505Sopenharmony_ci val = 0; 2157e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2158e5b75505Sopenharmony_ci 2159e5b75505Sopenharmony_ci if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie, 2160e5b75505Sopenharmony_ci IEEE80211_APPIE_MAX)) { 2161e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: " 2162e5b75505Sopenharmony_ci "%s", __func__, strerror(errno)); 2163e5b75505Sopenharmony_ci return -1; 2164e5b75505Sopenharmony_ci } 2165e5b75505Sopenharmony_ci 2166e5b75505Sopenharmony_ci *len = tfs_ie->app_buflen; 2167e5b75505Sopenharmony_ci os_memcpy(ie, &(tfs_ie->app_buf[0]), *len); 2168e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0], 2169e5b75505Sopenharmony_ci *len); 2170e5b75505Sopenharmony_ci break; 2171e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_RESP_IE_NONE: 2172e5b75505Sopenharmony_ci *len = 0; 2173e5b75505Sopenharmony_ci break; 2174e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_IE_DEL: 2175e5b75505Sopenharmony_ci tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; 2176e5b75505Sopenharmony_ci tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; 2177e5b75505Sopenharmony_ci tfs_ie->app_buflen = IEEE80211_APPIE_MAX - 2178e5b75505Sopenharmony_ci sizeof(struct ieee80211req_getset_appiebuf); 2179e5b75505Sopenharmony_ci /* Command header for driver */ 2180e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); 2181e5b75505Sopenharmony_ci val = oper; 2182e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); 2183e5b75505Sopenharmony_ci val = 0; 2184e5b75505Sopenharmony_ci os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); 2185e5b75505Sopenharmony_ci 2186e5b75505Sopenharmony_ci if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, 2187e5b75505Sopenharmony_ci IEEE80211_APPIE_MAX)) { 2188e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " 2189e5b75505Sopenharmony_ci "%s", __func__, strerror(errno)); 2190e5b75505Sopenharmony_ci return -1; 2191e5b75505Sopenharmony_ci } 2192e5b75505Sopenharmony_ci break; 2193e5b75505Sopenharmony_ci default: 2194e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper); 2195e5b75505Sopenharmony_ci break; 2196e5b75505Sopenharmony_ci } 2197e5b75505Sopenharmony_ci 2198e5b75505Sopenharmony_ci return 0; 2199e5b75505Sopenharmony_ci} 2200e5b75505Sopenharmony_ci 2201e5b75505Sopenharmony_ci 2202e5b75505Sopenharmony_cistatic int atheros_wnm_sleep(struct atheros_driver_data *drv, 2203e5b75505Sopenharmony_ci const u8 *peer, enum wnm_oper oper) 2204e5b75505Sopenharmony_ci{ 2205e5b75505Sopenharmony_ci u8 *data, *pos; 2206e5b75505Sopenharmony_ci size_t dlen; 2207e5b75505Sopenharmony_ci int ret; 2208e5b75505Sopenharmony_ci u16 val; 2209e5b75505Sopenharmony_ci 2210e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR, 2211e5b75505Sopenharmony_ci oper, MAC2STR(peer)); 2212e5b75505Sopenharmony_ci 2213e5b75505Sopenharmony_ci dlen = ETH_ALEN + 2 + 2; 2214e5b75505Sopenharmony_ci data = os_malloc(dlen); 2215e5b75505Sopenharmony_ci if (data == NULL) 2216e5b75505Sopenharmony_ci return -1; 2217e5b75505Sopenharmony_ci 2218e5b75505Sopenharmony_ci /* Command header for driver */ 2219e5b75505Sopenharmony_ci pos = data; 2220e5b75505Sopenharmony_ci os_memcpy(pos, peer, ETH_ALEN); 2221e5b75505Sopenharmony_ci pos += ETH_ALEN; 2222e5b75505Sopenharmony_ci 2223e5b75505Sopenharmony_ci val = oper; 2224e5b75505Sopenharmony_ci os_memcpy(pos, &val, 2); 2225e5b75505Sopenharmony_ci pos += 2; 2226e5b75505Sopenharmony_ci 2227e5b75505Sopenharmony_ci val = 0; 2228e5b75505Sopenharmony_ci os_memcpy(pos, &val, 2); 2229e5b75505Sopenharmony_ci 2230e5b75505Sopenharmony_ci ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM); 2231e5b75505Sopenharmony_ci 2232e5b75505Sopenharmony_ci os_free(data); 2233e5b75505Sopenharmony_ci 2234e5b75505Sopenharmony_ci return ret; 2235e5b75505Sopenharmony_ci} 2236e5b75505Sopenharmony_ci 2237e5b75505Sopenharmony_ci 2238e5b75505Sopenharmony_cistatic int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer, 2239e5b75505Sopenharmony_ci u8 *buf, u16 *buf_len) 2240e5b75505Sopenharmony_ci{ 2241e5b75505Sopenharmony_ci struct atheros_driver_data *drv = priv; 2242e5b75505Sopenharmony_ci 2243e5b75505Sopenharmony_ci switch (oper) { 2244e5b75505Sopenharmony_ci case WNM_SLEEP_ENTER_CONFIRM: 2245e5b75505Sopenharmony_ci case WNM_SLEEP_ENTER_FAIL: 2246e5b75505Sopenharmony_ci case WNM_SLEEP_EXIT_CONFIRM: 2247e5b75505Sopenharmony_ci case WNM_SLEEP_EXIT_FAIL: 2248e5b75505Sopenharmony_ci return atheros_wnm_sleep(drv, peer, oper); 2249e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_REQ_IE_SET: 2250e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_RESP_IE_ADD: 2251e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_RESP_IE_NONE: 2252e5b75505Sopenharmony_ci case WNM_SLEEP_TFS_IE_DEL: 2253e5b75505Sopenharmony_ci return athr_wnm_tfs(drv, peer, buf, buf_len, oper); 2254e5b75505Sopenharmony_ci default: 2255e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d", 2256e5b75505Sopenharmony_ci oper); 2257e5b75505Sopenharmony_ci return -1; 2258e5b75505Sopenharmony_ci } 2259e5b75505Sopenharmony_ci} 2260e5b75505Sopenharmony_ci#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ 2261e5b75505Sopenharmony_ci 2262e5b75505Sopenharmony_ci 2263e5b75505Sopenharmony_ciconst struct wpa_driver_ops wpa_driver_atheros_ops = { 2264e5b75505Sopenharmony_ci .name = "atheros", 2265e5b75505Sopenharmony_ci .hapd_init = atheros_init, 2266e5b75505Sopenharmony_ci .hapd_deinit = atheros_deinit, 2267e5b75505Sopenharmony_ci .set_ieee8021x = atheros_set_ieee8021x, 2268e5b75505Sopenharmony_ci .set_privacy = atheros_set_privacy, 2269e5b75505Sopenharmony_ci .set_key = atheros_set_key, 2270e5b75505Sopenharmony_ci .get_seqnum = atheros_get_seqnum, 2271e5b75505Sopenharmony_ci .flush = atheros_flush, 2272e5b75505Sopenharmony_ci .set_generic_elem = atheros_set_opt_ie, 2273e5b75505Sopenharmony_ci .sta_set_flags = atheros_sta_set_flags, 2274e5b75505Sopenharmony_ci .read_sta_data = atheros_read_sta_driver_data, 2275e5b75505Sopenharmony_ci .hapd_send_eapol = atheros_send_eapol, 2276e5b75505Sopenharmony_ci .sta_disassoc = atheros_sta_disassoc, 2277e5b75505Sopenharmony_ci .sta_deauth = atheros_sta_deauth, 2278e5b75505Sopenharmony_ci .hapd_set_ssid = atheros_set_ssid, 2279e5b75505Sopenharmony_ci .hapd_get_ssid = atheros_get_ssid, 2280e5b75505Sopenharmony_ci .set_countermeasures = atheros_set_countermeasures, 2281e5b75505Sopenharmony_ci .sta_clear_stats = atheros_sta_clear_stats, 2282e5b75505Sopenharmony_ci .commit = atheros_commit, 2283e5b75505Sopenharmony_ci .set_ap_wps_ie = atheros_set_ap_wps_ie, 2284e5b75505Sopenharmony_ci .set_authmode = atheros_set_authmode, 2285e5b75505Sopenharmony_ci .set_ap = atheros_set_ap, 2286e5b75505Sopenharmony_ci#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) 2287e5b75505Sopenharmony_ci .sta_assoc = atheros_sta_assoc, 2288e5b75505Sopenharmony_ci .sta_auth = atheros_sta_auth, 2289e5b75505Sopenharmony_ci .send_mlme = atheros_send_mgmt, 2290e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */ 2291e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R 2292e5b75505Sopenharmony_ci .add_tspec = atheros_add_tspec, 2293e5b75505Sopenharmony_ci .add_sta_node = atheros_add_sta_node, 2294e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R */ 2295e5b75505Sopenharmony_ci .send_action = atheros_send_action, 2296e5b75505Sopenharmony_ci#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) 2297e5b75505Sopenharmony_ci .wnm_oper = atheros_wnm_oper, 2298e5b75505Sopenharmony_ci#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ 2299e5b75505Sopenharmony_ci .set_qos_map = atheros_set_qos_map, 2300e5b75505Sopenharmony_ci}; 2301