Browse Source

qcacld-3.0: Clear oldest cached sta information

Currently host is caching all the connected sta info
in case of SAP, once the sta count reaches to MAX, below
mentioned issues occurs:
1. Driver can not cache the information of newly connected
   stations.
2. Some of the info is cached at the time of connection while
   remaining info is cached during disconnection. In the
   disconnect path driver tries to cache some of the info
   such mc_bc count, disconnect reason code, since driver can't
   cache anymore info, it does not find the current station which
   is getting disconnected in cache sta info structure leading to
   an error, and driver is returning an error without completing
   the wait for disconnect event which is resulting in timeout.
Since sta_disconnect comes with rtnl_held, any other process
is not able to get the rtnl_lock until this timeout occurs.

To address this issue below mentioned two measures taken care:
Clear the oldest cached sta information and save the newly connected
station's information.
In the disconnect path, do not return any error and simply proceed
with disconnection as failure to cache the information of sta
should not stop the disconnection process.

Change-Id: Ia955a6774033fdfa91ff1fa7c8832b3ec7e8e1a0
CRs-Fixed: 2333075
Ashish Kumar Dhanotiya 6 years ago
parent
commit
2ef479048d
2 changed files with 49 additions and 28 deletions
  1. 1 0
      core/hdd/inc/wlan_hdd_main.h
  2. 48 28
      core/hdd/src/wlan_hdd_hostapd.c

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

@@ -1042,6 +1042,7 @@ struct hdd_station_info {
 	uint64_t rx_bytes;
 	qdf_time_t last_tx_rx_ts;
 	qdf_time_t assoc_ts;
+	qdf_time_t disassoc_ts;
 	uint32_t tx_rate;
 	uint32_t rx_rate;
 	bool ampdu;

+ 48 - 28
core/hdd/src/wlan_hdd_hostapd.c

@@ -1419,7 +1419,8 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 				  tSap_StationAssocReassocCompleteEvent *event)
 {
 	struct hdd_station_info *stainfo;
-	uint8_t i = 0;
+	uint8_t i = 0, oldest_disassoc_sta_idx = WLAN_MAX_STA_COUNT + 1;
+	qdf_time_t oldest_disassoc_sta_ts = 0;
 
 	if (event->staId >= WLAN_MAX_STA_COUNT) {
 		hdd_err("invalid sta id");
@@ -1480,11 +1481,8 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 	while (i < WLAN_MAX_STA_COUNT) {
 		if (!qdf_mem_cmp(adapter->cache_sta_info[i].sta_mac.bytes,
 				 event->staMac.bytes,
-				 QDF_MAC_ADDR_SIZE)) {
-			qdf_mem_zero(&adapter->cache_sta_info[i],
-				     sizeof(*stainfo));
+				 QDF_MAC_ADDR_SIZE))
 			break;
-		}
 		i++;
 	}
 	if (i >= WLAN_MAX_STA_COUNT) {
@@ -1492,14 +1490,35 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 		while (i < WLAN_MAX_STA_COUNT) {
 			if (adapter->cache_sta_info[i].in_use != TRUE)
 				break;
+
+			if (adapter->cache_sta_info[i].disassoc_ts &&
+			    (!oldest_disassoc_sta_ts ||
+			    (qdf_system_time_after(
+					oldest_disassoc_sta_ts,
+					adapter->
+					cache_sta_info[i].disassoc_ts)))) {
+				oldest_disassoc_sta_ts =
+					adapter->
+						cache_sta_info[i].disassoc_ts;
+				oldest_disassoc_sta_idx = i;
+			}
 			i++;
 		}
 	}
