aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-02-22 17:22:25 -0500
committerLuciano Coelho <coelho@ti.com>2011-02-23 04:14:55 -0500
commit99a2775d02a7accf4cc661a65c76fd7b379d1c7a (patch)
treefb2031356dca5064540e467293e6dc6aa9d803bb /drivers/net
parentf4d08ddd3e60c79a141be36a5f3a7294c619291d (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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/wl12xx/acx.c25
-rw-r--r--drivers/net/wireless/wl12xx/acx.h9
-rw-r--r--drivers/net/wireless/wl12xx/tx.c19
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
1545int 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
1565out:
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
1158struct wl1271_acx_inconnection_sta {
1159 struct acx_header header;
1160
1161 u8 addr[ETH_ALEN];
1162 u8 padding1[2];
1163} __packed;
1164
1158enum { 1165enum {
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,
1290int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); 1298int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
1291int wl1271_acx_max_tx_retry(struct wl1271 *wl); 1299int wl1271_acx_max_tx_retry(struct wl1271 *wl);
1292int wl1271_acx_config_ps(struct wl1271 *wl); 1300int wl1271_acx_config_ps(struct wl1271 *wl);
1301int 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
73static 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
73static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, 89static 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 /*