[PATCH 2/2] wcn36xx: fix the mesh STA for rejoin

Jason Mobarak jam at cozybit.com
Wed Mar 19 14:56:43 EDT 2014


From: Chun-Yeow Yeoh <yeohchunyeow at gmail.com>

The firmware triggers the QoS NULL frame to monitor the links amongst
peer mesh STAs. Once one of the peer mesh STAs has left or is out of
range, and no ACK was received from the peer mesh STA, the firmware will
automatically delete the peer mesh STA.

After the mesh STA was signaled as "removed" from the firmware
(WCN36XX_HAL_DELETE_STA_CONTEXT_IND), initial attempts to work around
this simply tried re-adding the mesh STA (with the HAL command returning
no error) and the STA still would not work. Unicast data frames were not
able to transmit out from the mesh STA.

To work around this, we re-insert the inactivite mesh STA with the HAL
command WCN36XX_HAL_CONFIG_STA_REQ and the action field set to 'update',
which seems to solve the problem.

Signed-off-by: Jason Mobarak <jam at cozybit.com>
Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow at cozybit.com>
Signed-off-by: Javier Lopez <jlopex at cozybit.com>
Signed-off-by: Javier Cardona <javier at cozybit.com>
---

v2: Addressed comments from Pontus.

v3: Rework the patch so we don't need to track an internal list of STAs,
instead we just ask ieee80211 if it knows about the STA already.

 main.c | 15 +++++++++++++--
 smd.c  | 11 +++++++++--
 smd.h  |  2 +-
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/main.c b/main.c
index 2a6a9c4..add29fd 100644
--- a/main.c
+++ b/main.c
@@ -673,7 +673,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
 			 * config_sta must be called from  because this is the
 			 * place where AID is available.
 			 */
-			wcn36xx_smd_config_sta(wcn, vif, sta);
+			wcn36xx_smd_config_sta(wcn, vif, sta, 0);
 			rcu_read_unlock();
 		} else {
 			wcn36xx_dbg(WCN36XX_DBG_MAC,
@@ -783,6 +783,16 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw,
 	return 0;
 }
 
+static bool wcn36xx_sta_preexists(struct ieee80211_vif *vif,
+		struct ieee80211_sta *sta)
+{
+	struct ieee80211_sta *sta_preexist;
+	rcu_read_lock();
+	sta_preexist = ieee80211_find_sta(vif, sta->addr);
+	rcu_read_unlock();
+	return !!sta_preexist;
+}
+
 static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			   struct ieee80211_sta *sta)
 {
@@ -800,7 +810,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	if (NL80211_IFTYPE_STATION != vif->type) {
 		wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
 		sta_priv->aid = sta->aid;
-		wcn36xx_smd_config_sta(wcn, vif, sta);
+		wcn36xx_smd_config_sta(wcn, vif, sta, wcn36xx_sta_preexists(vif, sta));
 	}
 	return 0;
 }
@@ -817,6 +827,7 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
 
 	wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
 	sta_priv->vif = NULL;
+
 	return 0;
 }
 
diff --git a/smd.c b/smd.c
index a2bf694..d42cc0a 100644
--- a/smd.c
+++ b/smd.c
@@ -869,6 +869,7 @@ static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,
 	v1->type = orig->type;
 	v1->listen_interval = orig->listen_interval;
 	v1->ht_capable = orig->ht_capable;
+	v1->action = orig->action;
 
 	v1->max_ampdu_size = orig->max_ampdu_size;
 	v1->max_ampdu_density = orig->max_ampdu_density;
@@ -935,7 +936,7 @@ static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn,
 }
 
 int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
-			   struct ieee80211_sta *sta)
+			   struct ieee80211_sta *sta, u8 action)
 {
 	struct wcn36xx_hal_config_sta_req_msg msg;
 	struct wcn36xx_hal_config_sta_params *sta_params;
@@ -947,6 +948,7 @@ int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
 	sta_params = &msg.sta_params;
 
 	wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
+	sta_params->action = action;
 
 	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
 		ret = wcn36xx_smd_config_sta_v1(wcn, &msg);
@@ -1980,6 +1982,7 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
 	struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf;
 	struct wcn36xx_vif *tmp;
 	struct ieee80211_sta *sta;
+	struct ieee80211_vif *vif;
 
 	if (len != sizeof(*rsp)) {
 		wcn36xx_warn("Corrupted delete sta indication\n");
@@ -1990,10 +1993,14 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
 		    rsp->addr2, rsp->sta_id);
 
 	list_for_each_entry(tmp, &wcn->vif_list, list) {
+		wcn36xx_warn("STA %pM index %d is leaving\n", rsp->addr2, rsp->sta_id);
 		rcu_read_lock();
-		sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2);
+		vif = wcn36xx_priv_to_vif(tmp);
+		sta = ieee80211_find_sta(vif, rsp->addr2);
 		if (sta)
 			ieee80211_report_low_ack(sta, 0);
+		if (sta && vif->type == NL80211_IFTYPE_MESH_POINT)
+			wcn36xx_smd_config_sta(wcn, vif, sta, 1);
 		rcu_read_unlock();
 		if (sta)
 			return 0;
diff --git a/smd.h b/smd.h
index 751b62b..9e86e3d 100644
--- a/smd.h
+++ b/smd.h
@@ -77,7 +77,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
 			   bool update);
 int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif);
 int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
-			   struct ieee80211_sta *sta);
+			   struct ieee80211_sta *sta, u8 action);
 int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
 			    struct sk_buff *skb_beacon, u16 tim_off,
 			    u16 p2p_off);
-- 
1.9.0




More information about the wcn36xx mailing list