wl12xx: AP-mode - fix race condition on sta connection
If a sta starts transmitting immediately after authentication, sometimes the FW deauthenticates it. Fix this by marking the sta "in-connection" in FW before sending the autentication response. The "in-connection" entry is automatically removed when connection succeeds or after a timeout. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
This commit is contained in:
parent
f4d08ddd3e
commit
99a2775d02
3 changed files with 53 additions and 0 deletions
|
@ -1541,3 +1541,28 @@ out:
|
||||||
kfree(config_ps);
|
kfree(config_ps);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
|
||||||
|
{
|
||||||
|
struct wl1271_acx_inconnection_sta *acx = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr);
|
||||||
|
|
||||||
|
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||||
|
if (!acx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(acx->addr, addr, ETH_ALEN);
|
||||||
|
|
||||||
|
ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST,
|
||||||
|
acx, sizeof(*acx));
|
||||||
|
if (ret < 0) {
|
||||||
|
wl1271_warning("acx set inconnaction sta failed: %d", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(acx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps {
|
||||||
__le32 null_data_rate;
|
__le32 null_data_rate;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct wl1271_acx_inconnection_sta {
|
||||||
|
struct acx_header header;
|
||||||
|
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
u8 padding1[2];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ACX_WAKE_UP_CONDITIONS = 0x0002,
|
ACX_WAKE_UP_CONDITIONS = 0x0002,
|
||||||
ACX_MEM_CFG = 0x0003,
|
ACX_MEM_CFG = 0x0003,
|
||||||
|
@ -1215,6 +1222,7 @@ enum {
|
||||||
ACX_GEN_FW_CMD = 0x0070,
|
ACX_GEN_FW_CMD = 0x0070,
|
||||||
ACX_HOST_IF_CFG_BITMAP = 0x0071,
|
ACX_HOST_IF_CFG_BITMAP = 0x0071,
|
||||||
ACX_MAX_TX_FAILURE = 0x0072,
|
ACX_MAX_TX_FAILURE = 0x0072,
|
||||||
|
ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
|
||||||
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
|
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
|
||||||
DOT11_CUR_TX_PWR = 0x100D,
|
DOT11_CUR_TX_PWR = 0x100D,
|
||||||
DOT11_RX_DOT11_MODE = 0x1012,
|
DOT11_RX_DOT11_MODE = 0x1012,
|
||||||
|
@ -1290,5 +1298,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
|
||||||
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
|
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
|
||||||
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
|
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
|
||||||
int wl1271_acx_config_ps(struct wl1271 *wl);
|
int wl1271_acx_config_ps(struct wl1271 *wl);
|
||||||
|
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
|
||||||
|
|
||||||
#endif /* __WL1271_ACX_H__ */
|
#endif /* __WL1271_ACX_H__ */
|
||||||
|
|
|
@ -70,6 +70,22 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct ieee80211_hdr *hdr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add the station to the known list before transmitting the
|
||||||
|
* authentication response. this way it won't get de-authed by FW
|
||||||
|
* when transmitting too soon.
|
||||||
|
*/
|
||||||
|
hdr = (struct ieee80211_hdr *)(skb->data +
|
||||||
|
sizeof(struct wl1271_tx_hw_descr));
|
||||||
|
if (ieee80211_is_auth(hdr->frame_control))
|
||||||
|
wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
|
||||||
|
}
|
||||||
|
|
||||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||||
u32 buf_offset)
|
u32 buf_offset)
|
||||||
{
|
{
|
||||||
|
@ -238,6 +254,9 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (wl->bss_type == BSS_TYPE_AP_BSS)
|
||||||
|
wl1271_tx_ap_update_inconnection_sta(wl, skb);
|
||||||
|
|
||||||
wl1271_tx_fill_hdr(wl, skb, extra, info);
|
wl1271_tx_fill_hdr(wl, skb, extra, info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Reference in a new issue