X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libeap%2Fsrc%2Fdrivers%2Fdriver_atheros.c;fp=libeap%2Fsrc%2Fdrivers%2Fdriver_atheros.c;h=a88345fc92f8f1822dd6f23bde6dd96acf43c618;hb=f3746d009c6d7f50025af1f58a85e5fee9680be6;hp=27107aa14210265750f1ae0fadb9e5f06ec8d594;hpb=244f18d04aaf29e68495b5ffeb40ef5cca50942f;p=mech_eap.git diff --git a/libeap/src/drivers/driver_atheros.c b/libeap/src/drivers/driver_atheros.c index 27107aa..a88345f 100644 --- a/libeap/src/drivers/driver_atheros.c +++ b/libeap/src/drivers/driver_atheros.c @@ -5,14 +5,8 @@ * Copyright (c) 2005-2007, Jouni Malinen * Copyright (c) 2009, Atheros Communications * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -20,6 +14,12 @@ #include #include "common.h" +#include "eloop.h" +#include "common/ieee802_11_defs.h" +#include "l2_packet/l2_packet.h" +#include "p2p/p2p.h" + +#include "common.h" #ifndef _BYTE_ORDER #ifdef WORDS_BIGENDIAN #define _BYTE_ORDER _BIG_ENDIAN @@ -34,18 +34,18 @@ */ #define ATH_WPS_IE -#include "os/linux/include/ieee80211_external.h" +#include "ieee80211_external.h" #ifdef CONFIG_WPS #include +#endif /* CONFIG_WPS */ #ifndef ETH_P_80211_RAW #define ETH_P_80211_RAW 0x0019 #endif -#endif /* CONFIG_WPS */ -#include "wireless_copy.h" +#include "linux_wext.h" #include "driver.h" #include "eloop.h" @@ -55,8 +55,12 @@ #include "netlink.h" #include "linux_ioctl.h" +#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) +#define ATHEROS_USE_RAW_RECEIVE +#endif + -struct madwifi_driver_data { +struct atheros_driver_data { struct hostapd_data *hapd; /* back pointer */ char iface[IFNAMSIZ + 1]; @@ -70,11 +74,15 @@ struct madwifi_driver_data { struct hostap_sta_driver_data acct_data; struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ + struct wpabuf *wpa_ie; + struct wpabuf *wps_beacon_ie; + struct wpabuf *wps_probe_resp_ie; + u8 own_addr[ETH_ALEN]; }; -static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, +static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code); -static int madwifi_set_privacy(void *priv, int enabled); +static int atheros_set_privacy(void *priv, int enabled); static const char * athr_get_ioctl_name(int op) { @@ -125,16 +133,8 @@ static const char * athr_get_ioctl_name(int op) return "FILTERFRAME"; case IEEE80211_IOCTL_SET_RTPARAMS: return "SET_RTPARAMS"; - case IEEE80211_IOCTL_SENDADDBA: - return "SENDADDBA"; - case IEEE80211_IOCTL_GETADDBASTATUS: - return "GETADDBASTATUS"; - case IEEE80211_IOCTL_SENDDELBA: - return "SENDDELBA"; case IEEE80211_IOCTL_SET_MEDENYENTRY: return "SET_MEDENYENTRY"; - case IEEE80211_IOCTL_SET_ADDBARESP: - return "SET_ADDBARESP"; case IEEE80211_IOCTL_GET_MACADDR: return "GET_MACADDR"; case IEEE80211_IOCTL_SET_HBRPARAMS: @@ -179,7 +179,7 @@ static const char * athr_get_param_name(int op) static int -set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) +set80211priv(struct atheros_driver_data *drv, int op, void *data, int len) { struct iwreq iwr; int do_inline = len < IFNAMSIZ; @@ -189,13 +189,13 @@ set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) op == IEEE80211_IOCTL_FILTERFRAME) do_inline = 0; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); if (do_inline) { /* * Argument data fits inline; put it there. */ - memcpy(iwr.u.name, data, len); + os_memcpy(iwr.u.name, data, len); } else { /* * Argument data too big for inline transfer; setup a @@ -218,20 +218,20 @@ set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) } static int -set80211param(struct madwifi_driver_data *drv, int op, int arg) +set80211param(struct atheros_driver_data *drv, int op, int arg) { struct iwreq iwr; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.mode = op; - memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); + os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg)); if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { - perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); - wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d " - "(%s) arg %d)", __func__, drv->iface, op, - athr_get_param_name(op), arg); + wpa_printf(MSG_INFO, + "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s", + __func__, drv->iface, op, athr_get_param_name(op), + arg, strerror(errno)); return -1; } return 0; @@ -244,9 +244,9 @@ ether_sprintf(const u8 *addr) static char buf[sizeof(MACSTR)]; if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); + os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0); return buf; } #endif /* CONFIG_NO_STDOUT_DEBUG */ @@ -255,7 +255,7 @@ ether_sprintf(const u8 *addr) * Configure WPA parameters. */ static int -madwifi_configure_wpa(struct madwifi_driver_data *drv, +atheros_configure_wpa(struct atheros_driver_data *drv, struct wpa_bss_params *params) { int v; @@ -264,6 +264,17 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv, case WPA_CIPHER_CCMP: v = IEEE80211_CIPHER_AES_CCM; break; +#ifdef ATH_GCM_SUPPORT + case WPA_CIPHER_CCMP_256: + v = IEEE80211_CIPHER_AES_CCM_256; + break; + case WPA_CIPHER_GCMP: + v = IEEE80211_CIPHER_AES_GCM; + break; + case WPA_CIPHER_GCMP_256: + v = IEEE80211_CIPHER_AES_GCM_256; + break; +#endif /* ATH_GCM_SUPPORT */ case WPA_CIPHER_TKIP: v = IEEE80211_CIPHER_TKIP; break; @@ -283,14 +294,15 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv, } wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { - printf("Unable to set group key cipher to %u\n", v); + wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v); return -1; } if (v == IEEE80211_CIPHER_WEP) { /* key length is done only for specific ciphers */ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { - printf("Unable to set group key length to %u\n", v); + wpa_printf(MSG_INFO, + "Unable to set group key length to %u", v); return -1; } } @@ -298,13 +310,22 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv, v = 0; if (params->wpa_pairwise & WPA_CIPHER_CCMP) v |= 1<wpa_pairwise & WPA_CIPHER_CCMP_256) + v |= 1<wpa_pairwise & WPA_CIPHER_GCMP) + v |= 1<wpa_pairwise & WPA_CIPHER_GCMP_256) + v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) v |= 1<wpa_pairwise & WPA_CIPHER_NONE) v |= 1<wpa_key_mgmt); if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, params->wpa_key_mgmt)) { - printf("Unable to set key management algorithms to 0x%x\n", - params->wpa_key_mgmt); + wpa_printf(MSG_INFO, + "Unable to set key management algorithms to 0x%x", + params->wpa_key_mgmt); return -1; } v = 0; if (params->rsn_preauth) v |= BIT(0); - wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", - __func__, params->rsn_preauth); +#ifdef CONFIG_IEEE80211W + if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + v |= BIT(7); + if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) + v |= BIT(6); + } +#endif /* CONFIG_IEEE80211W */ + + wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v); if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { - printf("Unable to set RSN capabilities to 0x%x\n", v); + wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", + v); return -1; } wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { - printf("Unable to set WPA to %u\n", params->wpa); + wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); return -1; } return 0; } static int -madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) +atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); @@ -348,22 +378,19 @@ madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) IEEE80211_AUTH_AUTO) < 0) return -1; /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ - return madwifi_set_privacy(drv, 0); + return atheros_set_privacy(drv, 0); } if (!params->wpa && !params->ieee802_1x) { - hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); + wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!"); return -1; } - if (params->wpa && madwifi_configure_wpa(drv, params) != 0) { - hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); + if (params->wpa && atheros_configure_wpa(drv, params) != 0) { + wpa_printf(MSG_WARNING, "Error configuring WPA state!"); return -1; } if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); + wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!"); return -1; } @@ -371,9 +398,9 @@ madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) } static int -madwifi_set_privacy(void *priv, int enabled) +atheros_set_privacy(void *priv, int enabled) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); @@ -381,9 +408,9 @@ madwifi_set_privacy(void *priv, int enabled) } static int -madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) +atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_mlme mlme; int ret; @@ -395,7 +422,7 @@ madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) else mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; mlme.im_reason = 0; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, @@ -406,30 +433,31 @@ madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) } static int -madwifi_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) +atheros_sta_set_flags(void *priv, const u8 *addr, + unsigned int total_flags, unsigned int flags_or, + unsigned int flags_and) { /* For now, only support setting Authorized flag */ if (flags_or & WPA_STA_AUTHORIZED) - return madwifi_set_sta_authorized(priv, addr, 1); + return atheros_set_sta_authorized(priv, addr, 1); if (!(flags_and & WPA_STA_AUTHORIZED)) - return madwifi_set_sta_authorized(priv, addr, 0); + return atheros_set_sta_authorized(priv, addr, 0); return 0; } static int -madwifi_del_key(void *priv, const u8 *addr, int key_idx) +atheros_del_key(void *priv, const u8 *addr, int key_idx) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_del_key wk; int ret; wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", __func__, ether_sprintf(addr), key_idx); - memset(&wk, 0, sizeof(wk)); + os_memset(&wk, 0, sizeof(wk)); if (addr != NULL) { - memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; } else { wk.idk_keyix = key_idx; @@ -446,17 +474,17 @@ madwifi_del_key(void *priv, const u8 *addr, int key_idx) } static int -madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, +atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_key wk; u_int8_t cipher; int ret; if (alg == WPA_ALG_NONE) - return madwifi_del_key(drv, addr, key_idx); + return atheros_del_key(drv, addr, key_idx); wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", __func__, alg, ether_sprintf(addr), key_idx); @@ -471,31 +499,59 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, case WPA_ALG_CCMP: cipher = IEEE80211_CIPHER_AES_CCM; break; +#ifdef ATH_GCM_SUPPORT + case WPA_ALG_CCMP_256: + cipher = IEEE80211_CIPHER_AES_CCM_256; + break; + case WPA_ALG_GCMP: + cipher = IEEE80211_CIPHER_AES_GCM; + break; + case WPA_ALG_GCMP_256: + cipher = IEEE80211_CIPHER_AES_GCM_256; + break; +#endif /* ATH_GCM_SUPPORT */ +#ifdef CONFIG_IEEE80211W + case WPA_ALG_IGTK: + cipher = IEEE80211_CIPHER_AES_CMAC; + break; +#ifdef ATH_GCM_SUPPORT + case WPA_ALG_BIP_CMAC_256: + cipher = IEEE80211_CIPHER_AES_CMAC_256; + break; + case WPA_ALG_BIP_GMAC_128: + cipher = IEEE80211_CIPHER_AES_GMAC; + break; + case WPA_ALG_BIP_GMAC_256: + cipher = IEEE80211_CIPHER_AES_GMAC_256; + break; +#endif /* ATH_GCM_SUPPORT */ +#endif /* CONFIG_IEEE80211W */ default: - printf("%s: unknown/unsupported algorithm %d\n", - __func__, alg); + wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d", + __func__, alg); return -1; } if (key_len > sizeof(wk.ik_keydata)) { - printf("%s: key length %lu too big\n", __func__, - (unsigned long) key_len); + wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__, + (unsigned long) key_len); return -3; } - memset(&wk, 0, sizeof(wk)); + os_memset(&wk, 0, sizeof(wk)); wk.ik_type = cipher; wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; - if (addr == NULL) { - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + if (addr == NULL || is_broadcast_ether_addr(addr)) { + os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); wk.ik_keyix = key_idx; - wk.ik_flags |= IEEE80211_KEY_DEFAULT; + if (set_tx) + wk.ik_flags |= IEEE80211_KEY_DEFAULT; } else { - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = IEEE80211_KEYIX_NONE; } wk.ik_keylen = key_len; - memcpy(wk.ik_keydata, key, key_len); + os_memcpy(wk.ik_keydata, key, key_len); ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); if (ret < 0) { @@ -510,20 +566,20 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, static int -madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, +atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, u8 *seq) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_key wk; wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", __func__, ether_sprintf(addr), idx); - memset(&wk, 0, sizeof(wk)); + os_memset(&wk, 0, sizeof(wk)); if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = idx; if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { @@ -544,52 +600,53 @@ madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, #define WPA_KEY_RSC_LEN 8 #endif u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); for (i = 0; i < WPA_KEY_RSC_LEN; i++) { seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; } } #else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); #endif /* WORDS_BIGENDIAN */ return 0; } static int -madwifi_flush(void *priv) +atheros_flush(void *priv) { u8 allsta[IEEE80211_ADDR_LEN]; - memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return madwifi_sta_deauth(priv, NULL, allsta, + os_memset(allsta, 0xff, IEEE80211_ADDR_LEN); + return atheros_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); } static int -madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, +atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, const u8 *addr) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_sta_stats stats; - memset(data, 0, sizeof(*data)); + os_memset(data, 0, sizeof(*data)); /* * Fetch statistics for station from the system. */ - memset(&stats, 0, sizeof(stats)); - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); + os_memset(&stats, 0, sizeof(stats)); + os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, &stats, sizeof(stats))) { wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " MACSTR ")", __func__, MAC2STR(addr)); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - memcpy(data, &drv->acct_data, sizeof(*data)); + if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + os_memcpy(data, &drv->acct_data, sizeof(*data)); return 0; } - printf("Failed to get station stats information element.\n"); + wpa_printf(MSG_INFO, + "Failed to get station stats information element"); return -1; } @@ -602,16 +659,16 @@ madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, static int -madwifi_sta_clear_stats(void *priv, const u8 *addr) +atheros_sta_clear_stats(void *priv, const u8 *addr) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_mlme mlme; int ret; wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); mlme.im_op = IEEE80211_MLME_CLEAR_STATS; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { @@ -624,20 +681,61 @@ madwifi_sta_clear_stats(void *priv, const u8 *addr) static int -madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) +atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) { - /* - * Do nothing; we setup parameters at startup that define the - * contents of the beacon information element. - */ + struct atheros_driver_data *drv = priv; + u8 buf[512]; + struct ieee80211req_getset_appiebuf *app_ie; + + wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, + (unsigned long) ie_len); + wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len); + + wpabuf_free(drv->wpa_ie); + drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); + + app_ie = (struct ieee80211req_getset_appiebuf *) buf; + os_memcpy(&(app_ie->app_buf[0]), ie, ie_len); + app_ie->app_buflen = ie_len; + + app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON; + + /* append WPS IE for Beacon */ + if (drv->wps_beacon_ie != NULL) { + os_memcpy(&(app_ie->app_buf[ie_len]), + wpabuf_head(drv->wps_beacon_ie), + wpabuf_len(drv->wps_beacon_ie)); + app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); + } + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)", + app_ie->app_buf, app_ie->app_buflen); + set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, + sizeof(struct ieee80211req_getset_appiebuf) + + app_ie->app_buflen); + + /* append WPS IE for Probe Response */ + app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP; + if (drv->wps_probe_resp_ie != NULL) { + os_memcpy(&(app_ie->app_buf[ie_len]), + wpabuf_head(drv->wps_probe_resp_ie), + wpabuf_len(drv->wps_probe_resp_ie)); + app_ie->app_buflen = ie_len + + wpabuf_len(drv->wps_probe_resp_ie); + } else + app_ie->app_buflen = ie_len; + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)", + app_ie->app_buf, app_ie->app_buflen); + set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, + sizeof(struct ieee80211req_getset_appiebuf) + + app_ie->app_buflen); return 0; } static int -madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, +atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_mlme mlme; int ret; @@ -646,7 +744,7 @@ madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, mlme.im_op = IEEE80211_MLME_DEAUTH; mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR @@ -658,10 +756,10 @@ madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, } static int -madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, +atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct ieee80211req_mlme mlme; int ret; @@ -670,7 +768,7 @@ madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, mlme.im_op = IEEE80211_MLME_DISASSOC; mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " @@ -681,100 +779,341 @@ madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, return ret; } -#ifdef CONFIG_WPS -static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, +static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, + u8 qos_map_set_len) +{ +#ifdef CONFIG_ATHEROS_QOS_MAP + struct atheros_driver_data *drv = ctx; + struct ieee80211req_athdbg req; + struct ieee80211_qos_map *qos_map = &req.data.qos_map; + struct iwreq iwr; + int i, up_start; + + if (qos_map_set_len < 16 || qos_map_set_len > 58 || + qos_map_set_len & 1) { + wpa_printf(MSG_ERROR, "Invalid QoS Map"); + return -1; + } else { + os_memset(&req, 0, sizeof(struct ieee80211req_athdbg)); + req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF; + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name)); + iwr.u.data.pointer = (void *) &req; + iwr.u.data.length = sizeof(struct ieee80211req_athdbg); + } + + qos_map->valid = 1; + qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; + if (qos_map->num_dscp_except) { + for (i = 0; i < qos_map->num_dscp_except; i++) { + qos_map->dscp_exception[i].dscp = qos_map_set[i * 2]; + qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1]; + } + } + + up_start = qos_map_set_len - 16; + for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) { + qos_map->up[i].low = qos_map_set[up_start + (i * 2)]; + qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1]; + } + + if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) { + wpa_printf(MSG_ERROR, + "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s", + __func__, drv->iface, strerror(errno)); + return -1; + } +#endif /* CONFIG_ATHEROS_QOS_MAP */ + + return 0; +} + +#ifdef ATHEROS_USE_RAW_RECEIVE +static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { - struct madwifi_driver_data *drv = ctx; + struct atheros_driver_data *drv = ctx; const struct ieee80211_mgmt *mgmt; - u16 fc; union wpa_event_data event; + u16 fc, stype; + int ielen; + const u8 *iebuf; - /* Send Probe Request information to WPS processing */ - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) + if (len < IEEE80211_HDRLEN) return; + mgmt = (const struct ieee80211_mgmt *) buf; fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || - WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) + + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) + return; + + stype = WLAN_FC_GET_STYPE(fc); + + wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, + (int) len); + + if (stype == WLAN_FC_STYPE_PROBE_REQ) { + if (len < IEEE80211_HDRLEN) + return; + + os_memset(&event, 0, sizeof(event)); + event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.da = mgmt->da; + event.rx_probe_req.bssid = mgmt->bssid; + event.rx_probe_req.ie = buf + IEEE80211_HDRLEN; + event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN; + wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); + return; + } + + if (stype == WLAN_FC_STYPE_ACTION && + (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 || + is_broadcast_ether_addr(mgmt->bssid))) { + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); + return; + } + + if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", + __func__); return; + } - os_memset(&event, 0, sizeof(event)); - event.rx_probe_req.sa = mgmt->sa; - event.rx_probe_req.ie = mgmt->u.probe_req.variable; - event.rx_probe_req.ie_len = - len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); - wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); + switch (stype) { + case WLAN_FC_STYPE_ASSOC_REQ: + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)) + break; + ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); + iebuf = mgmt->u.assoc_req.variable; + drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0); + break; + case WLAN_FC_STYPE_REASSOC_REQ: + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)) + break; + ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); + iebuf = mgmt->u.reassoc_req.variable; + drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); + break; + case WLAN_FC_STYPE_AUTH: + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) + break; + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); + os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN); + event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); + event.auth.status_code = + le_to_host16(mgmt->u.auth.status_code); + event.auth.auth_transaction = + le_to_host16(mgmt->u.auth.auth_transaction); + event.auth.ies = mgmt->u.auth.variable; + event.auth.ies_len = len - IEEE80211_HDRLEN - + sizeof(mgmt->u.auth); + wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event); + break; + default: + break; + } } -#endif /* CONFIG_WPS */ +#endif /* ATHEROS_USE_RAW_RECEIVE */ -static int madwifi_receive_probe_req(struct madwifi_driver_data *drv) +static int atheros_receive_pkt(struct atheros_driver_data *drv) { int ret = 0; -#ifdef CONFIG_WPS struct ieee80211req_set_filter filt; wpa_printf(MSG_DEBUG, "%s Enter", __func__); - filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ; - - ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, - sizeof(struct ieee80211req_set_filter)); - if (ret) - return ret; + filt.app_filterype = 0; +#ifdef CONFIG_WPS + filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ; +#endif /* CONFIG_WPS */ +#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) + filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | + IEEE80211_FILTER_TYPE_AUTH | + IEEE80211_FILTER_TYPE_ACTION); +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ +#ifdef CONFIG_WNM + filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; +#endif /* CONFIG_WNM */ +#ifdef CONFIG_HS20 + filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; +#endif /* CONFIG_HS20 */ + if (filt.app_filterype) { + ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, + sizeof(struct ieee80211req_set_filter)); + if (ret) + return ret; + } +#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, - madwifi_raw_receive, drv, 1); + atheros_raw_receive, drv, 1); if (drv->sock_raw == NULL) return -1; -#endif /* CONFIG_WPS */ +#endif /* CONFIG_WPS || CONFIG_IEEE80211R */ return ret; } +static int atheros_reset_appfilter(struct atheros_driver_data *drv) +{ + struct ieee80211req_set_filter filt; + filt.app_filterype = 0; + return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, + sizeof(struct ieee80211req_set_filter)); +} + #ifdef CONFIG_WPS static int -madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) +atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) { - struct madwifi_driver_data *drv = priv; - u8 buf[500]; + struct atheros_driver_data *drv = priv; + u8 buf[512]; struct ieee80211req_getset_appiebuf *beac_ie; - wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, - (unsigned long) len); + wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__, + (unsigned long) len, frametype); + wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len); beac_ie = (struct ieee80211req_getset_appiebuf *) buf; beac_ie->app_frmtype = frametype; beac_ie->app_buflen = len; - memcpy(&(beac_ie->app_buf[0]), ie, len); + os_memcpy(&(beac_ie->app_buf[0]), ie, len); + + /* append the WPA/RSN IE if it is set already */ + if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || + (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && + (drv->wpa_ie != NULL)) { + wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE", + drv->wpa_ie); + os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), + wpabuf_len(drv->wpa_ie)); + beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); + } + wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF", + beac_ie->app_buf, beac_ie->app_buflen); return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, - sizeof(struct ieee80211req_getset_appiebuf) + len); + sizeof(struct ieee80211req_getset_appiebuf) + + beac_ie->app_buflen); } static int -madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, +atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, const struct wpabuf *proberesp, const struct wpabuf *assocresp) { - madwifi_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, + struct atheros_driver_data *drv = priv; + + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon); + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp", + proberesp); + wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp", + assocresp); + wpabuf_free(drv->wps_beacon_ie); + drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; + wpabuf_free(drv->wps_probe_resp_ie); + drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL; + + atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, assocresp ? wpabuf_len(assocresp) : 0, IEEE80211_APPIE_FRAME_ASSOC_RESP); - if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, + if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, beacon ? wpabuf_len(beacon) : 0, IEEE80211_APPIE_FRAME_BEACON)) return -1; - return madwifi_set_wps_ie(priv, + return atheros_set_wps_ie(priv, proberesp ? wpabuf_head(proberesp) : NULL, proberesp ? wpabuf_len(proberesp): 0, IEEE80211_APPIE_FRAME_PROBE_RESP); } #else /* CONFIG_WPS */ -#define madwifi_set_ap_wps_ie NULL +#define atheros_set_ap_wps_ie NULL #endif /* CONFIG_WPS */ +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) +static int +atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq, + u16 status_code, const u8 *ie, size_t len) +{ + struct atheros_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d", + __func__, ether_sprintf(addr), status_code); + + mlme.im_op = IEEE80211_MLME_AUTH; + mlme.im_reason = status_code; + mlme.im_seq = seq; + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + mlme.im_optie_len = len; + if (len) { + if (len < IEEE80211_MAX_OPT_IE) { + os_memcpy(mlme.im_optie, ie, len); + } else { + wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " + "opt_ie STA (addr " MACSTR " reason %d, " + "ie_len %d)", + __func__, MAC2STR(addr), status_code, + (int) len); + return -1; + } + } + ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR + " reason %d)", + __func__, MAC2STR(addr), status_code); + } + return ret; +} + +static int +atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, + int reassoc, u16 status_code, const u8 *ie, size_t len) +{ + struct atheros_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d", + __func__, ether_sprintf(addr), status_code, reassoc); + + if (reassoc) + mlme.im_op = IEEE80211_MLME_REASSOC; + else + mlme.im_op = IEEE80211_MLME_ASSOC; + mlme.im_reason = status_code; + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + mlme.im_optie_len = len; + if (len) { + if (len < IEEE80211_MAX_OPT_IE) { + os_memcpy(mlme.im_optie, ie, len); + } else { + wpa_printf(MSG_DEBUG, "%s: Not enough space to copy " + "opt_ie STA (addr " MACSTR " reason %d, " + "ie_len %d)", + __func__, MAC2STR(addr), status_code, + (int) len); + return -1; + } + } + ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR + " reason %d)", + __func__, MAC2STR(addr), status_code); + } + return ret; +} +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ + static void -madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) +atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct ieee80211req_wpaie ie; @@ -784,8 +1123,8 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) /* * Fetch negotiated WPA/RSN parameters from the system. */ - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); + os_memset(&ie, 0, sizeof(ie)); + os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { /* * See ATH_WPS_IE comment in the beginning of the file for a @@ -795,21 +1134,21 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) __func__, strerror(errno)); goto no_ie; } - wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE", + wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", ie.wpa_ie, IEEE80211_MAX_OPT_IE); - wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE", + wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", ie.rsn_ie, IEEE80211_MAX_OPT_IE); #ifdef ATH_WPS_IE - wpa_hexdump(MSG_MSGDUMP, "madwifi req WPS IE", + wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", ie.wps_ie, IEEE80211_MAX_OPT_IE); #endif /* ATH_WPS_IE */ iebuf = ie.wpa_ie; - /* madwifi seems to return some random data if WPA/RSN IE is not set. + /* atheros seems to return some random data if WPA/RSN IE is not set. * Assume the IE was not included if the IE type is unknown. */ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) iebuf[1] = 0; if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { - /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not + /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not * set. This is needed for WPA2. */ iebuf = ie.rsn_ie; if (iebuf[0] != WLAN_EID_RSN) @@ -833,25 +1172,26 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) ielen += 2; no_ie: - drv_event_assoc(hapd, addr, iebuf, ielen); + drv_event_assoc(hapd, addr, iebuf, ielen, 0); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { /* Cached accounting data is not valid anymore. */ - memset(drv->acct_mac, 0, ETH_ALEN); - memset(&drv->acct_data, 0, sizeof(drv->acct_data)); + os_memset(drv->acct_mac, 0, ETH_ALEN); + os_memset(&drv->acct_data, 0, sizeof(drv->acct_data)); } } static void -madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, +atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, char *custom, char *end) { +#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { + if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { char *pos; u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); + pos = os_strstr(custom, "addr="); if (pos == NULL) { wpa_printf(MSG_DEBUG, "MLME-MICHAELMICFAILURE.indication " @@ -875,55 +1215,179 @@ madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, char *key, *value; u32 val; key = custom; - while ((key = strchr(key, '\n')) != NULL) { + while ((key = os_strchr(key, '\n')) != NULL) { key++; - value = strchr(key, '='); + value = os_strchr(key, '='); if (value == NULL) continue; *value++ = '\0'; val = strtoul(value, NULL, 10); - if (strcmp(key, "mac") == 0) + if (os_strcmp(key, "mac") == 0) hwaddr_aton(value, drv->acct_mac); - else if (strcmp(key, "rx_packets") == 0) + else if (os_strcmp(key, "rx_packets") == 0) drv->acct_data.rx_packets = val; - else if (strcmp(key, "tx_packets") == 0) + else if (os_strcmp(key, "tx_packets") == 0) drv->acct_data.tx_packets = val; - else if (strcmp(key, "rx_bytes") == 0) + else if (os_strcmp(key, "rx_bytes") == 0) drv->acct_data.rx_bytes = val; - else if (strcmp(key, "tx_bytes") == 0) + else if (os_strcmp(key, "tx_bytes") == 0) drv->acct_data.tx_bytes = val; key = value; } #ifdef CONFIG_WPS - } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { + } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { /* Some atheros kernels send push button as a wireless event */ /* PROBLEM! this event is received for ALL BSSs ... * so all are enabled for WPS... ugh. */ wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); - } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { + } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) { /* * Atheros driver uses a hack to pass Probe Request frames as a * binary data in the custom wireless event. The old way (using * packet sniffing) didn't work when bridging. * Format: "Manage.prob_req " | zero padding | frame */ -#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */ int len = atoi(custom + 16); - if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) { + if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event " "length %d", len); return; } - madwifi_raw_receive(drv, NULL, - (u8 *) custom + WPS_FRAM_TAG_SIZE, len); + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); #endif /* CONFIG_WPS */ +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) + } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) { + /* Format: "Manage.assoc_req " | zero padding | + * frame */ + int len = atoi(custom + 17); + if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { + wpa_printf(MSG_DEBUG, + "Invalid Manage.assoc_req event length %d", + len); + return; + } + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); + } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { + /* Format: "Manage.auth " | zero padding | frame */ + int len = atoi(custom + 12); + if (len < 0 || + MGMT_FRAM_TAG_SIZE + len > end - custom) { + wpa_printf(MSG_DEBUG, + "Invalid Manage.auth event length %d", len); + return; + } + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); +#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */ +#ifdef ATHEROS_USE_RAW_RECEIVE + } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { + /* Format: "Manage.assoc_req " | zero padding | frame + */ + int len = atoi(custom + 14); + if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) { + wpa_printf(MSG_DEBUG, + "Invalid Manage.action event length %d", + len); + return; + } + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); +#endif /* ATHEROS_USE_RAW_RECEIVE */ + } +} + +/* +* Handle size of data problem. WEXT only allows data of 256 bytes for custom +* events, and p2p data can be much bigger. So the athr driver sends a small +* event telling me to collect the big data with an ioctl. +* On the first event, send all pending events to supplicant. +*/ +static void fetch_pending_big_events(struct atheros_driver_data *drv) +{ + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt; + u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */ + u16 fc, stype; + struct iwreq iwr; + size_t data_len; + u32 freq, frame_type; + + while (1) { + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + + iwr.u.data.pointer = (void *) tbuf; + iwr.u.data.length = sizeof(tbuf); + iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME; + + if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) + < 0) { + if (errno == ENOSPC) { + wpa_printf(MSG_DEBUG, "%s:%d exit", + __func__, __LINE__); + return; + } + wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM[" + "P2P_FETCH_FRAME] failed: %s", + __func__, strerror(errno)); + return; + } + data_len = iwr.u.data.length; + wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data", + (u8 *) tbuf, data_len); + if (data_len < sizeof(freq) + sizeof(frame_type) + 24) { + wpa_printf(MSG_DEBUG, "athr: frame too short"); + continue; + } + os_memcpy(&freq, tbuf, sizeof(freq)); + os_memcpy(&frame_type, &tbuf[sizeof(freq)], + sizeof(frame_type)); + mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)]; + data_len -= sizeof(freq) + sizeof(frame_type); + + if (frame_type == IEEE80211_EV_RX_MGMT) { + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + + wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u " + "freq=%u len=%u", stype, freq, (int) data_len); + + if (stype == WLAN_FC_STYPE_ACTION) { + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = (const u8 *) mgmt; + event.rx_mgmt.frame_len = data_len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, + &event); + continue; + } + } else { + wpa_printf(MSG_DEBUG, "athr: %s unknown type %d", + __func__, frame_type); + continue; + } } } static void -madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, - char *data, int len) +atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv, + int opcode, char *buf, int len) +{ + switch (opcode) { + case IEEE80211_EV_RX_MGMT: + wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT"); + fetch_pending_big_events(drv); + break; + default: + break; + } +} + +static void +atheros_wireless_event_wireless(struct atheros_driver_data *drv, + char *data, unsigned int len) { struct iw_event iwe_buf, *iwe = &iwe_buf; char *pos, *end, *custom, *buf; @@ -931,13 +1395,13 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, pos = data; end = data + len; - while (pos + IW_EV_LCP_LEN <= end) { + while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { /* Event data may be unaligned, so make a local, aligned copy * before processing. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); + os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) + if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) return; custom = pos + IW_EV_POINT_LEN; @@ -948,10 +1412,10 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, /* WE-19 removed the pointer from struct iw_point */ char *dpos = (char *) &iwe_buf.u.data.length; int dlen = dpos - (char *) &iwe_buf; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); + os_memcpy(dpos, pos + IW_EV_LCP_LEN, + sizeof(struct iw_event) - dlen); } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); + os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); custom += IW_EV_POINT_OFF; } @@ -961,7 +1425,7 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, (u8 *) iwe->u.addr.sa_data); break; case IWEVREGISTERED: - madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data); + atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data); break; case IWEVASSOCREQIE: /* Driver hack.. Use IWEVASSOCREQIE to bypass @@ -969,16 +1433,23 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, * just like IWEVCUSTOM. */ case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) + if (iwe->u.data.length > end - custom) return; - buf = malloc(iwe->u.data.length + 1); + buf = os_malloc(iwe->u.data.length + 1); if (buf == NULL) return; /* XXX */ - memcpy(buf, custom, iwe->u.data.length); + os_memcpy(buf, custom, iwe->u.data.length); buf[iwe->u.data.length] = '\0'; - madwifi_wireless_event_wireless_custom( - drv, buf, buf + iwe->u.data.length); - free(buf); + + if (iwe->u.data.flags != 0) { + atheros_wireless_event_atheros_custom( + drv, (int) iwe->u.data.flags, + buf, len); + } else { + atheros_wireless_event_wireless_custom( + drv, buf, buf + iwe->u.data.length); + } + os_free(buf); break; } @@ -988,10 +1459,10 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, static void -madwifi_wireless_event_rtm_newlink(void *ctx, +atheros_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len) { - struct madwifi_driver_data *drv = ctx; + struct atheros_driver_data *drv = ctx; int attrlen, rta_len; struct rtattr *attr; @@ -1004,7 +1475,7 @@ madwifi_wireless_event_rtm_newlink(void *ctx, rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_WIRELESS) { - madwifi_wireless_event_wireless( + atheros_wireless_event_wireless( drv, ((char *) attr) + rta_len, attr->rta_len - rta_len); } @@ -1014,7 +1485,7 @@ madwifi_wireless_event_rtm_newlink(void *ctx, static int -madwifi_get_we_version(struct madwifi_driver_data *drv) +atheros_get_we_version(struct atheros_driver_data *drv) { struct iw_range *range; struct iwreq iwr; @@ -1032,7 +1503,7 @@ madwifi_get_we_version(struct madwifi_driver_data *drv) if (range == NULL) return -1; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.data.pointer = (caddr_t) range; iwr.u.data.length = buflen; @@ -1041,8 +1512,9 @@ madwifi_get_we_version(struct madwifi_driver_data *drv) sizeof(range->enc_capa); if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); + wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", + strerror(errno)); + os_free(range); return -1; } else if (iwr.u.data.length >= minlen && range->we_version_compiled >= 18) { @@ -1054,23 +1526,23 @@ madwifi_get_we_version(struct madwifi_driver_data *drv) drv->we_version = range->we_version_compiled; } - free(range); + os_free(range); return 0; } static int -madwifi_wireless_event_init(struct madwifi_driver_data *drv) +atheros_wireless_event_init(struct atheros_driver_data *drv) { struct netlink_config *cfg; - madwifi_get_we_version(drv); + atheros_get_we_version(drv); cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL) return -1; cfg->ctx = drv; - cfg->newlink_cb = madwifi_wireless_event_rtm_newlink; + cfg->newlink_cb = atheros_wireless_event_rtm_newlink; drv->netlink = netlink_init(cfg); if (drv->netlink == NULL) { os_free(cfg); @@ -1082,10 +1554,10 @@ madwifi_wireless_event_init(struct madwifi_driver_data *drv) static int -madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr) +atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, + int encrypt, const u8 *own_addr, u32 flags) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; unsigned char buf[3000]; unsigned char *bp = buf; struct l2_ethhdr *eth; @@ -1100,62 +1572,66 @@ madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, */ len = data_len + sizeof(struct l2_ethhdr); if (len > sizeof(buf)) { - bp = malloc(len); + bp = os_malloc(len); if (bp == NULL) { - printf("EAPOL frame discarded, cannot malloc temp " - "buffer of size %lu!\n", (unsigned long) len); + wpa_printf(MSG_INFO, + "EAPOL frame discarded, cannot malloc temp buffer of size %lu!", + (unsigned long) len); return -1; } } eth = (struct l2_ethhdr *) bp; - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, own_addr, ETH_ALEN); + os_memcpy(eth->h_dest, addr, ETH_ALEN); + os_memcpy(eth->h_source, own_addr, ETH_ALEN); eth->h_proto = host_to_be16(ETH_P_EAPOL); - memcpy(eth+1, data, data_len); + os_memcpy(eth + 1, data, data_len); wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); if (bp != buf) - free(bp); + os_free(bp); return status; } static void handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { - struct madwifi_driver_data *drv = ctx; + struct atheros_driver_data *drv = ctx; drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), len - sizeof(struct l2_ethhdr)); } static void * -madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) +atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) { - struct madwifi_driver_data *drv; + struct atheros_driver_data *drv; struct ifreq ifr; struct iwreq iwr; char brname[IFNAMSIZ]; - drv = os_zalloc(sizeof(struct madwifi_driver_data)); + drv = os_zalloc(sizeof(struct atheros_driver_data)); if (drv == NULL) { - printf("Could not allocate memory for madwifi driver data\n"); + wpa_printf(MSG_INFO, + "Could not allocate memory for atheros driver data"); return NULL; } drv->hapd = hapd; drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); + wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", + strerror(errno)); goto bad; } - memcpy(drv->iface, params->ifname, sizeof(drv->iface)); + os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); - memset(&ifr, 0, sizeof(ifr)); + os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); + wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", + strerror(errno)); goto bad; } drv->ifindex = ifr.ifr_ifindex; @@ -1166,6 +1642,7 @@ madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) goto bad; if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) goto bad; + os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN); if (params->bridge[0]) { wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", params->bridge[0]); @@ -1184,45 +1661,57 @@ madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) } else drv->sock_recv = drv->sock_xmit; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.mode = IW_MODE_MASTER; if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { - perror("ioctl[SIOCSIWMODE]"); - printf("Could not set interface to master mode!\n"); + wpa_printf(MSG_ERROR, + "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s", + strerror(errno)); goto bad; } /* mark down during setup */ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); - madwifi_set_privacy(drv, 0); /* default to no privacy */ + atheros_set_privacy(drv, 0); /* default to no privacy */ - madwifi_receive_probe_req(drv); + if (atheros_receive_pkt(drv)) + goto bad; - if (madwifi_wireless_event_init(drv)) + if (atheros_wireless_event_init(drv)) goto bad; return drv; bad: + atheros_reset_appfilter(drv); + if (drv->sock_raw) + l2_packet_deinit(drv->sock_raw); if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) l2_packet_deinit(drv->sock_recv); if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); if (drv->ioctl_sock >= 0) close(drv->ioctl_sock); - if (drv != NULL) - free(drv); + os_free(drv); return NULL; } static void -madwifi_deinit(void *priv) +atheros_deinit(void *priv) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; + atheros_reset_appfilter(drv); + + if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) { + atheros_set_opt_ie(priv, NULL, 0); + wpabuf_free(drv->wpa_ie); + wpabuf_free(drv->wps_beacon_ie); + wpabuf_free(drv->wps_probe_resp_ie); + } netlink_deinit(drv->netlink); (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); if (drv->ioctl_sock >= 0) @@ -1233,43 +1722,45 @@ madwifi_deinit(void *priv) l2_packet_deinit(drv->sock_xmit); if (drv->sock_raw) l2_packet_deinit(drv->sock_raw); - free(drv); + os_free(drv); } static int -madwifi_set_ssid(void *priv, const u8 *buf, int len) +atheros_set_ssid(void *priv, const u8 *buf, int len) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct iwreq iwr; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.flags = 1; /* SSID active */ iwr.u.essid.pointer = (caddr_t) buf; iwr.u.essid.length = len + 1; if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); + wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s", + len, strerror(errno)); return -1; } return 0; } static int -madwifi_get_ssid(void *priv, u8 *buf, int len) +atheros_get_ssid(void *priv, u8 *buf, int len) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; struct iwreq iwr; int ret = 0; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len; + iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? + IW_ESSID_MAX_SIZE : len; if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); + wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", + strerror(errno)); ret = -1; } else ret = iwr.u.essid.length; @@ -1278,39 +1769,407 @@ madwifi_get_ssid(void *priv, u8 *buf, int len) } static int -madwifi_set_countermeasures(void *priv, int enabled) +atheros_set_countermeasures(void *priv, int enabled) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); } static int -madwifi_commit(void *priv) +atheros_commit(void *priv) { - struct madwifi_driver_data *drv = priv; + struct atheros_driver_data *drv = priv; return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); } +static int atheros_set_authmode(void *priv, int auth_algs) +{ + int authmode; + + if ((auth_algs & WPA_AUTH_ALG_OPEN) && + (auth_algs & WPA_AUTH_ALG_SHARED)) + authmode = IEEE80211_AUTH_AUTO; + else if (auth_algs & WPA_AUTH_ALG_OPEN) + authmode = IEEE80211_AUTH_OPEN; + else if (auth_algs & WPA_AUTH_ALG_SHARED) + authmode = IEEE80211_AUTH_SHARED; + else + return -1; + + return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode); +} + +static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) +{ + /* + * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x, + * set_generic_elem, and hapd_set_ssid. + */ + + wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x " + "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x " + "wpa_version=0x%x privacy=%d interworking=%d", + params->pairwise_ciphers, params->group_cipher, + params->key_mgmt_suites, params->auth_algs, + params->wpa_version, params->privacy, params->interworking); + wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID", + params->ssid, params->ssid_len); + if (params->hessid) + wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR, + MAC2STR(params->hessid)); + wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies", + params->beacon_ies); + wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies", + params->proberesp_ies); + wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", + params->assocresp_ies); + +#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN)) + if (params->osen) { + struct wpa_bss_params bss_params; + + os_memset(&bss_params, 0, sizeof(struct wpa_bss_params)); + bss_params.enabled = 1; + bss_params.wpa = 2; + bss_params.wpa_pairwise = WPA_CIPHER_CCMP; + bss_params.wpa_group = WPA_CIPHER_CCMP; + bss_params.ieee802_1x = 1; + + if (atheros_set_privacy(priv, 1) || + set80211param(priv, IEEE80211_PARAM_OSEN, 1)) + return -1; + + return atheros_set_ieee8021x(priv, &bss_params); + } +#endif /* CONFIG_HS20 && IEEE80211_PARAM_OSEN */ + + return 0; +} + + +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) + +static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, + int noack, unsigned int freq, + const u16 *csa_offs, size_t csa_offs_len) +{ + struct atheros_driver_data *drv = priv; + u8 buf[1510]; + const struct ieee80211_mgmt *mgmt; + struct ieee80211req_mgmtbuf *mgmt_frm; + + mgmt = (const struct ieee80211_mgmt *) frm; + wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__, + (unsigned long) data_len, MAC2STR(mgmt->da)); + mgmt_frm = (struct ieee80211req_mgmtbuf *) buf; + os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); + mgmt_frm->buflen = data_len; + if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) { + wpa_printf(MSG_INFO, "atheros: Too long frame for " + "atheros_send_mgmt (%u)", (unsigned int) data_len); + return -1; + } + os_memcpy(&mgmt_frm->buf[0], frm, data_len); + return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm, + sizeof(struct ieee80211req_mgmtbuf) + data_len); +} +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ + + +#ifdef CONFIG_IEEE80211R + +static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie, + size_t tspec_ielen) +{ + struct atheros_driver_data *drv = priv; + int retv; + struct ieee80211req_res req; + struct ieee80211req_res_addts *addts = &req.u.addts; + + wpa_printf(MSG_DEBUG, "%s", __func__); + req.type = IEEE80211_RESREQ_ADDTS; + os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); + os_memcpy(addts->tspecie, tspec_ie, tspec_ielen); + retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, + sizeof(struct ieee80211req_res)); + if (retv < 0) { + wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED " + "retv = %d", __func__, retv); + return -1; + } + os_memcpy(tspec_ie, addts->tspecie, tspec_ielen); + return addts->status; +} + + +static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg) +{ + struct atheros_driver_data *drv = priv; + struct ieee80211req_res req; + struct ieee80211req_res_addnode *addnode = &req.u.addnode; + + wpa_printf(MSG_DEBUG, "%s", __func__); + req.type = IEEE80211_RESREQ_ADDNODE; + os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN); + addnode->auth_alg = auth_alg; + return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req, + sizeof(struct ieee80211req_res)); +} + +#endif /* CONFIG_IEEE80211R */ + + +/* Use only to set a big param, get will not work. */ +static int +set80211big(struct atheros_driver_data *drv, int op, const void *data, int len) +{ + struct iwreq iwr; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + + iwr.u.data.pointer = (void *) data; + iwr.u.data.length = len; + iwr.u.data.flags = op; + wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x", + __func__, op, op, athr_get_param_name(op), len); + + if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) { + wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d " + "value=0x%x,0x%x failed: %d (%s)", + __func__, op, athr_get_ioctl_name(op), iwr.u.mode, + iwr.u.mode, iwr.u.data.length, + iwr.u.data.flags, errno, strerror(errno)); + return -1; + } + return 0; +} + + +static int atheros_send_action(void *priv, unsigned int freq, + unsigned int wait, + const u8 *dst, const u8 *src, + const u8 *bssid, + const u8 *data, size_t data_len, int no_cck) +{ + struct atheros_driver_data *drv = priv; + struct ieee80211_p2p_send_action *act; + int res; + + act = os_zalloc(sizeof(*act) + data_len); + if (act == NULL) + return -1; + act->freq = freq; + os_memcpy(act->dst_addr, dst, ETH_ALEN); + os_memcpy(act->src_addr, src, ETH_ALEN); + os_memcpy(act->bssid, bssid, ETH_ALEN); + os_memcpy(act + 1, data, data_len); + wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src=" + MACSTR ", bssid=" MACSTR, + __func__, act->freq, wait, MAC2STR(act->dst_addr), + MAC2STR(act->src_addr), MAC2STR(act->bssid)); + wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act)); + wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len); + + res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION, + act, sizeof(*act) + data_len); + os_free(act); + return res; +} + + +#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) +static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer, + u8 *ie, u16 *len, enum wnm_oper oper) +{ +#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */ + u8 buf[IEEE80211_APPIE_MAX]; + struct ieee80211req_getset_appiebuf *tfs_ie; + u16 val; + + wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR, + drv->iface, oper, MAC2STR(peer)); + + switch (oper) { + case WNM_SLEEP_TFS_REQ_IE_SET: + if (*len > IEEE80211_APPIE_MAX - + sizeof(struct ieee80211req_getset_appiebuf)) { + wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large"); + return -1; + } + tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; + tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; + tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len; + + /* Command header for driver */ + os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); + val = oper; + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); + val = *len; + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); + + /* copy the ie */ + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len); + + if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, + IEEE80211_APPIE_MAX)) { + wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " + "%s", __func__, strerror(errno)); + return -1; + } + break; + case WNM_SLEEP_TFS_RESP_IE_ADD: + tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; + tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; + tfs_ie->app_buflen = IEEE80211_APPIE_MAX - + sizeof(struct ieee80211req_getset_appiebuf); + /* Command header for driver */ + os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); + val = oper; + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); + val = 0; + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); + + if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie, + IEEE80211_APPIE_MAX)) { + wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: " + "%s", __func__, strerror(errno)); + return -1; + } + + *len = tfs_ie->app_buflen; + os_memcpy(ie, &(tfs_ie->app_buf[0]), *len); + wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0], + *len); + break; + case WNM_SLEEP_TFS_RESP_IE_NONE: + *len = 0; + break; + case WNM_SLEEP_TFS_IE_DEL: + tfs_ie = (struct ieee80211req_getset_appiebuf *) buf; + tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM; + tfs_ie->app_buflen = IEEE80211_APPIE_MAX - + sizeof(struct ieee80211req_getset_appiebuf); + /* Command header for driver */ + os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN); + val = oper; + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2); + val = 0; + os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2); + + if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie, + IEEE80211_APPIE_MAX)) { + wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: " + "%s", __func__, strerror(errno)); + return -1; + } + break; + default: + wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper); + break; + } + + return 0; +} + + +static int atheros_wnm_sleep(struct atheros_driver_data *drv, + const u8 *peer, enum wnm_oper oper) +{ + u8 *data, *pos; + size_t dlen; + int ret; + u16 val; + + wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR, + oper, MAC2STR(peer)); + + dlen = ETH_ALEN + 2 + 2; + data = os_malloc(dlen); + if (data == NULL) + return -1; + + /* Command header for driver */ + pos = data; + os_memcpy(pos, peer, ETH_ALEN); + pos += ETH_ALEN; + + val = oper; + os_memcpy(pos, &val, 2); + pos += 2; + + val = 0; + os_memcpy(pos, &val, 2); + + ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM); + + os_free(data); + + return ret; +} + + +static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer, + u8 *buf, u16 *buf_len) +{ + struct atheros_driver_data *drv = priv; + + switch (oper) { + case WNM_SLEEP_ENTER_CONFIRM: + case WNM_SLEEP_ENTER_FAIL: + case WNM_SLEEP_EXIT_CONFIRM: + case WNM_SLEEP_EXIT_FAIL: + return atheros_wnm_sleep(drv, peer, oper); + case WNM_SLEEP_TFS_REQ_IE_SET: + case WNM_SLEEP_TFS_RESP_IE_ADD: + case WNM_SLEEP_TFS_RESP_IE_NONE: + case WNM_SLEEP_TFS_IE_DEL: + return athr_wnm_tfs(drv, peer, buf, buf_len, oper); + default: + wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d", + oper); + return -1; + } +} +#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ + + const struct wpa_driver_ops wpa_driver_atheros_ops = { .name = "atheros", - .hapd_init = madwifi_init, - .hapd_deinit = madwifi_deinit, - .set_ieee8021x = madwifi_set_ieee8021x, - .set_privacy = madwifi_set_privacy, - .set_key = madwifi_set_key, - .get_seqnum = madwifi_get_seqnum, - .flush = madwifi_flush, - .set_generic_elem = madwifi_set_opt_ie, - .sta_set_flags = madwifi_sta_set_flags, - .read_sta_data = madwifi_read_sta_driver_data, - .hapd_send_eapol = madwifi_send_eapol, - .sta_disassoc = madwifi_sta_disassoc, - .sta_deauth = madwifi_sta_deauth, - .hapd_set_ssid = madwifi_set_ssid, - .hapd_get_ssid = madwifi_get_ssid, - .set_countermeasures = madwifi_set_countermeasures, - .sta_clear_stats = madwifi_sta_clear_stats, - .commit = madwifi_commit, - .set_ap_wps_ie = madwifi_set_ap_wps_ie, + .hapd_init = atheros_init, + .hapd_deinit = atheros_deinit, + .set_ieee8021x = atheros_set_ieee8021x, + .set_privacy = atheros_set_privacy, + .set_key = atheros_set_key, + .get_seqnum = atheros_get_seqnum, + .flush = atheros_flush, + .set_generic_elem = atheros_set_opt_ie, + .sta_set_flags = atheros_sta_set_flags, + .read_sta_data = atheros_read_sta_driver_data, + .hapd_send_eapol = atheros_send_eapol, + .sta_disassoc = atheros_sta_disassoc, + .sta_deauth = atheros_sta_deauth, + .hapd_set_ssid = atheros_set_ssid, + .hapd_get_ssid = atheros_get_ssid, + .set_countermeasures = atheros_set_countermeasures, + .sta_clear_stats = atheros_sta_clear_stats, + .commit = atheros_commit, + .set_ap_wps_ie = atheros_set_ap_wps_ie, + .set_authmode = atheros_set_authmode, + .set_ap = atheros_set_ap, +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) + .sta_assoc = atheros_sta_assoc, + .sta_auth = atheros_sta_auth, + .send_mlme = atheros_send_mgmt, +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + .add_tspec = atheros_add_tspec, + .add_sta_node = atheros_add_sta_node, +#endif /* CONFIG_IEEE80211R */ + .send_action = atheros_send_action, +#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM) + .wnm_oper = atheros_wnm_oper, +#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */ + .set_qos_map = atheros_set_qos_map, };