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

Jason Mobarak jam at cozybit.com
Thu Mar 6 20:31:02 EST 2014


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

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

After deleting the mesh STA and adding the mesh STA back with the HAL
command returning no error, the STA still won't work. Unicast data
frames is not able to transmit out from the mesh STA.

Now, re-insert the inactivite mesh STA with WCN36XX_HAL_CONFIG_STA_REQ
command with action field set to update seems to solve the problem.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow at cozybit.com>
Signed-off-by: Jason Mobarak <jam at cozybit.com>
Signed-off-by: Javier Lopez <jlopex at cozybit.com>
Signed-off-by: Javier Cardona <javier at cozybit.com>
---
 main.c    | 45 +++++++++++++++++++++++++++++++++++++++++----
 smd.c     | 62 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
 smd.h     |  9 ++++++++-
 wcn36xx.h |  6 ++++++
 4 files changed, 103 insertions(+), 19 deletions(-)

diff --git a/main.c b/main.c
index 2a6a9c4..a1c2a5f 100644
--- a/main.c
+++ b/main.c
@@ -299,6 +299,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
 	wcn36xx_debugfs_init(wcn);
 
 	INIT_LIST_HEAD(&wcn->vif_list);
+
 	return 0;
 
 out_smd_stop:
@@ -673,7 +674,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,
@@ -777,6 +778,9 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw,
 		return -EOPNOTSUPP;
 	}
 
+	INIT_LIST_HEAD(&vif_priv->sta_list);
+	spin_lock_init(&vif_priv->sta_list_spinlock);
+
 	list_add(&vif_priv->list, &wcn->vif_list);
 	wcn36xx_smd_add_sta_self(wcn, vif);
 
@@ -789,10 +793,22 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	struct wcn36xx *wcn = hw->priv;
 	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
+	struct wcn36xx_sta *sta_priv_existing = NULL;
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
 		    vif, sta->addr);
 
 	sta_priv->vif = vif_priv;
+
+	spin_lock(&vif_priv->sta_list_spinlock);
+	sta_priv_existing = wcn36xx_find_sta(vif_priv, sta->addr);
+
+	if (sta_priv_existing)
+		sta_priv = sta_priv_existing;
+	else
+		list_add(&sta_priv->list, &vif_priv->sta_list);
+
+	spin_unlock(&vif_priv->sta_list_spinlock);
+
 	/*
 	 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
 	 * at this stage AID is not available yet.
@@ -800,8 +816,12 @@ 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);
+		if (sta_priv_existing)
+			wcn36xx_smd_config_sta(wcn, vif, sta, 1);
+		else
+			wcn36xx_smd_config_sta(wcn, vif, sta, 0);
 	}
+
 	return 0;
 }
 
@@ -811,12 +831,29 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
 {
 	struct wcn36xx *wcn = hw->priv;
 	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
+	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+	struct wcn36xx_sta *sta_priv_existing = NULL;
 
 	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
 		    vif, sta->addr, sta_priv->sta_index);
 
-	wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
-	sta_priv->vif = NULL;
+	spin_lock(&vif_priv->sta_list_spinlock);
+	sta_priv_existing = wcn36xx_find_sta(vif_priv, sta->addr);
+
+	if (sta_priv_existing)
+		list_del(&sta_priv_existing->list);
+
+	spin_unlock(&vif_priv->sta_list_spinlock);
+
+	if (sta_priv_existing) {
+		sta_priv_existing->vif = NULL;
+		wcn36xx_smd_delete_sta(wcn, sta_priv_existing->sta_index);
+	}
+	else {
+		sta_priv->vif = NULL;
+		wcn36xx_smd_delete_sta(wcn, sta_priv_existing->sta_index);
+	}
+
 	return 0;
 }
 
diff --git a/smd.c b/smd.c
index e01933a..55bcab0 100644
--- a/smd.c
+++ b/smd.c
@@ -860,7 +860,8 @@ out:
 
 static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,
 			const struct wcn36xx_hal_config_sta_params *orig,
-			struct wcn36xx_hal_config_sta_params_v1 *v1)
+			struct wcn36xx_hal_config_sta_params_v1 *v1,
+			u8 action)
 {
 	/* convert orig to v1 format */
 	memcpy(&v1->bssid, orig->bssid, ETH_ALEN);
@@ -869,6 +870,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 = action;
 
 	v1->max_ampdu_size = orig->max_ampdu_size;
 	v1->max_ampdu_density = orig->max_ampdu_density;
@@ -905,6 +907,8 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
 	sta_priv->dpu_desc_index = params->dpu_index;
 	sta_priv->ucast_dpu_sign = params->uc_ucast_sig;
 
+	memcpy(sta_priv->mac_addr, sta->addr, ETH_ALEN);
+
 	wcn36xx_dbg(WCN36XX_DBG_HAL,
 		    "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n",
 		    params->status, params->sta_index, params->bssid_index,
@@ -914,7 +918,8 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
 }
 
 static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn,
