diff options
author | Arik Nemtsov <arik@wizery.com> | 2011-02-22 17:22:25 -0500 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2011-02-23 04:14:55 -0500 |
commit | 99a2775d02a7accf4cc661a65c76fd7b379d1c7a (patch) | |
tree | fb2031356dca5064540e467293e6dc6aa9d803bb | |
parent | f4d08ddd3e60c79a141be36a5f3a7294c619291d (diff) |
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>
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 19 |
3 files changed, 53 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 6d5312990f79..3badc6bb7866 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c | |||
@@ -1541,3 +1541,28 @@ out: | |||
1541 | kfree(config_ps); | 1541 | kfree(config_ps); |
1542 | return ret; | 1542 | return ret; |
1543 | } | 1543 | } |
1544 | |||
1545 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) | ||
1546 | { | ||
1547 | struct wl1271_acx_inconnection_sta *acx = NULL; | ||
1548 | int ret; | ||
1549 | |||
1550 | wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); | ||
1551 | |||
1552 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1553 | if (!acx) | ||
1554 | return -ENOMEM; | ||
1555 | |||
1556 | memcpy(acx->addr, addr, ETH_ALEN); | ||
1557 | |||
1558 | ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, | ||
1559 | acx, sizeof(*acx)); | ||
1560 | if (ret < 0) { | ||
1561 | wl1271_warning("acx set inconnaction sta failed: %d", ret); | ||
1562 | goto out; | ||
1563 | } | ||
1564 | |||
1565 | out: | ||
1566 | kfree(acx); | ||
1567 | return ret; | ||
1568 | } | ||
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 4e301de916bb..dd19b01d807b 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h | |||
@@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps { | |||
1155 | __le32 null_data_rate; | 1155 | __le32 null_data_rate; |
1156 | } __packed; | 1156 | } __packed; |
1157 | 1157 | ||
1158 | struct wl1271_acx_inconnection_sta { | ||
1159 | struct acx_header header; | ||
1160 | |||
1161 | u8 addr[ETH_ALEN]; | ||
1162 | u8 padding1[2]; | ||
1163 | } __packed; | ||
1164 | |||
1158 | enum { | 1165 | enum { |
1159 | ACX_WAKE_UP_CONDITIONS = 0x0002, | 1166 | ACX_WAKE_UP_CONDITIONS = 0x0002, |
1160 | ACX_MEM_CFG = 0x0003, | 1167 | ACX_MEM_CFG = 0x0003, |
@@ -1215,6 +1222,7 @@ enum { | |||
1215 | ACX_GEN_FW_CMD = 0x0070, | 1222 | ACX_GEN_FW_CMD = 0x0070, |
1216 | ACX_HOST_IF_CFG_BITMAP = 0x0071, | 1223 | ACX_HOST_IF_CFG_BITMAP = 0x0071, |
1217 | ACX_MAX_TX_FAILURE = 0x0072, | 1224 | ACX_MAX_TX_FAILURE = 0x0072, |
1225 | ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073, | ||
1218 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | 1226 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, |
1219 | DOT11_CUR_TX_PWR = 0x100D, | 1227 | DOT11_CUR_TX_PWR = 0x100D, |
1220 | DOT11_RX_DOT11_MODE = 0x1012, | 1228 | DOT11_RX_DOT11_MODE = 0x1012, |
@@ -1290,5 +1298,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, | |||
1290 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); | 1298 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); |
1291 | int wl1271_acx_max_tx_retry(struct wl1271 *wl); | 1299 | int wl1271_acx_max_tx_retry(struct wl1271 *wl); |
1292 | int wl1271_acx_config_ps(struct wl1271 *wl); | 1300 | int wl1271_acx_config_ps(struct wl1271 *wl); |
1301 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); | ||
1293 | 1302 | ||
1294 | #endif /* __WL1271_ACX_H__ */ | 1303 | #endif /* __WL1271_ACX_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 94ff3faf7dde..0bb57daac889 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c | |||
@@ -70,6 +70,22 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, | ||
74 | struct sk_buff *skb) | ||
75 | { | ||
76 | struct ieee80211_hdr *hdr; | ||
77 | |||
78 | /* | ||
79 | * add the station to the known list before transmitting the | ||
80 | * authentication response. this way it won't get de-authed by FW | ||
81 | * when transmitting too soon. | ||
82 | */ | ||
83 | hdr = (struct ieee80211_hdr *)(skb->data + | ||
84 | sizeof(struct wl1271_tx_hw_descr)); | ||
85 | if (ieee80211_is_auth(hdr->frame_control)) | ||
86 | wl1271_acx_set_inconnection_sta(wl, hdr->addr1); | ||
87 | } | ||
88 | |||
73 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | 89 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, |
74 | u32 buf_offset) | 90 | u32 buf_offset) |
75 | { | 91 | { |
@@ -238,6 +254,9 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, | |||
238 | if (ret < 0) | 254 | if (ret < 0) |
239 | return ret; | 255 | return ret; |
240 | 256 | ||
257 | if (wl->bss_type == BSS_TYPE_AP_BSS) | ||
258 | wl1271_tx_ap_update_inconnection_sta(wl, skb); | ||
259 | |||
241 | wl1271_tx_fill_hdr(wl, skb, extra, info); | 260 | wl1271_tx_fill_hdr(wl, skb, extra, info); |
242 | 261 | ||
243 | /* | 262 | /* |