wcn36xx: Use correct SSN for ADD BA request
authorLoic Poulain <loic.poulain@linaro.org>
Mon, 22 Nov 2021 18:04:11 +0000 (19:04 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 26 Nov 2021 10:19:28 +0000 (12:19 +0200)
Since firmware uses its own sequence number counters, we need to
use firmware number as well when mac80211 generates the ADD_BA
request packet. Indeed the firmware sequence counters tend to
slightly drift from the mac80211 ones because of firmware offload
features like ARP responses. This causes the starting sequence
number field of the ADD_BA request to be unaligned, and can possibly
cause issues with strict/picky APs.

To fix this, we retrieve the current firmware sequence number for
a given TID through the smd_trigger_ba API, and use that number as
replacement of the mac80211 starting sequence number.

This change also ensures that any issue in the smd *ba procedures
will cause the ba action to properly fail, and remove useless call
to smd_trigger_ba() from IEEE80211_AMPDU_RX_START.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1637604251-11763-1-git-send-email-loic.poulain@linaro.org
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/smd.h

index 0110f5062296a0208b1d42bd12bb9165001a514c..4074398eafef2d38592ffa35689a621394092ff4 100644 (file)
@@ -1220,7 +1220,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
        u16 tid = params->tid;
        u16 *ssn = &params->ssn;
        int ret = 0;
-       u8 session;
+       int session;
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
                    action, tid);
@@ -1232,9 +1232,11 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                sta_priv->tid = tid;
                session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
                                                     get_sta_index(vif, sta_priv));
+               if (session < 0) {
+                       ret = session;
+                       goto out;
+               }
                wcn36xx_smd_add_ba(wcn, session);
-               wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid,
-                                      session);
                break;
        case IEEE80211_AMPDU_RX_STOP:
                wcn36xx_smd_del_ba(wcn, tid, 0, get_sta_index(vif, sta_priv));
@@ -1244,6 +1246,18 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
                spin_unlock_bh(&sta_priv->ampdu_lock);
 
+               /* Replace the mac80211 ssn with the firmware one */
+               wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu ssn = %u\n", *ssn);
+               wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, ssn);
+               wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu fw-ssn = %u\n", *ssn);
+
+               /* Start BA session */
+               session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
+                                                    get_sta_index(vif, sta_priv));
+               if (session < 0) {
+                       ret = session;
+                       goto out;
+               }
                ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -1251,8 +1265,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
                spin_unlock_bh(&sta_priv->ampdu_lock);
 
-               wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
-                       get_sta_index(vif, sta_priv));
                break;
        case IEEE80211_AMPDU_TX_STOP_FLUSH:
        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
@@ -1268,6 +1280,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                wcn36xx_err("Unknown AMPDU action\n");
        }
 
+out:
        mutex_unlock(&wcn->conf_mutex);
 
        return ret;
index d3285a504429d395b0c6c8ee7bf35a496e7a608b..eb7493e2c958b0a4de643b08aba8cf90d11659e0 100644 (file)
@@ -2561,6 +2561,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
                                             &session_id);
        if (ret) {
                wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret);
+               ret = -EINVAL;
                goto out;
        }
 
@@ -2626,27 +2627,43 @@ out:
        return ret;
 }
 
-static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len)
+static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba_info)
 {
+       struct wcn36xx_hal_trigger_ba_rsp_candidate *candidate;
        struct wcn36xx_hal_trigger_ba_rsp_msg *rsp;
+       int i;
 
        if (len < sizeof(*rsp))
                return -EINVAL;
 
        rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf;
+
+       if (rsp->candidate_cnt < 1)
+               return rsp->status ? rsp->status : -EINVAL;
+
+       candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp));
+
+       for (i = 0; i < STACFG_MAX_TC; i++) {
+               ba_info[i] = candidate->ba_info[i];
+       }
+
        return rsp->status;
 }
 
-int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id)
+int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn)
 {
        struct wcn36xx_hal_trigger_ba_req_msg msg_body;
        struct wcn36xx_hal_trigger_ba_req_candidate *candidate;
+       struct add_ba_info ba_info[STACFG_MAX_TC];
        int ret;
 
+       if (tid >= STACFG_MAX_TC)
+               return -EINVAL;
+
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ);
 
-       msg_body.session_id = session_id;
+       msg_body.session_id = 0; /* not really used */
        msg_body.candidate_cnt = 1;
        msg_body.header.len += sizeof(*candidate);
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
@@ -2661,13 +2678,17 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 sessio
                wcn36xx_err("Sending hal_trigger_ba failed\n");
                goto out;
        }
-       ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len);
+       ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len, ba_info);
        if (ret) {
                wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
                goto out;
        }
 out:
        mutex_unlock(&wcn->hal_mutex);
+
+       if (ssn)
+               *ssn = ba_info[tid].starting_seq_num;
+
        return ret;
 }
 
index 88e045dad8f3a1ab882644ccc2f70e874b0cbd01..cfde15341a88d582d2a7eb25800a4760287c6c77 100644 (file)
@@ -137,7 +137,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
                u8 sta_index);
 int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id);
 int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 direction, u8 sta_index);
-int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id);
+int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn);
 
 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);