Sfoglia il codice sorgente

qcacld-3.0: Modify datastructure of sta_info from hash table to list

For each peer connected to SAP, there is a corresponding entry maintained
in HDD called station_info. Currently, this data is being stored as a
hash table. There are two primary complications in using a hash table
in this scenario:

	- The max peers supported are 32. This is a very small number to
	  use a hash table for. The minute time complexity gains for a
	  fetch/insert operation do not justify the implementation
	  complexity.

	- The hash table is being implemented with the use of kernel ht
	  APIs. These do not provide the granularity to achieve proper
	  synchronization as is needed in driver.

To address the above points, move the storage of sta_info from hash
table to linked list. This will provide simpler implementation and also
give access to using proper synchronization methods.

Change-Id: I7d3a8a2937048f29a867453a91dfc1864932619e
CRs-Fixed: 2668300
Sourav Mohapatra 5 anni fa
parent
commit
d8608e5f8c

+ 14 - 10
core/hdd/src/wlan_hdd_cfg80211.c

@@ -10497,7 +10497,7 @@ static int __wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
 		nss = sta_info->nss;
 		freq = (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operating_chan_freq;
 		rate_flags = sta_info->rate_flags;
-		hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	} else {
 		hdd_err("Not Associated! with mac "QDF_MAC_ADDR_STR,
 		       QDF_MAC_ADDR_ARRAY(peer_mac));
@@ -20695,7 +20695,6 @@ QDF_STATUS hdd_softap_deauth_current_sta(struct hdd_adapter *adapter,
 					 struct hdd_hostapd_state *hapd_state,
 					 struct csr_del_sta_params *param)
 {
-	uint8_t index = 0;
 	qdf_event_t *disassoc_event = &hapd_state->qdf_sta_disassoc_event;
 	struct hdd_context *hdd_ctx;
 	QDF_STATUS qdf_status;
@@ -20721,9 +20720,11 @@ QDF_STATUS hdd_softap_deauth_current_sta(struct hdd_adapter *adapter,
 
 	if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
 		if(qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
-			hdd_for_each_station(adapter->sta_info_list,
-					     sta_info, index)
+			hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 				sta_info->is_deauth_in_progress = true;
+				hdd_put_sta_info_ref(&adapter->sta_info_list,
+						     &sta_info, true);
+			}
 		} else {
 			sta_info->is_deauth_in_progress = true;
 		}
@@ -20755,7 +20756,6 @@ QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter,
 				     struct hdd_hostapd_state *hapd_state,
 				     struct csr_del_sta_params *param)
 {
-	uint8_t index = 0;
 	QDF_STATUS status;
 	bool is_sap_bcast_deauth_enabled = false;
 	struct hdd_context *hdd_ctx;
@@ -20780,16 +20780,20 @@ QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter,
 						     hapd_state, param);
 	}
 
-	hdd_for_each_station(adapter->sta_info_list, sta_info, index) {
+	hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 		if (!sta_info->is_deauth_in_progress) {
 			hdd_debug("Delete STA with MAC:" QDF_MAC_ADDR_STR,
 				  QDF_MAC_ADDR_ARRAY(sta_info->sta_mac.bytes));
 			status =
 			    hdd_softap_deauth_current_sta(adapter, sta_info,
 							  hapd_state, param);
-			if (QDF_IS_STATUS_ERROR(status))
+			if (QDF_IS_STATUS_ERROR(status)) {
+				hdd_put_sta_info_ref(&adapter->sta_info_list,
+						     &sta_info, true);
 				return status;
+			}
 		}
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 	return QDF_STATUS_SUCCESS;
@@ -20872,8 +20876,8 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
 			hdd_debug("Skip DEL STA as deauth is in progress::"
 				  QDF_MAC_ADDR_STR,
 				  QDF_MAC_ADDR_ARRAY(mac));
-			hdd_put_sta_info(&adapter->sta_info_list, &sta_info,
-					 true);
+			hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info,
+					     true);
 			return -ENOENT;
 		}
 
@@ -20881,7 +20885,7 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
 			  QDF_MAC_ADDR_ARRAY(mac));
 		hdd_softap_deauth_current_sta(adapter, sta_info, hapd_state,
 					      param);
-		hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 fn_end:

+ 30 - 35
core/hdd/src/wlan_hdd_hostapd.c

