nl80211: Send EAPOL frames as QoS data frames for QoS aware clients
authorFelix Fietkau <nbd@openwrt.org>
Sat, 2 Apr 2011 19:03:05 +0000 (22:03 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 2 Apr 2011 19:03:05 +0000 (22:03 +0300)
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.

13 files changed:
src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/ieee802_1x.c
src/ap/wpa_auth_glue.c
src/drivers/driver.h
src/drivers/driver_atheros.c
src/drivers/driver_bsd.c
src/drivers/driver_hostap.c
src/drivers/driver_madwifi.c
src/drivers/driver_nl80211.c
src/drivers/driver_test.c
src/drivers/driver_wired.c
wpa_supplicant/driver_i.h

index 5017cbf..2ff3a68 100644 (file)
@@ -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)
index 3af9eca..36bb826 100644 (file)
@@ -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(
index 676a3e1..28e08b9 100644 (file)
@@ -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);
index f7999b9..b35b7ba 100644 (file)
@@ -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);
 }
 
 
index 2836224..8e19da1 100644 (file)
@@ -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)
index 56eac5b..8f24798 100644 (file)
@@ -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];
index b91f511..5348d09 100644 (file)
@@ -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;
 
index 4fe6178..e855c1b 100644 (file)
@@ -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;
index b485d38..630fbf4 100644 (file)
@@ -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];
index 59d44a1..87fb4e2 100644 (file)
@@ -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);
index 2aecef5..9e502e4 100644 (file)
@@ -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;
index de038e2..618db26 100644 (file)
@@ -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;
index 693491b..0d436dd 100644 (file)
@@ -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;
 }