Browse Source

qcacld-3.0: Defer power-save for certain APs during initial connection

Few APs create interoperability issues when STA goes to power-save mode
right after initial connection.

In order to resolve these issues, defer the power-save for few seconds
when connected to those APs.

Change-Id: I3f6b642fb4e481dcb8e14f6da141f4cfa9d6b167
CRs-Fixed: 2046014
Krunal Soni 8 years ago
parent
commit
364e087691

+ 1 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -673,6 +673,7 @@ struct hdd_station_ctx {
 #if defined(WLAN_FEATURE_NAN_DATAPATH) && !defined(WLAN_FEATURE_NAN_CONVERGENCE)
 	struct nan_datapath_ctx ndp_ctx;
 #endif
+	bool ap_supports_immediate_power_save;
 };
 
 #define BSS_STOP    0

+ 15 - 2
core/hdd/src/wlan_hdd_assoc.c

@@ -2237,7 +2237,7 @@ static int hdd_change_sta_state_authenticated(hdd_adapter_t *adapter,
 		sme_ps_enable_auto_ps_timer(
 			WLAN_HDD_GET_HAL_CTX(adapter),
 			adapter->sessionId,
-			timeout);
+			timeout, false);
 	}
 
 	return qdf_status_to_os_return(status);
@@ -2442,7 +2442,7 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter,
 	hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
 	uint8_t reqRsnIe[DOT11F_IE_RSN_MAX_LEN];
-	uint32_t reqRsnLength = DOT11F_IE_RSN_MAX_LEN;
+	uint32_t reqRsnLength = DOT11F_IE_RSN_MAX_LEN, ie_len;
 	int ft_carrier_on = false;
 	bool hddDisconInProgress = false;
 	unsigned long rc;
@@ -2498,6 +2498,19 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter,
 			pAdapter->wapi_info.fIsWapiSta = 0;
 		}
 #endif /* FEATURE_WLAN_WAPI */
+		hdd_debug("bss_descr[%d] devicemode[%d]", !!pRoamInfo->pBssDesc,
+				pAdapter->device_mode);
+		if ((QDF_STA_MODE == pAdapter->device_mode) &&
+						pRoamInfo->pBssDesc) {
+			ie_len = GET_IE_LEN_IN_BSS(pRoamInfo->pBssDesc->length);
+			pHddStaCtx->ap_supports_immediate_power_save =
+				wlan_hdd_is_ap_supports_immediate_power_save(
+				     (uint8_t *) pRoamInfo->pBssDesc->ieFields,
+				     ie_len);
+			hdd_debug("ap_supports_immediate_power_save flag [%d]",
+				  pHddStaCtx->ap_supports_immediate_power_save);
+		}
+
 		/* Indicate 'connect' status to user space */
 		hdd_send_association_event(dev, pRoamInfo);
 

+ 21 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -11104,6 +11104,27 @@ uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length,
 	return NULL;
 }
 
+bool wlan_hdd_is_ap_supports_immediate_power_save(uint8_t *ies, int length)
+{
+	uint8_t *vendor_ie;
+
+	if (length < 2) {
+		hdd_debug("bss size is less than expected");
+		return true;
+	}
+	if (!ies) {
+		hdd_debug("invalid IE pointer");
+		return true;
+	}
+	vendor_ie = wlan_hdd_get_vendor_oui_ie_ptr(VENDOR1_AP_OUI_TYPE,
+				VENDOR1_AP_OUI_TYPE_SIZE, ies, length);
+	if (vendor_ie) {
+		hdd_debug("AP can't support immediate powersave. defer it");
+		return false;
+	}
+	return true;
+}
+
 /*
  * FUNCTION: wlan_hdd_validate_operation_channel
  * called by wlan_hdd_cfg80211_start_bss() and

+ 16 - 1
core/hdd/src/wlan_hdd_cfg80211.h

@@ -81,6 +81,9 @@
 #define WMM_OUI_TYPE   "\x00\x50\xf2\x02\x01"
 #define WMM_OUI_TYPE_SIZE  5
 
+#define VENDOR1_AP_OUI_TYPE "\x00\xE0\x4C"
+#define VENDOR1_AP_OUI_TYPE_SIZE 3
+
 #define WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
 #define WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
 #define BASIC_RATE_MASK   0x80
@@ -265,7 +268,19 @@ void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel,
 
 uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length,
 				      uint8_t eid);
-
+/**
+ * wlan_hdd_is_ap_supports_immediate_power_save() - to find certain vendor APs
+ *				which do not support immediate power-save.
+ * @ies: beacon IE of the AP which STA is connecting/connected to
+ * @length: beacon IE length only
+ *
+ * This API takes the IE of connected/connecting AP and determines that
+ * whether it has specific vendor OUI. If it finds then it will return false to
+ * notify that AP doesn't support immediate power-save.
+ *
+ * Return: true or false based on findings
+ */
+bool wlan_hdd_is_ap_supports_immediate_power_save(uint8_t *ies, int length);
 void wlan_hdd_del_station(hdd_adapter_t *adapter);
 
 #if defined(USE_CFG80211_DEL_STA_V2)