@@ -776,13 +776,13 @@ static void hdd_clear_sta(struct hdd_adapter *adapter,
 
 static void hdd_clear_all_sta(struct hdd_adapter *adapter)
 {
-	uint8_t index = 0;
 	struct hdd_station_info *sta_info;
 
 	hdd_enter_dev(adapter->dev);
 
-	hdd_for_each_station(adapter->sta_info_list, sta_info, index) {
+	hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 		hdd_clear_sta(adapter, sta_info);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 }
 
@@ -1453,7 +1453,6 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 {
 	struct hdd_station_info *stainfo, *cache_sta_info;
 	struct hdd_station_info *oldest_disassoc_sta_info = NULL;
-	uint8_t index = 0;
 	qdf_time_t oldest_disassoc_sta_ts = 0;
 	bool is_dot11_mode_abgn;
 
@@ -1504,6 +1503,7 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 	 * should always be true.
 	 */
 	is_dot11_mode_abgn = true;
+	stainfo->ecsa_capable = event->ecsa_capable;
 
 	if (event->vht_caps.present) {
 		stainfo->vht_present = true;
@@ -1545,8 +1545,7 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 				     event->ies, event->ies_len);
 			cache_sta_info->assoc_req_ies.len = event->ies_len;
 		}
-		qdf_mem_zero(&cache_sta_info->sta_node,
-			     sizeof(cache_sta_info->sta_node));
+		qdf_atomic_init(&cache_sta_info->ref_cnt);
 
 		/*
 		 * If cache_sta_info is not present and cache limit is not
@@ -1560,12 +1559,14 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 			qdf_atomic_inc(&adapter->cache_sta_count);
 		} else {
 			struct hdd_station_info *temp_sta_info;
+			struct hdd_sta_info_obj *sta_list =
+						&adapter->cache_sta_info_list;
 
 			hdd_debug("reached max caching, removing oldest");
 
 			/* Find the oldest cached station */
-			hdd_for_each_station(adapter->cache_sta_info_list,
-					     temp_sta_info, index) {
+			hdd_for_each_sta_ref(adapter->cache_sta_info_list,
+					     temp_sta_info) {
 				if (temp_sta_info->disassoc_ts &&
 				    (!oldest_disassoc_sta_ts ||
 				    qdf_system_time_after(
@@ -1576,6 +1577,8 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 					oldest_disassoc_sta_info =
 						temp_sta_info;
 				}
+				hdd_put_sta_info_ref(sta_list, &temp_sta_info,
+						     true);
 			}
 
 			/* Remove the oldest and store the current */
@@ -1585,8 +1588,8 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 					    cache_sta_info);
 		}
 	} else {
-		hdd_put_sta_info(&adapter->cache_sta_info_list,
-				 &cache_sta_info, true);
+		hdd_put_sta_info_ref(&adapter->cache_sta_info_list,
+				     &cache_sta_info, true);
 	}
 
 	hdd_debug("cap %d %d %d %d %d %d %d %d %d %x %d",
@@ -1608,7 +1611,7 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 		  stainfo->rx_mcs_map,
 		  stainfo->tx_mcs_map);
 exit:
-	hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 	return;
 }
 
@@ -1798,7 +1801,6 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 	int ret = 0;
 	tSap_StationDisassocCompleteEvent *disassoc_comp;
 	struct hdd_station_info *stainfo, *cache_stainfo;
-	uint8_t index = 0;
 	mac_handle_t mac_handle;
 	struct sap_config *sap_config;
 
@@ -2287,18 +2289,6 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 		if (QDF_IS_STATUS_SUCCESS(qdf_status))
 			hdd_fill_station_info(adapter, event);
 
-		stainfo = hdd_get_sta_info_by_mac(
-					&adapter->sta_info_list,
-					(uint8_t *)&wrqu.addr.sa_data);
-
-		if (stainfo) {
-			stainfo->ecsa_capable = event->ecsa_capable;
-			hdd_put_sta_info(&adapter->sta_info_list, &stainfo,
-					 true);
-		} else {
-			hdd_err("Station not found");
-		}
-
 		if (ucfg_ipa_is_enabled()) {
 			status = ucfg_ipa_wlan_evt(hdd_ctx->pdev,
 						   adapter->dev,
@@ -2400,8 +2390,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 				  cache_stainfo->tx_rate,
 				  cache_stainfo->rx_rate,
 				  cache_stainfo->reason_code);
-			hdd_put_sta_info(&adapter->cache_sta_info_list,
-					 &cache_stainfo, true);
+			hdd_put_sta_info_ref(&adapter->cache_sta_info_list,
+					     &cache_stainfo, true);
 		}
 		hdd_nofl_info("SAP disassociated " QDF_MAC_ADDR_STR,
 			      QDF_MAC_ADDR_ARRAY(wrqu.addr.sa_data));
@@ -2438,18 +2428,21 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 					  WMA_DHCP_STOP_IND);
 		stainfo->dhcp_nego_status = DHCP_NEGO_STOP;
 
-		hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 		hdd_softap_deregister_sta(adapter, &stainfo);
 
 		ap_ctx->ap_active = false;
 
-		hdd_for_each_station(adapter->sta_info_list, stainfo,
-				     index) {
+		hdd_for_each_sta_ref(adapter->sta_info_list, stainfo) {
 			if (!qdf_is_macaddr_broadcast(
 			    &stainfo->sta_mac)) {
 				ap_ctx->ap_active = true;
+				hdd_put_sta_info_ref(&adapter->sta_info_list,
+						     &stainfo, true);
 				break;
 			}
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &stainfo, true);
 		}
 
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
@@ -6770,10 +6763,8 @@ int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy,
 void hdd_sap_indicate_disconnect_for_sta(struct hdd_adapter *adapter)
 {
 	struct sap_event sap_event;
-	uint8_t index = 0;
 	struct sap_context *sap_ctx;
-	struct hdd_station_info *sta_info;
-	struct hdd_sta_info_entry *tmp;
+	struct hdd_station_info *sta_info, *tmp = NULL;
 
 	hdd_enter();
 
@@ -6783,13 +6774,14 @@ void hdd_sap_indicate_disconnect_for_sta(struct hdd_adapter *adapter)
 		return;
 	}
 
-	hdd_for_each_station_safe(adapter->sta_info_list, sta_info, index,
-				  tmp) {
+	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp) {
 		hdd_debug("sta_mac: " QDF_MAC_ADDR_STR,
 			  QDF_MAC_ADDR_ARRAY(sta_info->sta_mac.bytes));
 
 		if (qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
 			hdd_softap_deregister_sta(adapter, &sta_info);
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta_info, true);
 			continue;
 		}
 
@@ -6804,6 +6796,7 @@ void hdd_sap_indicate_disconnect_for_sta(struct hdd_adapter *adapter)
 		sap_event.sapevt.sapStationDisassocCompleteEvent.status_code =
 				QDF_STATUS_E_RESOURCES;
 		hdd_hostapd_sap_event_cb(&sap_event, sap_ctx->user_context);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 	hdd_exit();
