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.
This commit is contained in:
parent
439efd1eac
commit
4378fc14eb
13 changed files with 27 additions and 24 deletions
|
@ -26,7 +26,7 @@
|
||||||
#include "ap_drv_ops.h"
|
#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;
|
int res = 0;
|
||||||
if (flags & WLAN_STA_AUTHORIZED)
|
if (flags & WLAN_STA_AUTHORIZED)
|
||||||
|
|
|
@ -20,6 +20,7 @@ struct wpa_bss_params;
|
||||||
struct wpa_driver_scan_params;
|
struct wpa_driver_scan_params;
|
||||||
struct ieee80211_ht_capabilities;
|
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_ap_wps_ie(struct hostapd_data *hapd);
|
||||||
int hostapd_set_authorized(struct hostapd_data *hapd,
|
int hostapd_set_authorized(struct hostapd_data *hapd,
|
||||||
struct sta_info *sta, int authorized);
|
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,
|
static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
|
||||||
const u8 *addr, const u8 *data,
|
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)
|
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
|
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
|
||||||
data_len, encrypt,
|
data_len, encrypt,
|
||||||
hapd->own_addr);
|
hapd->own_addr, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int hostapd_drv_read_sta_data(
|
static inline int hostapd_drv_read_sta_data(
|
||||||
|
|
|
@ -73,7 +73,7 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
rsn_preauth_send(hapd, sta, buf, len);
|
rsn_preauth_send(hapd, sta, buf, len);
|
||||||
} else {
|
} else {
|
||||||
hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len,
|
hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len,
|
||||||
encrypt);
|
encrypt, sta->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
os_free(buf);
|
os_free(buf);
|
||||||
|
|
|
@ -243,8 +243,15 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
|
||||||
int encrypt)
|
int encrypt)
|
||||||
{
|
{
|
||||||
struct hostapd_data *hapd = ctx;
|
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,
|
return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
|
||||||
encrypt);
|
encrypt, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1406,12 +1406,13 @@ struct wpa_driver_ops {
|
||||||
* @data_len: Length of the EAPOL packet in octets
|
* @data_len: Length of the EAPOL packet in octets
|
||||||
* @encrypt: Whether the frame should be encrypted
|
* @encrypt: Whether the frame should be encrypted
|
||||||
* @own_addr: Source MAC address
|
* @own_addr: Source MAC address
|
||||||
|
* @flags: WPA_STA_* flags for the destination station
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -1 on failure
|
* Returns: 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
|
int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
|
||||||
size_t data_len, int encrypt,
|
size_t data_len, int encrypt,
|
||||||
const u8 *own_addr);
|
const u8 *own_addr, u32 flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sta_deauth - Deauthenticate a station (AP only)
|
* sta_deauth - Deauthenticate a station (AP only)
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ atheros_wireless_event_init(struct atheros_driver_data *drv)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
|
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;
|
struct atheros_driver_data *drv = priv;
|
||||||
unsigned char buf[3000];
|
unsigned char buf[3000];
|
||||||
|
|
|
@ -516,7 +516,7 @@ no_ie:
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
|
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;
|
struct bsd_driver_data *drv = priv;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
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 hostap_driver_data *drv = priv;
|
||||||
struct ieee80211_hdr *hdr;
|
struct ieee80211_hdr *hdr;
|
||||||
|
|
|
@ -1067,7 +1067,7 @@ madwifi_wireless_event_init(struct madwifi_driver_data *drv)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
|
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;
|
struct madwifi_driver_data *drv = priv;
|
||||||
unsigned char buf[3000];
|
unsigned char buf[3000];
|
||||||
|
|
|
@ -4240,7 +4240,7 @@ static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
static int wpa_driver_nl80211_hapd_send_eapol(
|
static int wpa_driver_nl80211_hapd_send_eapol(
|
||||||
void *priv, const u8 *addr, const u8 *data,
|
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 i802_bss *bss = priv;
|
||||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
|
@ -4248,11 +4248,7 @@ static int wpa_driver_nl80211_hapd_send_eapol(
|
||||||
size_t len;
|
size_t len;
|
||||||
u8 *pos;
|
u8 *pos;
|
||||||
int res;
|
int res;
|
||||||
#if 0 /* FIX */
|
int qos = flags & WPA_STA_WMM;
|
||||||
int qos = sta->flags & WPA_STA_WMM;
|
|
||||||
#else
|
|
||||||
int qos = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
|
len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
|
||||||
data_len;
|
data_len;
|
||||||
|
@ -4268,26 +4264,22 @@ static int wpa_driver_nl80211_hapd_send_eapol(
|
||||||
hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
|
hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
|
||||||
if (encrypt)
|
if (encrypt)
|
||||||
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
|
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
|
||||||
#if 0 /* To be enabled if qos determination is added above */
|
|
||||||
if (qos) {
|
if (qos) {
|
||||||
hdr->frame_control |=
|
hdr->frame_control |=
|
||||||
host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
|
host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
|
memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
|
||||||
memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
|
memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
|
||||||
memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
|
memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
|
||||||
pos = (u8 *) (hdr + 1);
|
pos = (u8 *) (hdr + 1);
|
||||||
|
|
||||||
#if 0 /* To be enabled if qos determination is added above */
|
|
||||||
if (qos) {
|
if (qos) {
|
||||||
/* add an empty QoS header if needed */
|
/* add an empty QoS header if needed */
|
||||||
pos[0] = 0;
|
pos[0] = 0;
|
||||||
pos[1] = 0;
|
pos[1] = 0;
|
||||||
pos += 2;
|
pos += 2;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
|
memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
|
||||||
pos += sizeof(rfc1042_header);
|
pos += sizeof(rfc1042_header);
|
||||||
|
|
|
@ -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,
|
static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
|
||||||
size_t data_len, int encrypt,
|
size_t data_len, int encrypt,
|
||||||
const u8 *own_addr)
|
const u8 *own_addr, u32 flags)
|
||||||
{
|
{
|
||||||
struct test_driver_bss *dbss = priv;
|
struct test_driver_bss *dbss = priv;
|
||||||
struct wpa_driver_test_data *drv = dbss->drv;
|
struct wpa_driver_test_data *drv = dbss->drv;
|
||||||
|
|
|
@ -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,
|
static int wired_send_eapol(void *priv, const u8 *addr,
|
||||||
const u8 *data, size_t data_len, int encrypt,
|
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 wpa_driver_wired_data *drv = priv;
|
||||||
struct ieee8023_hdr *hdr;
|
struct ieee8023_hdr *hdr;
|
||||||
|
|
|
@ -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,
|
static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *addr, const u8 *data,
|
const u8 *addr, const u8 *data,
|
||||||
size_t data_len, int encrypt,
|
size_t data_len, int encrypt,
|
||||||
const u8 *own_addr)
|
const u8 *own_addr, u32 flags)
|
||||||
{
|
{
|
||||||
if (wpa_s->driver->hapd_send_eapol)
|
if (wpa_s->driver->hapd_send_eapol)
|
||||||
return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr,
|
return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr,
|
||||||
data, data_len, encrypt,
|
data, data_len, encrypt,
|
||||||
own_addr);
|
own_addr, flags);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue