diff options
Diffstat (limited to 'src/drivers/driver_atheros.c')
-rw-r--r-- | src/drivers/driver_atheros.c | 1162 |
1 files changed, 1010 insertions, 152 deletions
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 5c25f00b16431..c2f59344af5ab 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -5,14 +5,8 @@ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> * 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 <sys/ioctl.h> #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 <netpacket/packet.h> +#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" @@ -56,7 +56,7 @@ #include "linux_ioctl.h" -struct madwifi_driver_data { +struct atheros_driver_data { struct hostapd_data *hapd; /* back pointer */ char iface[IFNAMSIZ + 1]; @@ -70,11 +70,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 +129,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 +175,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; @@ -218,7 +214,7 @@ 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; @@ -255,7 +251,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; @@ -320,8 +316,15 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv, 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); return -1; @@ -336,9 +339,9 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv, } 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,14 +351,14 @@ 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!"); return -1; } - if (params->wpa && madwifi_configure_wpa(drv, params) != 0) { + if (params->wpa && atheros_configure_wpa(drv, params) != 0) { hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); return -1; @@ -371,9 +374,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 +384,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; @@ -406,21 +409,21 @@ madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) } static int -madwifi_sta_set_flags(void *priv, const u8 *addr, +atheros_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, 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; @@ -446,17 +449,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,6 +474,11 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, case WPA_ALG_CCMP: cipher = IEEE80211_CIPHER_AES_CCM; break; +#ifdef CONFIG_IEEE80211W + case WPA_ALG_IGTK: + cipher = IEEE80211_CIPHER_AES_CMAC; + break; +#endif /* CONFIG_IEEE80211W */ default: printf("%s: unknown/unsupported algorithm %d\n", __func__, alg); @@ -486,10 +494,11 @@ madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, memset(&wk, 0, sizeof(wk)); wk.ik_type = cipher; wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; - if (addr == NULL) { + if (addr == NULL || is_broadcast_ether_addr(addr)) { 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); wk.ik_keyix = IEEE80211_KEYIX_NONE; @@ -510,10 +519,10 @@ 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", @@ -557,20 +566,20 @@ madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, 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, + 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)); @@ -602,9 +611,9 @@ 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; @@ -624,20 +633,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; @@ -658,10 +708,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; @@ -682,10 +732,10 @@ madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, } #ifdef CONFIG_WPS -static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) +static void atheros_raw_recv_wps(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; @@ -703,6 +753,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, 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 = mgmt->u.probe_req.variable; event.rx_probe_req.ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); @@ -710,67 +762,379 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, } #endif /* CONFIG_WPS */ -static int madwifi_receive_probe_req(struct madwifi_driver_data *drv) +#ifdef CONFIG_IEEE80211R +static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) +{ + struct atheros_driver_data *drv = ctx; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt; + u16 fc; + u16 stype; + int ielen; + const u8 *iebuf; + + /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */ + 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) + return; + stype = WLAN_FC_GET_STYPE(fc); + + wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, + (int) len); + + if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", + __func__); + return; + } + 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_ACTION: + if (&mgmt->u.action.category > buf + len) + break; + os_memset(&event, 0, sizeof(event)); + event.rx_action.da = mgmt->da; + event.rx_action.sa = mgmt->sa; + event.rx_action.bssid = mgmt->bssid; + event.rx_action.category = mgmt->u.action.category; + event.rx_action.data = &mgmt->u.action.category; + event.rx_action.len = buf + len - event.rx_action.data; + wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event); + 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_IEEE80211R */ + +#ifdef CONFIG_HS20 +static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) +{ + struct atheros_driver_data *drv = ctx; + const struct ieee80211_mgmt *mgmt; + u16 fc; + union wpa_event_data event; + + /* Send the Action frame for HS20 processing */ + + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) + + sizeof(mgmt->u.action.u.public_action)) + 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_ACTION || + mgmt->u.action.category != WLAN_ACTION_PUBLIC) + return; + + wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__); + + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = (const u8 *) mgmt; + event.rx_mgmt.frame_len = len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); +} +#endif /* CONFIG_HS20 */ + +#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R) +static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) +{ + struct atheros_driver_data *drv = ctx; + union wpa_event_data event; + const struct ieee80211_mgmt *mgmt; + u16 fc; + u16 stype; + + /* Do 11R processing for WNM ACTION frames */ + 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) + return; + stype = WLAN_FC_GET_STYPE(fc); + + wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype, + (int) len); + + if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", + __func__); + return; + } + + switch (stype) { + case WLAN_FC_STYPE_ACTION: + if (&mgmt->u.action.category > buf + len) + break; + os_memset(&event, 0, sizeof(event)); + event.rx_action.da = mgmt->da; + event.rx_action.sa = mgmt->sa; + event.rx_action.bssid = mgmt->bssid; + event.rx_action.category = mgmt->u.action.category; + event.rx_action.data = &mgmt->u.action.category; + event.rx_action.len = buf + len - event.rx_action.data; + wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event); + break; + default: + break; + } +} +#endif /* CONFIG_WNM */ + +#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) +static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) { - int ret = 0; #ifdef CONFIG_WPS + atheros_raw_recv_wps(ctx, src_addr, buf, len); +#endif /* CONFIG_WPS */ +#ifdef CONFIG_IEEE80211R + atheros_raw_recv_11r(ctx, src_addr, buf, len); +#endif /* CONFIG_IEEE80211R */ +#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R) + atheros_raw_recv_11v(ctx, src_addr, buf, len); +#endif /* CONFIG_WNM */ +#ifdef CONFIG_HS20 + atheros_raw_recv_hs20(ctx, src_addr, buf, len); +#endif /* CONFIG_HS20 */ +} +#endif /* CONFIG_WPS || CONFIG_IEEE80211R */ + +static int atheros_receive_pkt(struct atheros_driver_data *drv) +{ + int ret = 0; 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 */ +#ifdef CONFIG_IEEE80211R + filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | + IEEE80211_FILTER_TYPE_AUTH | + IEEE80211_FILTER_TYPE_ACTION); +#endif +#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[256]; + 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, - const struct wpabuf *proberesp) +atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp, + const struct wpabuf *assocresp) { - if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : 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 (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 */ +#ifdef CONFIG_IEEE80211R +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 */ + 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; @@ -791,17 +1155,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, "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) @@ -809,13 +1177,23 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) } ielen = iebuf[1]; + +#ifdef ATH_WPS_IE + /* if WPS IE is present, preference is given to WPS */ + if (ie.wps_ie && + (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) { + iebuf = ie.wps_ie; + ielen = ie.wps_ie[1]; + } +#endif /* ATH_WPS_IE */ + if (ielen == 0) iebuf = NULL; else 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) { /* Cached accounting data is not valid anymore. */ @@ -825,7 +1203,7 @@ no_ie: } 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) { wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); @@ -883,6 +1261,9 @@ madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, * so all are enabled for WPS... ugh. */ wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); +#endif /* CONFIG_WPS */ +#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) +#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { /* * Atheros driver uses a hack to pass Probe Request frames as a @@ -890,21 +1271,139 @@ madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, * packet sniffing) didn't work when bridging. * Format: "Manage.prob_req <frame len>" | 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 || custom + MGMT_FRAM_TAG_SIZE + len > end) { 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); -#endif /* CONFIG_WPS */ + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); + } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) { + /* Format: "Manage.assoc_req <frame len>" | zero padding | + * frame */ + int len = atoi(custom + 17); + if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { + wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" + "assoc_req/auth event length %d", len); + return; + } + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); + } else if (strncmp(custom, "Manage.action ", 14) == 0) { + /* Format: "Manage.assoc_req <frame len>" | zero padding | + * frame */ + int len = atoi(custom + 14); + if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { + wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" + "assoc_req/auth event length %d", len); + return; + } + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); + } else if (strncmp(custom, "Manage.auth ", 12) == 0) { + /* Format: "Manage.auth <frame len>" | zero padding | frame + */ + int len = atoi(custom + 12); + if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { + wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" + "assoc_req/auth event length %d", len); + return; + } + atheros_raw_receive(drv, NULL, + (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); +#endif /* CONFIG_WPS or CONFIG_IEEE80211R */ + } +} + +/* +* 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_strncpy(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 +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 -madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, +atheros_wireless_event_wireless(struct atheros_driver_data *drv, char *data, int len) { struct iw_event iwe_buf, *iwe = &iwe_buf; @@ -943,7 +1442,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 @@ -958,8 +1457,15 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, return; /* XXX */ 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); + + 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); + } free(buf); break; } @@ -970,10 +1476,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; @@ -986,7 +1492,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); } @@ -996,7 +1502,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; @@ -1036,23 +1542,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); @@ -1064,10 +1570,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; @@ -1107,22 +1613,22 @@ madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, 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"); + printf("Could not allocate memory for atheros driver data\n"); return NULL; } @@ -1148,6 +1654,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]); @@ -1179,15 +1686,19 @@ madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) /* 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) @@ -1201,10 +1712,11 @@ bad: 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); netlink_deinit(drv->netlink); (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); if (drv->ioctl_sock >= 0) @@ -1215,13 +1727,16 @@ madwifi_deinit(void *priv) l2_packet_deinit(drv->sock_xmit); if (drv->sock_raw) l2_packet_deinit(drv->sock_raw); + wpabuf_free(drv->wpa_ie); + wpabuf_free(drv->wps_beacon_ie); + wpabuf_free(drv->wps_probe_resp_ie); 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)); @@ -1239,16 +1754,17 @@ madwifi_set_ssid(void *priv, const u8 *buf, int len) } 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_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]"); @@ -1260,39 +1776,381 @@ 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); + + return 0; +} + + +#ifdef CONFIG_IEEE80211R + +static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, + int noack) +{ + 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; + 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); +} + + +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; +} + + +#ifdef CONFIG_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 */ + + 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, +#ifdef CONFIG_IEEE80211R + .sta_assoc = atheros_sta_assoc, + .sta_auth = atheros_sta_auth, + .send_mlme = atheros_send_mgmt, + .add_tspec = atheros_add_tspec, + .add_sta_node = atheros_add_sta_node, +#endif /* CONFIG_IEEE80211R */ + .send_action = atheros_send_action, +#ifdef CONFIG_WNM + .wnm_oper = atheros_wnm_oper, +#endif /* CONFIG_WNM */ }; |