-		     const struct wcn36xx_hal_config_sta_req_msg *orig)
+		     const struct wcn36xx_hal_config_sta_req_msg *orig,
+		     u8 action)
 {
 	struct wcn36xx_hal_config_sta_req_msg_v1 msg_body;
 	struct wcn36xx_hal_config_sta_params_v1 *sta = &msg_body.sta_params;
@@ -922,7 +927,7 @@ static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn,
 	INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);
 
 	wcn36xx_smd_convert_sta_to_v1(wcn, &orig->sta_params,
-				      &msg_body.sta_params);
+				      &msg_body.sta_params, action);
 
 	PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -935,7 +940,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;
@@ -949,7 +954,7 @@ int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
 	wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
 
 	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
-		ret = wcn36xx_smd_config_sta_v1(wcn, &msg);
+		ret = wcn36xx_smd_config_sta_v1(wcn, &msg, action);
 	} else {
 		PREPARE_HAL_BUF(wcn->hal_buf, msg);
 
@@ -1068,7 +1073,7 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
 	msg_body.bss_params.max_tx_power = orig->bss_params.max_tx_power;
 
 	wcn36xx_smd_convert_sta_to_v1(wcn, &orig->bss_params.sta,
-				      &msg_body.bss_params.sta);
+				      &msg_body.bss_params.sta, 0);
 
 	PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -1956,7 +1961,9 @@ 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_sta *sta = NULL;
+	struct wcn36xx_sta *sta_priv = NULL;
+	struct ieee80211_vif *vif = NULL;
 
 	if (len != sizeof(*rsp)) {
 		wcn36xx_warn("Corrupted delete sta indication\n");
@@ -1967,18 +1974,26 @@ 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) {
-		rcu_read_lock();
-		sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2);
-		if (sta)
-			ieee80211_report_low_ack(sta, 0);
-		rcu_read_unlock();
-		if (sta)
-			return 0;
+        wcn36xx_warn("STA %pM index %d is leaving\n", rsp->addr2, rsp->sta_id);
+
+        sta_priv = wcn36xx_find_sta(tmp, rsp->addr2);
+        if(!sta_priv)
+            continue;
+
+        sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2);
+        vif = wcn36xx_priv_to_vif(tmp);
+
+        if (vif->type == NL80211_IFTYPE_MESH_POINT) {
+            wcn36xx_smd_config_sta(wcn, vif, sta, 1);
+        }
+
+        return 0;
 	}
 
 	wcn36xx_warn("STA with addr %pM and index %d not found\n",
 		     rsp->addr2,
 		     rsp->sta_id);
+
 	return -ENOENT;
 }
 
@@ -2164,3 +2179,22 @@ void wcn36xx_smd_close(struct wcn36xx *wcn)
 	destroy_workqueue(wcn->hal_ind_wq);
 	mutex_destroy(&wcn->hal_ind_mutex);
 }
+
+/**
+ * Assumes lock wcn36xx_vif->sta_list_spinlock is already held.
+ */
+struct wcn36xx_sta* wcn36xx_find_sta(struct wcn36xx_vif *priv, u8 *mac_addr)
+{
+    struct wcn36xx_sta* entry = NULL;
+
+    if (!mac_addr)
+        return NULL;
+
+    list_for_each_entry(entry, &priv->sta_list, list) {
+        if (!memcmp(entry->mac_addr, mac_addr, ETH_ALEN))
+            return entry;
+    }
+
+    return NULL;
+}
+
diff --git a/smd.h b/smd.h
index 751b62b..6a12874 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);
@@ -128,4 +128,11 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
 
 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+int wcn36xx_smd_get_stats(struct wcn36xx *wcn, u32 sta_index,
+			  enum wcn36xx_hal_stats_mask stats_mask,
+			  void *stats);
+
+struct wcn36xx_vif;
+struct wcn36xx_sta* wcn36xx_find_sta(struct wcn36xx_vif *priv, u8 *mac_addr);
+
 #endif	/* _SMD_H_ */
diff --git a/wcn36xx.h b/wcn36xx.h
index 82d773c..8be2788 100644
--- a/wcn36xx.h
+++ b/wcn36xx.h
@@ -121,6 +121,10 @@ struct wcn36xx_vif {
 	bool is_joining;
 	struct wcn36xx_hal_mac_ssid ssid;
 
+	struct list_head sta_list;
+	/* spin lock for associated station list */
+	spinlock_t sta_list_spinlock;
+
 	/* Power management */
 	enum wcn36xx_power_state pw_state;
 
@@ -154,6 +158,7 @@ struct wcn36xx_vif {
  * |______________|_____________|_______________|
  */
 struct wcn36xx_sta {
+	struct list_head list;
 	struct wcn36xx_vif *vif;
 	u16 aid;
 	u16 tid;
@@ -165,6 +170,7 @@ struct wcn36xx_sta {
 	bool is_data_encrypted;
 	/* Rates */
 	struct wcn36xx_hal_supported_rates supported_rates;
+	u8 mac_addr[ETH_ALEN];
 };
 struct wcn36xx_dxe_ch;
 struct wcn36xx {
-- 
1.9.0




More information about the wcn36xx mailing list