From 4378fc14ebfb355705e7674bf347ea659bcd77bc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 2 Apr 2011 22:03:05 +0300 Subject: [PATCH] nl80211: Send EAPOL frames as QoS data frames for QoS aware clients This should fix EAPOL reauthentication and rekeying timeout issues with Intel clients when using WMM (e.g., with IEEE 802.11n). These stations do not seem to be able to handle EAPOL data frames as non-QoS Data frames after the initial setup. This adds STA flags to hapd_send_eapol() driver op to allow driver_nl80211.c to mark the EAPOL frames as QoS Data frame when injecting it through the monitor interface. --- src/ap/ap_drv_ops.c | 2 +- src/ap/ap_drv_ops.h | 6 ++++-- src/ap/ieee802_1x.c | 2 +- src/ap/wpa_auth_glue.c | 9 ++++++++- src/drivers/driver.h | 3 ++- src/drivers/driver_atheros.c | 2 +- src/drivers/driver_bsd.c | 2 +- src/drivers/driver_hostap.c | 3 ++- src/drivers/driver_madwifi.c | 2 +- src/drivers/driver_nl80211.c | 12 ++---------- src/drivers/driver_test.c | 2 +- src/drivers/driver_wired.c | 2 +- wpa_supplicant/driver_i.h | 4 ++-- 13 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 5017cbf2e..2ff3a6809 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -26,7 +26,7 @@ #include "ap_drv_ops.h" -static int hostapd_sta_flags_to_drv(int flags) +u32 hostapd_sta_flags_to_drv(u32 flags) { int res = 0; if (flags & WLAN_STA_AUTHORIZED) diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 3af9ecaa6..36bb826db 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -20,6 +20,7 @@ struct wpa_bss_params; struct wpa_driver_scan_params; struct ieee80211_ht_capabilities; +u32 hostapd_sta_flags_to_drv(u32 flags); int hostapd_set_ap_wps_ie(struct hostapd_data *hapd); int hostapd_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); @@ -135,13 +136,14 @@ static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd, static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data, - size_t data_len, int encrypt) + size_t data_len, int encrypt, + u32 flags) { if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL) return 0; return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data, data_len, encrypt, - hapd->own_addr); + hapd->own_addr, flags); } static inline int hostapd_drv_read_sta_data( diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 676a3e15c..28e08b9ae 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -73,7 +73,7 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, rsn_preauth_send(hapd, sta, buf, len); } else { hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len, - encrypt); + encrypt, sta->flags); } os_free(buf); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index f7999b9f0..b35b7ba5e 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -243,8 +243,15 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, int encrypt) { struct hostapd_data *hapd = ctx; + struct sta_info *sta; + u32 flags = 0; + + sta = ap_get_sta(hapd, addr); + if (sta) + flags = hostapd_sta_flags_to_drv(sta->flags); + return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, - encrypt); + encrypt, flags); } diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 2836224a3..8e19da14a 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1406,12 +1406,13 @@ struct wpa_driver_ops { * @data_len: Length of the EAPOL packet in octets * @encrypt: Whether the frame should be encrypted * @own_addr: Source MAC address + * @flags: WPA_STA_* flags for the destination station * * Returns: 0 on success, -1 on failure */ int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr); + const u8 *own_addr, u32 flags); /** * sta_deauth - Deauthenticate a station (AP only) diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 56eac5bb7..8f24798a3 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -1132,7 +1132,7 @@ atheros_wireless_event_init(struct atheros_driver_data *drv) static int atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr) + int encrypt, const u8 *own_addr, u32 flags) { struct atheros_driver_data *drv = priv; unsigned char buf[3000]; diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index b91f5111d..5348d0974 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -516,7 +516,7 @@ no_ie: static int bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr) + int encrypt, const u8 *own_addr, u32 flags) { struct bsd_driver_data *drv = priv; diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c index 4fe617830..e855c1bf6 100644 --- a/src/drivers/driver_hostap.c +++ b/src/drivers/driver_hostap.c @@ -289,7 +289,8 @@ static int hostap_send_mlme(void *priv, const u8 *msg, size_t len) static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr) + size_t data_len, int encrypt, const u8 *own_addr, + u32 flags) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr; diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c index b485d38c2..630fbf4c5 100644 --- a/src/drivers/driver_madwifi.c +++ b/src/drivers/driver_madwifi.c @@ -1067,7 +1067,7 @@ 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) + int encrypt, const u8 *own_addr, u32 flags) { struct madwifi_driver_data *drv = priv; unsigned char buf[3000]; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 59d44a1da..87fb4e28c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4240,7 +4240,7 @@ static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; static int wpa_driver_nl80211_hapd_send_eapol( void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr) + size_t data_len, int encrypt, const u8 *own_addr, u32 flags) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -4248,11 +4248,7 @@ static int wpa_driver_nl80211_hapd_send_eapol( size_t len; u8 *pos; int res; -#if 0 /* FIX */ - int qos = sta->flags & WPA_STA_WMM; -#else - int qos = 0; -#endif + int qos = flags & WPA_STA_WMM; len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + data_len; @@ -4268,26 +4264,22 @@ static int wpa_driver_nl80211_hapd_send_eapol( hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); if (encrypt) hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); -#if 0 /* To be enabled if qos determination is added above */ if (qos) { hdr->frame_control |= host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); } -#endif memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); pos = (u8 *) (hdr + 1); -#if 0 /* To be enabled if qos determination is added above */ if (qos) { /* add an empty QoS header if needed */ pos[0] = 0; pos[1] = 0; pos += 2; } -#endif memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); pos += sizeof(rfc1042_header); diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 2aecef53f..9e502e4fc 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -175,7 +175,7 @@ test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from, static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr) + const u8 *own_addr, u32 flags) { struct test_driver_bss *dbss = priv; struct wpa_driver_test_data *drv = dbss->drv; diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c index de038e28f..618db2648 100644 --- a/src/drivers/driver_wired.c +++ b/src/drivers/driver_wired.c @@ -314,7 +314,7 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) static int wired_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr) + const u8 *own_addr, u32 flags) { struct wpa_driver_wired_data *drv = priv; struct ieee8023_hdr *hdr; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 693491b97..0d436dd1f 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -351,12 +351,12 @@ static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s, static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr) + const u8 *own_addr, u32 flags) { if (wpa_s->driver->hapd_send_eapol) return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr, data, data_len, encrypt, - own_addr); + own_addr, flags); return -1; }