Browse Source

qcacld-3.0: Let IOT APs recover by avoiding back to back DELBA

Station sends the BA and upgrades to the next possible BA window
size upon receiving all frames successfully from the current
window. Some IOT APs go out of sync from BA window size of the
station when AP fails to receive the BA sent from station. AP
transmits the frames again with previous window sequence number
and won't be ack'ed by station hardware as BA window has already
moved ahead. So, station deletes the upgraded BA and tries
to fallback.

Ideally, AP is supposed to consider the fact that "the previous
window transmission was successful when station upgrades to next
window size". But some APs take little longer time to
recover/upgrade to next window size. Don't delete the BA
immediately and have some tolerance(3 seconds) as the previous
negotiated BA just got deleted.

Change-Id: I6b277223f02dac521316cec20bd5d958785cc2e9
CRs-Fixed: 2970714
Srinivas Dasari 3 years ago
parent
commit
c65ead975b

+ 5 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -385,6 +385,9 @@ struct wait_for_key_timer {
  * @connect_info: mlme connect information
  * @wait_key_timer: wait key timer
  * @eht_config: Eht capability configuration
+ * @last_delba_sent_time: Last delba sent time to handle back to back delba
+ *			  requests from some IOT APs
+ * @ba_2k_jump_iot_ap: This is set to true if connected to the ba 2k jump IOT AP
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -421,6 +424,8 @@ struct mlme_legacy_priv {
 #ifdef WLAN_FEATURE_11BE
 	tDot11fIEeht_cap eht_config;
 #endif
+	qdf_time_t last_delba_sent_time;
+	bool ba_2k_jump_iot_ap;
 };
 
 /**

+ 39 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -3240,4 +3240,43 @@ wlan_mlme_is_data_stall_recovery_fw_supported(struct wlan_objmgr_psoc *psoc);
  */
 QDF_STATUS mlme_cfg_get_eht_caps(struct wlan_objmgr_psoc *psoc,
 				 tDot11fIEeht_cap *eht_cap);
+
+/**
+ * wlan_mlme_set_ba_2k_jump_iot_ap() - Set a flag if ba 2k jump IOT AP is found
+ * @vdev: vdev pointer
+ * @found: Carries the value true if ba 2k jump IOT AP is found
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_set_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev, bool found);
+
+/**
+ * wlan_mlme_is_ba_2k_jump_iot_ap() - Check if ba 2k jump IOT AP is found
+ * @vdev: vdev pointer
+ *
+ * Return: true if ba 2k jump IOT AP is found
+ */
+bool
+wlan_mlme_is_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * wlan_mlme_set_last_delba_sent_time() - Cache the last delba sent ts
+ * @vdev: vdev pointer
+ * @delba_sent_time: Last delba sent timestamp
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_set_last_delba_sent_time(struct wlan_objmgr_vdev *vdev,
+				   qdf_time_t delba_sent_time);
+
+/**
+ * wlan_mlme_get_last_delba_sent_time() - Get the last delba sent ts
+ * @vdev: vdev pointer
+ *
+ * Return: Last delba timestamp if cached, 0 otherwise
+ */
+qdf_time_t
+wlan_mlme_get_last_delba_sent_time(struct wlan_objmgr_vdev *vdev);
 #endif /* _WLAN_MLME_API_H_ */

+ 60 - 0
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -4985,3 +4985,63 @@ QDF_STATUS mlme_cfg_get_eht_caps(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+
+QDF_STATUS
+wlan_mlme_set_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev, bool found)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv->ba_2k_jump_iot_ap = found;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool wlan_mlme_is_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return false;
+	}
+
+	return mlme_priv->ba_2k_jump_iot_ap;
+}
+
+QDF_STATUS
+wlan_mlme_set_last_delba_sent_time(struct wlan_objmgr_vdev *vdev,
+				   qdf_time_t delba_sent_time)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv->last_delba_sent_time = delba_sent_time;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_time_t
+wlan_mlme_get_last_delba_sent_time(struct wlan_objmgr_vdev *vdev)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return 0;
+	}
+
+	return mlme_priv->last_delba_sent_time;
+}

+ 3 - 0
core/mac/inc/sir_mac_prot_def.h

@@ -339,6 +339,9 @@
 #define SIR_MAC_VENDOR_AP_4_OUI             "\x8C\xFD\xF0"
 #define SIR_MAC_VENDOR_AP_4_OUI_LEN         3
 
+#define SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI             "\x00\x14\x6C"
+#define SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI_LEN         3
+
 /* Maximum allowable size of a beacon and probe rsp frame */
 #define SIR_MAX_BEACON_SIZE    512
 #define SIR_MAX_PROBE_RESP_SIZE 512

+ 6 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -1740,6 +1740,12 @@ static void lim_check_oui_and_update_session(struct mac_context *mac_ctx,
 	lim_handle_iot_ap_no_common_he_rates(mac_ctx, session, ie_struct);
 	lim_update_he_caps_mcs(mac_ctx, session);
 	lim_update_eht_caps_mcs(mac_ctx, session);
+
+	is_vendor_ap_present = wlan_get_vendor_ie_ptr_from_oui(
+				SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI,
+				SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI_LEN,
+				vendor_ap_search_attr.ie_data, ie_len);
+	wlan_mlme_set_ba_2k_jump_iot_ap(session->vdev, is_vendor_ap_present);
 }
 
 static enum mlme_dot11_mode

+ 37 - 0
core/wma/src/wma_data.c

@@ -3099,6 +3099,39 @@ uint8_t wma_rx_invalid_peer_ind(uint8_t vdev_id, void *wh)
 	return 0;
 }
 
+static bool
+wma_drop_delba(tp_wma_handle wma, uint8_t vdev_id,
+	       enum cdp_delba_rcode cdp_reason_code)
+{
+	struct wlan_objmgr_vdev *vdev;
+	qdf_time_t last_ts, ts = qdf_mc_timer_get_system_time();
+	bool drop = false;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		wma_err("vdev is NULL");
+		return drop;
+	}
+	if (!wlan_mlme_is_ba_2k_jump_iot_ap(vdev))
+		goto done;
+
+	last_ts = wlan_mlme_get_last_delba_sent_time(vdev);
+	if ((last_ts && cdp_reason_code == CDP_DELBA_2K_JUMP) &&
+	    (ts - last_ts) < CDP_DELBA_INTERVAL_MS) {
+		wma_debug("Drop DELBA, last sent ts: %lu current ts: %lu",
+			  last_ts, ts);
+		drop = true;
+	}
+
+	wlan_mlme_set_last_delba_sent_time(vdev, ts);
+
+done:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+
+	return drop;
+}
+
 int wma_dp_send_delba_ind(uint8_t vdev_id, uint8_t *peer_macaddr,
 			  uint8_t tid, uint8_t reason_code,
 			  enum cdp_delba_rcode cdp_reason_code)
@@ -3110,6 +3143,10 @@ int wma_dp_send_delba_ind(uint8_t vdev_id, uint8_t *peer_macaddr,
 		wma_err("wma handle or mac addr is NULL");
 		return -EINVAL;
 	}
+
+	if (wma_drop_delba(wma, vdev_id, cdp_reason_code))
+		return 0;
+
 	req = qdf_mem_malloc(sizeof(*req));
 	if (!req)
 		return -ENOMEM;