@@ -6812,7 +6805,6 @@ void hdd_sap_indicate_disconnect_for_sta(struct hdd_adapter *adapter)
 bool hdd_is_peer_associated(struct hdd_adapter *adapter,
 			    struct qdf_mac_addr *mac_addr)
 {
-	uint8_t index = 0;
 	bool is_associated = false;
 	struct hdd_station_info *sta_info;
 
@@ -6821,12 +6813,15 @@ bool hdd_is_peer_associated(struct hdd_adapter *adapter,
 		return false;
 	}
 
-	hdd_for_each_station(adapter->sta_info_list, sta_info, index) {
+	hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 		if (!qdf_mem_cmp(&sta_info->sta_mac, mac_addr,
 				 QDF_MAC_ADDR_SIZE)) {
 			is_associated = true;
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta_info, true);
 			break;
 		}
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 	return is_associated;

+ 20 - 11
core/hdd/src/wlan_hdd_hostapd_wext.c

@@ -144,7 +144,6 @@ static int __iw_softap_set_two_ints_getnone(struct net_device *dev,
 	struct hdd_context *hdd_ctx;
 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
 	struct cdp_txrx_stats_req req = {0};
-	uint8_t index = 0;
 	struct hdd_station_info *sta_info;
 
 	hdd_enter_dev(dev);
@@ -176,8 +175,7 @@ static int __iw_softap_set_two_ints_getnone(struct net_device *dev,
 			ret = cdp_txrx_stats_request(soc, adapter->vdev_id,
 						     &req);
 
-			hdd_for_each_station(adapter->sta_info_list, sta_info,
-					     index) {
+			hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 				hdd_debug("bss_id: " QDF_MAC_ADDR_STR,
 					  QDF_MAC_ADDR_ARRAY(
 					  sta_info->sta_mac.bytes));
@@ -186,6 +184,8 @@ static int __iw_softap_set_two_ints_getnone(struct net_device *dev,
 					&sta_info->sta_mac;
 				ret = cdp_txrx_stats_request(
 					soc, adapter->vdev_id, &req);
+				hdd_put_sta_info_ref(&adapter->sta_info_list,
+						     &sta_info, true);
 			}
 		} else {
 			ret = cdp_txrx_stats_request(soc, adapter->vdev_id,
@@ -1682,7 +1682,6 @@ static __iw_softap_getassoc_stamacaddr(struct net_device *dev,
 	struct hdd_station_info *sta_info;
 	struct hdd_context *hdd_ctx;
 	char *buf;
-	int index = 0;
 	int left;
 	int ret;
 	/* maclist_index must be u32 to match userspace */
@@ -1729,13 +1728,14 @@ static __iw_softap_getassoc_stamacaddr(struct net_device *dev,
 	maclist_index = sizeof(maclist_index);
 	left = wrqu->data.length - maclist_index;
 
-	hdd_for_each_station(adapter->sta_info_list, sta_info, index) {
+	hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 		if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
 			memcpy(&buf[maclist_index], &sta_info->sta_mac,
 			       QDF_MAC_ADDR_SIZE);
 			maclist_index += QDF_MAC_ADDR_SIZE;
 			left -= QDF_MAC_ADDR_SIZE;
 		}
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 	*((u32 *) buf) = maclist_index;
@@ -2221,7 +2221,6 @@ static int hdd_softap_get_sta_info(struct hdd_adapter *adapter,
 				   uint8_t *buf,
 				   int size)
 {
-	uint8_t index = 0;
 	int written;
 	struct hdd_station_info *sta;
 
@@ -2229,12 +2228,18 @@ static int hdd_softap_get_sta_info(struct hdd_adapter *adapter,
 
 	written = scnprintf(buf, size, "\nstaId staAddress\n");
 
-	hdd_for_each_station(adapter->sta_info_list, sta, index) {
-		if (written >= size - 1)
+	hdd_for_each_sta_ref(adapter->sta_info_list, sta) {
+		if (written >= size - 1) {
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta, true);
 			break;
+		}
 
-		if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes))
+		if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) {
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta, true);
 			continue;
+		}
 
 		written += scnprintf(buf + written, size - written,
 				     QDF_MAC_ADDR_STR
@@ -2246,6 +2251,7 @@ static int hdd_softap_get_sta_info(struct hdd_adapter *adapter,
 				     sta->sta_mac.bytes[4],
 				     sta->sta_mac.bytes[5],
 				     sta->ecsa_capable);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true);
 	}
 
 	hdd_exit();
@@ -2448,7 +2454,6 @@ int __iw_get_softap_linkspeed(struct net_device *dev,
 	char macaddr_string[MAC_ADDRESS_STR_LEN + 1];
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	int rc, ret;
-	uint8_t index = 0;
 
 	hdd_enter_dev(dev);
 
@@ -2490,13 +2495,17 @@ int __iw_get_softap_linkspeed(struct net_device *dev,
 	if (wrqu->data.length < 17 || !QDF_IS_STATUS_SUCCESS(status)) {
 		struct hdd_station_info *sta_info;
 
-		hdd_for_each_station(adapter->sta_info_list, sta_info, index) {
+		hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 			if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
 				qdf_copy_macaddr(&mac_address,
 						 &sta_info->sta_mac);
 				status = QDF_STATUS_SUCCESS;
+				hdd_put_sta_info_ref(&adapter->sta_info_list,
+						     &sta_info, true);
 				break;
 			}
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta_info, true);
 		}
 	}
 	if (!QDF_IS_STATUS_SUCCESS(status)) {

+ 9 - 5
core/hdd/src/wlan_hdd_main.c

@@ -6644,7 +6644,7 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 		}
 
 		/* Clear all the cached sta info */
-		hdd_clear_cached_sta_info(&adapter->cache_sta_info_list);
+		hdd_clear_cached_sta_info(adapter);
 
 		/*
 		 * If Do_Not_Break_Stream was enabled clear avoid channel list.
@@ -16413,7 +16413,6 @@ static QDF_STATUS hdd_is_connection_in_progress_iterator(
 					void *ctx)
 {
 	struct hdd_station_ctx *hdd_sta_ctx;
-	uint8_t index = 0;
 	uint8_t *sta_mac;
 	struct hdd_context *hdd_ctx;
 	mac_handle_t mac_handle;
@@ -16485,11 +16484,13 @@ static QDF_STATUS hdd_is_connection_in_progress_iterator(
 		}
 	} else if ((QDF_SAP_MODE == adapter->device_mode) ||
 			(QDF_P2P_GO_MODE == adapter->device_mode)) {
-		hdd_for_each_station(adapter->sta_info_list, sta_info,
-				     index) {
+		hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) {
 			if (sta_info->peer_state !=
-				OL_TXRX_PEER_STATE_CONN)
+				OL_TXRX_PEER_STATE_CONN) {
+				hdd_put_sta_info_ref(&adapter->sta_info_list,
+						     &sta_info, true);
 				continue;
+			}
 
 			sta_mac = sta_info->sta_mac.bytes;
 			hdd_debug("client " QDF_MAC_ADDR_STR
@@ -16500,6 +16501,9 @@ static QDF_STATUS hdd_is_connection_in_progress_iterator(
 			context->out_reason = SAP_EAPOL_IN_PROGRESS;
 			context->connection_in_progress = true;
 
+			hdd_put_sta_info_ref(&adapter->sta_info_list,
+					     &sta_info, true);
+
 			return QDF_STATUS_E_ABORTED;
 		}
 		if (hdd_ctx->connection_in_progress) {

+ 17 - 19
core/hdd/src/wlan_hdd_softap_tx_rx.c

@@ -306,7 +306,7 @@ static void hdd_softap_inspect_tx_eap_pkt(struct hdd_adapter *adapter,
 				   &sta_info->pending_eap_frm_type);
 		QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(skb) = 1;
 	}
-	hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 }
 
 void hdd_softap_check_wait_for_tx_eap_pkt(struct hdd_adapter *adapter,
@@ -336,7 +336,7 @@ void hdd_softap_check_wait_for_tx_eap_pkt(struct hdd_adapter *adapter,
 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 			hdd_debug("eap_failure tx timeout");
 	}
-	hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 }
 
 #ifdef SAP_DHCP_FW_IND
@@ -489,7 +489,8 @@ int hdd_softap_inspect_dhcp_packet(struct hdd_adapter *adapter,
 		hdd_debug("EXIT: phase=%d, nego_status=%d",
 			  hdd_sta_info->dhcp_phase,
 			  hdd_sta_info->dhcp_nego_status);
-		hdd_put_sta_info(&adapter->sta_info_list, &hdd_sta_info, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &hdd_sta_info,
+				     true);
 	}
 
 	return errno;
@@ -708,22 +709,21 @@ static void __hdd_softap_hard_start_xmit(struct sk_buff *skb,
 	netif_trans_update(dev);
 
 	wlan_hdd_sar_unsolicited_timer_start(hdd_ctx);
-	hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 
 	return;
 
 drop_pkt_and_release_skb:
 	qdf_net_buf_debug_release_skb(skb);
 drop_pkt:
-	if (sta_info)
-		hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
-
 	qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID,
 			      QDF_DP_TRACE_DROP_PACKET_RECORD, 0,
 			      QDF_TX);
 	kfree_skb(skb);
 
 drop_pkt_accounting:
+	if (sta_info)
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	++adapter->stats.tx_dropped;
 	++adapter->hdd_stats.tx_rx_stats.tx_dropped;
 }
@@ -849,9 +849,9 @@ QDF_STATUS hdd_softap_init_tx_rx_sta(struct hdd_adapter *adapter,
 					   sta_mac->bytes);
 
 	if (sta_info) {
-		hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
 		hdd_err("Reinit of in use station " QDF_MAC_ADDR_STR,
 			QDF_MAC_ADDR_ARRAY(sta_mac->bytes));
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -999,8 +999,8 @@ QDF_STATUS hdd_softap_rx_packet_cbk(void *adapter_context, qdf_nbuf_t rx_buf)
 			sta_info->rx_bytes += skb->len;
 			sta_info->last_tx_rx_ts = qdf_system_ticks();
 			hdd_softap_inspect_dhcp_packet(adapter, skb, QDF_RX);
-			hdd_put_sta_info(&adapter->sta_info_list, &sta_info,
-					 true);
+			hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info,
+					     true);
 		}
 
 		hdd_event_eapol_log(skb, QDF_RX);
@@ -1131,7 +1131,7 @@ QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter,
 		hdd_debug("clean up old entry for STA MAC " QDF_MAC_ADDR_STR,
 			  QDF_MAC_ADDR_ARRAY(sta_mac->bytes));
 		hdd_softap_deregister_sta(adapter, &sta_info);
-		hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 	/*
@@ -1182,7 +1182,7 @@ QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter,
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
 		hdd_debug("cdp_peer_register() failed to register.  Status = %d [0x%08X]",
 			  qdf_status, qdf_status);
-		hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 		return qdf_status;
 	}
 
@@ -1226,7 +1226,7 @@ QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter,
 		sta_info->peer_state = OL_TXRX_PEER_STATE_CONN;
 	}
 
-	hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	hdd_debug("Enabling queues");
 	wlan_hdd_netif_queue_control(adapter,
 				   WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
@@ -1270,9 +1270,7 @@ QDF_STATUS hdd_softap_stop_bss(struct hdd_adapter *adapter)
 	uint8_t indoor_chnl_marking = 0;
 	struct hdd_context *hdd_ctx;
 	struct hdd_ap_ctx *ap_ctx;
-	uint16_t index;
-	struct hdd_station_info *sta_info;
-	struct hdd_sta_info_entry *tmp;
+	struct hdd_station_info *sta_info, *tmp = NULL;
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
@@ -1286,9 +1284,9 @@ QDF_STATUS hdd_softap_stop_bss(struct hdd_adapter *adapter)
 	 * object leak
 	 */
 
-	hdd_for_each_station_safe(adapter->sta_info_list, sta_info,
-				  index, tmp) {
+	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp) {
 		status = hdd_softap_deregister_sta(adapter, &sta_info);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	}
 
 	if (adapter->device_mode == QDF_SAP_MODE &&
@@ -1350,7 +1348,7 @@ QDF_STATUS hdd_softap_change_sta_state(struct hdd_adapter *adapter,
 		p2p_peer_authorized(adapter->vdev, sta_mac->bytes);
 	}
 
-	hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true);
 	hdd_exit();
 	return qdf_status;
 }

+ 89 - 26
core/hdd/src/wlan_hdd_sta_info.c

@@ -23,12 +23,10 @@
  *
  */
 
-#include "wlan_hdd_sta_info.h"
 #include <wlan_hdd_includes.h>
+#include "wlan_hdd_sta_info.h"
 
-/* Generate a numeric constant to form the key to be provided for hashing */
-#define WLAN_HDD_STA_INFO_HASH(addr) \
-	(((const uint8_t *)addr)[QDF_MAC_ADDR_SIZE - 1])
+#define HDD_MAX_PEERS 32
 
 QDF_STATUS hdd_sta_info_init(struct hdd_sta_info_obj *sta_info_container)
 {
@@ -38,7 +36,7 @@ QDF_STATUS hdd_sta_info_init(struct hdd_sta_info_obj *sta_info_container)
 	}
 
 	qdf_spinlock_create(&sta_info_container->sta_obj_lock);
-	qdf_ht_init(sta_info_container->sta_obj);
+	qdf_list_create(&sta_info_container->sta_obj, HDD_MAX_PEERS);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -50,7 +48,7 @@ void hdd_sta_info_deinit(struct hdd_sta_info_obj *sta_info_container)
 		return;
 	}
 
-	qdf_ht_deinit(sta_info_container->sta_obj);
+	qdf_list_destroy(&sta_info_container->sta_obj);
 	qdf_spinlock_destroy(&sta_info_container->sta_obj_lock);
 }
 
@@ -65,8 +63,8 @@ QDF_STATUS hdd_sta_info_attach(struct hdd_sta_info_obj *sta_info_container,
 	qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
 
 	qdf_atomic_set(&sta_info->ref_cnt, 1);
-	qdf_ht_add(sta_info_container->sta_obj, &sta_info->sta_node,
-		   WLAN_HDD_STA_INFO_HASH(sta_info->sta_mac.bytes));
+	qdf_list_insert_front(&sta_info_container->sta_obj,
+			      &sta_info->sta_node);
 
 	qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
 
@@ -90,8 +88,7 @@ void hdd_sta_info_detach(struct hdd_sta_info_obj *sta_info_container,
 
 	qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
 
-	qdf_ht_remove(&(info->sta_node));
-	hdd_put_sta_info(sta_info_container, sta_info, false);
+	hdd_put_sta_info_ref(sta_info_container, sta_info, false);
 
 	qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
 }
@@ -109,11 +106,11 @@ struct hdd_station_info *hdd_get_sta_info_by_mac(
 
 	qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
 
-	qdf_ht_for_each_in_bucket(sta_info_container->sta_obj, sta_info,
-				  sta_node, WLAN_HDD_STA_INFO_HASH(mac_addr)) {
+	qdf_list_for_each(&sta_info_container->sta_obj, sta_info, sta_node) {
 		if (qdf_is_macaddr_equal(&sta_info->sta_mac,
 					 (struct qdf_mac_addr *)mac_addr)) {
-			qdf_atomic_inc(&sta_info->ref_cnt);
+			hdd_take_sta_info_ref(sta_info_container,
+					      sta_info, false);
 			qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
 			return sta_info;
 		}
@@ -124,8 +121,27 @@ struct hdd_station_info *hdd_get_sta_info_by_mac(
 	return NULL;
 }
 
-void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
-		      struct hdd_station_info **sta_info, bool lock_required)
+void hdd_take_sta_info_ref(struct hdd_sta_info_obj *sta_info_container,
+			   struct hdd_station_info *sta_info,
+			   bool lock_required)
+{
+	if (!sta_info_container || !sta_info) {
+		hdd_err("Parameter(s) null");
+		return;
+	}
+
+	if (lock_required)
+		qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
+
+	qdf_atomic_inc(&sta_info->ref_cnt);
+
+	if (lock_required)
+		qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
+}
+
+void
+hdd_put_sta_info_ref(struct hdd_sta_info_obj *sta_info_container,
+		     struct hdd_station_info **sta_info, bool lock_required)
 {
 	struct hdd_station_info *info;
 
@@ -136,8 +152,10 @@ void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
 
 	info = *sta_info;
 
-	if (!info)
+	if (!info) {
+		hdd_err("station info NULL");
 		return;
+	}
 
 	if (lock_required)
 		qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
@@ -156,6 +174,7 @@ void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
 		info->assoc_req_ies.len = 0;
 	}
 
+	qdf_list_remove_node(&sta_info_container->sta_obj, &info->sta_node);
 	qdf_mem_free(info);
 	*sta_info = NULL;
 
@@ -163,21 +182,65 @@ void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
 		qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
 }
 
-void hdd_clear_cached_sta_info(struct hdd_sta_info_obj *sta_info_container)
+void hdd_clear_cached_sta_info(struct hdd_adapter *adapter)
 {
-	struct hdd_station_info *sta_info = NULL;
-	uint8_t index = 0;
-	struct qdf_ht_entry *tmp;
+	struct hdd_station_info *sta_info = NULL, *tmp = NULL;
 
-	if (!sta_info_container) {
+	if (!adapter) {
 		hdd_err("Parameter null");
 		return;
 	}
 
-	qdf_ht_for_each_safe(sta_info_container->sta_obj, index, tmp, sta_info,
-			     sta_node) {
-		if (sta_info) {
-			hdd_sta_info_detach(sta_info_container, &sta_info);
-		}
+	hdd_for_each_sta_ref_safe(adapter->cache_sta_info_list, sta_info, tmp) {
+		hdd_sta_info_detach(&adapter->cache_sta_info_list, &sta_info);
+		hdd_put_sta_info_ref(&adapter->cache_sta_info_list, &sta_info,
+				     true);
 	}
 }
+
+QDF_STATUS
+hdd_get_front_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container,
+			       struct hdd_station_info **out_sta_info)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *node;
+
+	*out_sta_info = NULL;
+
+	status = qdf_list_peek_front(&sta_info_container->sta_obj, &node);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	*out_sta_info =
+		qdf_container_of(node, struct hdd_station_info, sta_node);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+hdd_get_next_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container,
+			      struct hdd_station_info *current_sta_info,
+			      struct hdd_station_info **out_sta_info)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *node;
+
+	if (!current_sta_info)
+		return QDF_STATUS_E_INVAL;
+
+	*out_sta_info = NULL;
+
+	status = qdf_list_peek_next(&sta_info_container->sta_obj,
+				    &current_sta_info->sta_node,
+				    &node);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	*out_sta_info =
+		qdf_container_of(node, struct hdd_station_info, sta_node);
+
+	return QDF_STATUS_SUCCESS;
+}
+

+ 180 - 35
core/hdd/src/wlan_hdd_sta_info.h

@@ -25,20 +25,18 @@
 #if !defined(__WLAN_HDD_STA_INFO_H)
 #define __WLAN_HDD_STA_INFO_H
 
+#include <wlan_hdd_main.h>
 #include "qdf_lock.h"
 #include "qdf_types.h"
-#include "qdf_hashtable.h"
+#include "qdf_list.h"
 #include "sap_api.h"
 #include "cdp_txrx_cmn_struct.h"
 #include "sir_mac_prot_def.h"
 #include <linux/ieee80211.h>
 #include <wlan_mlme_public_struct.h>
 
-/* A bucket size of 2^4 = 16 */
-#define WLAN_HDD_STA_INFO_SIZE 4
-
 /* Opaque handle for abstraction */
-#define hdd_sta_info_entry qdf_ht_entry
+#define hdd_sta_info_entry qdf_list_node_t
 
 /**
  * struct dhcp_phase - Per Peer DHCP Phases
@@ -177,7 +175,7 @@ struct hdd_station_info {
 	uint8_t support_mode;
 	uint32_t rx_retry_cnt;
 	uint32_t rx_mc_bc_cnt;
-	struct qdf_ht_entry sta_node;
+	qdf_list_node_t sta_node;
 	struct wlan_ies assoc_req_ies;
 	qdf_atomic_t ref_cnt;
 	unsigned long pending_eap_frm_type;
@@ -189,41 +187,199 @@ struct hdd_station_info {
  * @sta_obj_lock: Lock to protect the sta_obj read/write access
  */
 struct hdd_sta_info_obj {
-	qdf_ht_declare(sta_obj, WLAN_HDD_STA_INFO_SIZE);
+	qdf_list_t sta_obj;
 	qdf_spinlock_t sta_obj_lock;
 };
 
 /**
- * hdd_for_each_station - Iterate over each station stored in the sta info
- *                        container
+ * hdd_put_sta_info_ref() - Release sta_info ref for synchronization
+ * @sta_info_container: The station info container obj that stores and maintains
+ *                      the sta_info obj.
+ * @sta_info: Station info structure to be released.
+ *
+ * Return: None
+ */
+void hdd_put_sta_info_ref(struct hdd_sta_info_obj *sta_info_container,
+			  struct hdd_station_info **sta_info,
+			  bool lock_required);
+
+/**
+ * hdd_take_sta_info_ref() - Increment sta info ref.
+ * @sta_info_container: The station info container obj that stores and maintains
+ *                      the sta_info obj.
+ * @sta_info: Station info structure to be released.
+ *
+ * This function has to be accompanied by hdd_put_sta_info when the work with
+ * the sta info is done. Failure to do so will result in a mem leak.
+ *
+ * Return: None
+ */
+void hdd_take_sta_info_ref(struct hdd_sta_info_obj *sta_info_container,
+			   struct hdd_station_info *sta_info,
+			   bool lock_required);
+
+/**
+ * hdd_get_front_sta_info_no_lock() - Get the first sta_info from the sta list
+ * This API doesnot use any lock in it's implementation. It is the caller's
+ * directive to ensure concurrency safety.
+ *
+ * @sta_info_container: The station info container obj that stores and maintains
+ *                      the sta_info obj.
+ * @out_sta_info: The station info structure that acts as the container object.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+hdd_get_front_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container,
+			       struct hdd_station_info **out_sta_info);
+
+/**
+ * hdd_get_next_sta_info_no_lock() - Get the next sta_info from the sta list
+ * This API doesnot use any lock in it's implementation. It is the caller's
+ * directive to ensure concurrency safety.
+ *
+ * @sta_info_container: The station info container obj that stores and maintains
+ *                      the sta_info obj.
+ * @out_sta_info: The station info structure that acts as the container object.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+hdd_get_next_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container,
+			      struct hdd_station_info *current_sta_info,
+			      struct hdd_station_info **out_sta_info);
+
+/* Abstract wrapper to check sta_info validity */
+#define __hdd_is_station_valid(sta_info) sta_info
+
+/**
+ * __hdd_take_ref_and_fetch_front_sta_info - Helper macro to lock, fetch front
+ * sta_info, take ref and unlock.
+ * @sta_info_container: The station info container obj that stores and maintains
+ *                      the sta_info obj.
+ * @sta_info: The station info structure that acts as the iterator object.
+ */
+#define __hdd_take_ref_and_fetch_front_sta_info(sta_info_container, sta_info) \
+	qdf_spin_lock_bh(&sta_info_container.sta_obj_lock), \
+	hdd_get_front_sta_info_no_lock(&sta_info_container, &sta_info), \
+	(sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \
+					   sta_info, false) : (false), \
+	qdf_spin_unlock_bh(&sta_info_container.sta_obj_lock)
+
+/**
+ * __hdd_take_ref_and_fetch_next_sta_info - Helper macro to lock, fetch next
+ * sta_info, take ref and unlock.
+ * @sta_info_container: The station info container obj that stores and maintains
+ *                      the sta_info obj.
+ * @sta_info: The station info structure that acts as the iterator object.
+ */
+#define __hdd_take_ref_and_fetch_next_sta_info(sta_info_container, sta_info) \
+	qdf_spin_lock_bh(&sta_info_container.sta_obj_lock), \
+	hdd_get_next_sta_info_no_lock(&sta_info_container, sta_info, \
+				      &sta_info), \
+	(sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \
+					   sta_info, false) : (false), \
+	qdf_spin_unlock_bh(&sta_info_container.sta_obj_lock)
+
+/**
+ * hdd_for_each_sta_ref - Iterate over each station stored in the sta info
+ *                        container with ref taken
  * @sta_info_container: The station info container obj that stores and maintains
  *                      the sta_info obj.
  * @sta_info: The station info structure that acts as the iterator object.
- * @index: The current index in which the current station is present.
  *
  * The sta_info will contain the structure that is fetched for that particular
- * iteration. The index of the current iterator object in the container
- * represents the bucket at which the given station info is stored.
+ * iteration.
+ *
+ *			     ***** NOTE *****
+ * Before the end of each iteration, dev_put(adapter->dev) must be
+ * called. Not calling this will keep hold of a reference, thus preventing
+ * unregister of the netdevice.
+ *
+ * Usage example:
+ *	    hdd_for_each_sta_ref(sta_info_container, sta_info) {
+ *		    <work involving station>
+ *		    <some more work>
+ *		    hdd_put_sta_info_ref(sta_info_container, sta_info, true)
+ *	    }
  */
-#define hdd_for_each_station(sta_info_container, sta_info, index) \
-	  qdf_ht_for_each(sta_info_container.sta_obj, index, sta_info, sta_node)
+#define hdd_for_each_sta_ref(sta_info_container, sta_info) \
+	for (__hdd_take_ref_and_fetch_front_sta_info(sta_info_container, \
+						     sta_info); \
+	     __hdd_is_station_valid(sta_info); \
+	     __hdd_take_ref_and_fetch_next_sta_info(sta_info_container, \
+						    sta_info))
 
 /**
- * hdd_for_each_station_safe - Iterate over each station stored in the sta info
- *                           container being safe for removal of the sta info
+ * __hdd_take_ref_and_fetch_front_sta_info_safe - Helper macro to lock, fetch
+ * front sta_info, take ref and unlock in a delete safe manner.
+ * @sta_info_container: The station info container obj that stores and maintains
+ *			the sta_info obj.
+ * @sta_info: The station info structure that acts as the iterator object.
+ */
+#define __hdd_take_ref_and_fetch_front_sta_info_safe(sta_info_container, \
+						     sta_info, next_sta_info) \
+	qdf_spin_lock_bh(&sta_info_container.sta_obj_lock), \
+	hdd_get_front_sta_info_no_lock(&sta_info_container, &sta_info), \
+	(sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \
+					   sta_info, false) : (false), \
+	hdd_get_next_sta_info_no_lock(&sta_info_container, sta_info, \
+				      &next_sta_info), \
+	(next_sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \
+						next_sta_info, false) : \
+						(false), \
+	qdf_spin_unlock_bh(&sta_info_container.sta_obj_lock)
+
+/**
+ * __hdd_take_ref_and_fetch_next_sta_info_safe - Helper macro to lock, fetch
+ * next sta_info, take ref and unlock.
+ * @sta_info_container: The station info container obj that stores and maintains
+ *			the sta_info obj.
+ * @sta_info: The station info structure that acts as the iterator object.
+ */
+#define __hdd_take_ref_and_fetch_next_sta_info_safe(sta_info_container, \
+						    sta_info, next_sta_info) \
+	sta_info = next_sta_info, \
+	qdf_spin_lock_bh(&sta_info_container.sta_obj_lock), \
+	hdd_get_next_sta_info_no_lock(&sta_info_container, sta_info, \
+				      &next_sta_info), \
+	(next_sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \
+					     next_sta_info, false) : (false), \
+	qdf_spin_unlock_bh(&sta_info_container.sta_obj_lock)
+
+/**
+ * hdd_for_each_sta_ref_safe - Iterate over each station stored in the sta info
+ *                             container in a delete safe manner
  * @sta_info_container: The station info container obj that stores and maintains
  *                      the sta_info obj.
  * @sta_info: The station info structure that acts as the iterator object.
- * @index: The current index in which the current station is present.
- * @tmp: A &struct for temporary storage
+ * @next_sta_info: A temporary node for maintaing del safe.
  *
  * The sta_info will contain the structure that is fetched for that particular
- * iteration. The index of the current iterator object in the container
- * represents the bucket at which the given station info is stored.
+ * iteration. The next_sta_info is used to store the next station before the
+ * current station is deleted so as to provide a safe way to iterate the list
+ * while deletion is undergoing.
+ *
+ *			     ***** NOTE *****
+ * Before the end of each iteration, hdd_put_sta_info_ref must be
+ * called. Not calling this will keep hold of a reference, thus preventing
+ * deletion of the station info
+ *
+ * Usage example:
+ *	hdd_for_each_sta_ref_safe(sta_info_container, sta_info, next_sta_info) {
+ *		<work involving station>
+ *		<some more work>
+ *		hdd_put_sta_info_ref(sta_info_container, sta_info, true)
+ *	}
  */
-#define hdd_for_each_station_safe(sta_info_container, sta_info, index, tmp) \
-	qdf_ht_for_each_safe(sta_info_container.sta_obj, index, tmp, \
-			     sta_info, sta_node)
+#define hdd_for_each_sta_ref_safe(sta_info_container, sta_info, next_sta_info) \
+	for (__hdd_take_ref_and_fetch_front_sta_info_safe(sta_info_container, \
+							  sta_info, \
+							  next_sta_info); \
+	     __hdd_is_station_valid(sta_info); \
+	     __hdd_take_ref_and_fetch_next_sta_info_safe(sta_info_container, \
+							 sta_info, \
+							 next_sta_info))
 
 /**
  * wlan_sta_info_init() - Initialise the wlan hdd station info container obj
@@ -280,17 +436,6 @@ struct hdd_station_info *hdd_get_sta_info_by_mac(
 				struct hdd_sta_info_obj *sta_info_container,
 				const uint8_t *mac_addr);
 
-/**
- * hdd_put_sta_info() - Release sta_info for synchronization
- * @sta_info_container: The station info container obj that stores and maintains
- *                      the sta_info obj.
- * @sta_info: Station info structure to be released.
- *
- * Return: None
- */
-void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
-		      struct hdd_station_info **sta_info, bool lock_required);
-
 /**
  * hdd_clear_cached_sta_info() - Clear the cached sta info from the container
  * @sta_info_container: The station info container obj that stores and maintains
@@ -298,6 +443,6 @@ void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
  *
  * Return: None
  */