-	if (i < WLAN_MAX_STA_COUNT)
+
+	if ((i == WLAN_MAX_STA_COUNT) && oldest_disassoc_sta_ts) {
+		hdd_debug("reached max cached staid, removing oldest stainfo");
+		i = oldest_disassoc_sta_idx;
+	}
+	if (i < WLAN_MAX_STA_COUNT) {
+		qdf_mem_zero(&adapter->cache_sta_info[i],
+			     sizeof(*stainfo));
 		qdf_mem_copy(&adapter->cache_sta_info[i],
-			     stainfo, sizeof(struct hdd_station_info));
-	else
+				     stainfo, sizeof(struct hdd_station_info));
+
+	} else {
 		hdd_debug("reached max staid, stainfo can't be cached");
+	}
 
 	hdd_debug("cap %d %d %d %d %d %d %d %d %d %x %d",
 		  stainfo->ampdu,
@@ -1597,7 +1616,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 	eCsrPhyMode phy_mode;
 	bool legacy_phymode;
 	tSap_StationDisassocCompleteEvent *disassoc_comp;
-	struct hdd_station_info *stainfo;
+	struct hdd_station_info *stainfo, *cache_stainfo;
 	mac_handle_t mac_handle;
 	tsap_config_t *sap_config;
 
@@ -2193,21 +2212,19 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 		memcpy(wrqu.addr.sa_data,
 		       &disassoc_comp->staMac, QDF_MAC_ADDR_SIZE);
 
-		stainfo = hdd_get_stainfo(adapter->cache_sta_info,
-					  disassoc_comp->staMac);
-		if (!stainfo) {
-			hdd_err("peer " MAC_ADDRESS_STR " not found",
-					MAC_ADDR_ARRAY(wrqu.addr.sa_data));
-			return -EINVAL;
+		cache_stainfo = hdd_get_stainfo(adapter->cache_sta_info,
+						disassoc_comp->staMac);
+		if (cache_stainfo) {
+			/* Cache the disassoc info */
+			cache_stainfo->rssi = disassoc_comp->rssi;
+			cache_stainfo->tx_rate = disassoc_comp->tx_rate;
+			cache_stainfo->rx_rate = disassoc_comp->rx_rate;
+			cache_stainfo->reason_code = disassoc_comp->reason_code;
+			cache_stainfo->disassoc_ts = qdf_system_ticks();
 		}
 		hdd_info(" disassociated " MAC_ADDRESS_STR,
 				MAC_ADDR_ARRAY(wrqu.addr.sa_data));
 
-		stainfo->rssi = disassoc_comp->rssi;
-		stainfo->tx_rate = disassoc_comp->tx_rate;
-		stainfo->rx_rate = disassoc_comp->rx_rate;
-		stainfo->reason_code = disassoc_comp->reason_code;
-
 		qdf_status = qdf_event_set(&hostapd_state->qdf_sta_disassoc_event);
 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 			hdd_err("Station Deauth event Set failed");
@@ -2233,14 +2250,17 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 			QDF_TRACE_DEFAULT_PDEV_ID,
 			QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC));
 
-		/* Send DHCP STOP indication to FW */
-		stainfo->dhcp_phase = DHCP_PHASE_ACK;
-		if (stainfo->dhcp_nego_status ==
-					DHCP_NEGO_IN_PROGRESS)
-			hdd_post_dhcp_ind(adapter, staId,
-					WMA_DHCP_STOP_IND);
-		stainfo->dhcp_nego_status = DHCP_NEGO_STOP;
-
+		stainfo = hdd_get_stainfo(adapter->sta_info,
+					  disassoc_comp->staMac);
+		if (stainfo) {
+			/* Send DHCP STOP indication to FW */
+			stainfo->dhcp_phase = DHCP_PHASE_ACK;
+			if (stainfo->dhcp_nego_status ==
+						DHCP_NEGO_IN_PROGRESS)
+				hdd_post_dhcp_ind(adapter, staId,
+						  WMA_DHCP_STOP_IND);
+			stainfo->dhcp_nego_status = DHCP_NEGO_STOP;
+		}
 		hdd_softap_deregister_sta(adapter, staId);
 
 		ap_ctx->ap_active = false;