+ 11 - 1
core/hdd/src/wlan_hdd_power.c

@@ -1523,6 +1523,7 @@ static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
 {
 	tHalHandle hal;
 	hdd_context_t *hdd_ctx;
+	bool force_trigger = false;
 
 	if (NULL == adapter) {
 		hdd_err("Adapter NULL");
@@ -1538,6 +1539,15 @@ static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
 	hdd_debug("Allow power save: %d", allow_power_save);
 	hal = WLAN_HDD_GET_HAL_CTX(adapter);
 
+	if ((QDF_STA_MODE == adapter->device_mode) &&
+	    !adapter->sessionCtx.station.ap_supports_immediate_power_save) {
+		/* override user's requested flag */
+		force_trigger = allow_power_save;
+		allow_power_save = false;
+		timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
+		hdd_debug("Defer power-save for few seconds...");
+	}
+
 	if (allow_power_save) {
 		if (QDF_STA_MODE == adapter->device_mode ||
 		    QDF_P2P_CLIENT_MODE == adapter->device_mode) {
@@ -1570,7 +1580,7 @@ static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
 			adapter->sessionId);
 		sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
 		sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
-			adapter->sessionId, timeout);
+			adapter->sessionId, timeout, force_trigger);
 	}
 
 	return 0;

+ 10 - 2
core/sme/inc/sme_power_save_api.h

@@ -70,9 +70,17 @@ QDF_STATUS sme_set_ps_ns_offload(tHalHandle hal_ctx,
 tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx,
 				  struct scheduler_msg *pMsg);
 
+/**
+ * sme_ps_enable_auto_ps_timer(): Enable power-save auto timer with timeout
+ * @hal_ctx:       HAL context
+ * @session_id:    adapter session Id
+ * @timeout:       timeout period in ms
+ * @force_trigger: forcing power-save timer to trigger
+ *
+ * Returns: QDF_STATUS
+ */
 QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx,
-		uint32_t sessionId,
-		uint32_t timeout);
+		uint32_t sessionId, uint32_t timeout, bool force_trigger);
 QDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx,
 		uint32_t sessionId);
 

+ 4 - 11
core/sme/src/common/sme_power_save.c

@@ -820,24 +820,17 @@ tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx,
 	return eSIR_SUCCESS;
 }
 
-/**
- * sme_ps_enable_auto_ps_timer(): Enable power-save auto timer with timeout
- * @hal_ctx:	HAL context
- * @session_id:	adapter session Id
- * @timeout:	timeout period in ms
- *
- * Returns:	0 on success, non-zero on failure
- */
 QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx,
-	uint32_t session_id, uint32_t timeout)
+	uint32_t session_id, uint32_t timeout, bool force_trigger)
 {
 	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx);
 	struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info;
 	struct ps_params *ps_param = &ps_global_info->ps_params[session_id];
 	QDF_STATUS qdf_status;
 
-	if (!ps_global_info->auto_bmps_timer_val) {
-		sme_debug("auto_ps_timer is disabled in INI");
+	if (!ps_global_info->auto_bmps_timer_val && !force_trigger) {
+		sme_debug("auto_ps_timer is disabled in INI, force_trigger-%d",
+			  force_trigger);
 		return QDF_STATUS_SUCCESS;
 	}