-void hdd_clear_cached_sta_info(struct hdd_sta_info_obj *sta_info_container);
+void hdd_clear_cached_sta_info(struct hdd_adapter *hdd_adapter);
 
 #endif /* __WLAN_HDD_STA_INFO_H */

+ 6 - 5
core/hdd/src/wlan_hdd_station_info.c

@@ -1104,7 +1104,8 @@ static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx,
 
 	skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
 	if (!skb) {
-		hdd_put_sta_info(&adapter->cache_sta_info_list, &stainfo, true);
+		hdd_put_sta_info_ref(&adapter->cache_sta_info_list,
+				     &stainfo, true);
 		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
 		return -ENOMEM;
 	}
@@ -1171,12 +1172,12 @@ static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx,
 		}
 	}
 	hdd_sta_info_detach(&adapter->cache_sta_info_list, &stainfo);
-	hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 	qdf_atomic_dec(&adapter->cache_sta_count);
 
 	return cfg80211_vendor_cmd_reply(skb);
 fail:
-	hdd_put_sta_info(&adapter->cache_sta_info_list, &stainfo, true);
+	hdd_put_sta_info_ref(&adapter->cache_sta_info_list, &stainfo, true);
 	if (skb)
 		kfree_skb(skb);
 
@@ -1334,13 +1335,13 @@ static int hdd_get_station_remote(struct hdd_context *hdd_ctx,
 	if (!is_associated) {
 		status = hdd_get_cached_station_remote(hdd_ctx, adapter,
 						       mac_addr);
-		hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 		return status;
 	}
 
 	status = hdd_get_connected_station_info(hdd_ctx, adapter,
 						mac_addr, stainfo);
-	hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 	return status;
 }
 

+ 2 - 2
core/hdd/src/wlan_hdd_stats.c

@@ -4143,7 +4143,7 @@ static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
 	qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
 	status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
 	if (status) {
-		hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+		hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 		hdd_err("fail to get peer info from fw");
 		return -EPERM;
 	}
@@ -4158,7 +4158,7 @@ static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
 	txrx_stats.rssi = peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
 	wlan_hdd_fill_rate_info(&txrx_stats, &peer_info);
 	wlan_hdd_fill_station_info(hddctx->psoc, sinfo, stainfo, &txrx_stats);
-	hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
+	hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true);
 
 	return status;
 }