wl12xx: AP-mode - fix race condition on sta connection
authorArik Nemtsov <arik@wizery.com>
Tue, 22 Feb 2011 22:22:25 +0000 (00:22 +0200)
committerLuciano Coelho <coelho@ti.com>
Wed, 23 Feb 2011 09:14:55 +0000 (11:14 +0200)
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>
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/tx.c

index 6d53129..3badc6b 100644 (file)
@@ -1541,3 +1541,28 @@ out:
        kfree(config_ps);
        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;
+}
index 4e301de..dd19b01 100644 (file)
@@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps {
        __le32 null_data_rate;
 } __packed;
 
+struct wl1271_acx_inconnection_sta {
+       struct acx_header header;
+
+       u8 addr[ETH_ALEN];
+       u8 padding1[2];
+} __packed;
+
 enum {
        ACX_WAKE_UP_CONDITIONS      = 0x0002,
        ACX_MEM_CFG                 = 0x0003,
@@ -1215,6 +1222,7 @@ enum {
        ACX_GEN_FW_CMD              = 0x0070,
        ACX_HOST_IF_CFG_BITMAP      = 0x0071,
        ACX_MAX_TX_FAILURE          = 0x0072,
+       ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
        DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
        DOT11_CUR_TX_PWR            = 0x100D,
        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_max_tx_retry(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__ */
index 94ff3fa..0bb57da 100644 (file)
@@ -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,
                                u32 buf_offset)
 {
@@ -238,6 +254,9 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
        if (ret < 0)
                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);
 
        /*