diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index bcb0bb06b4ea..2188a906e5d8 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -21117,6 +21117,7 @@ QDF_STATUS hdd_softap_deauth_current_sta(struct hdd_adapter *adapter, qdf_event_t *disassoc_event = &hapd_state->qdf_sta_disassoc_event; struct hdd_context *hdd_ctx; QDF_STATUS qdf_status; + struct hdd_station_info *tmp = NULL; hdd_ctx = WLAN_HDD_GET_CTX(adapter); if (!hdd_ctx) { @@ -21139,7 +21140,8 @@ 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_sta_ref(adapter->sta_info_list, sta_info) { + hdd_for_each_sta_ref_safe(adapter->sta_info_list, + sta_info, tmp) { sta_info->is_deauth_in_progress = true; hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true); @@ -21178,7 +21180,7 @@ QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter, QDF_STATUS status; bool is_sap_bcast_deauth_enabled = false; struct hdd_context *hdd_ctx; - struct hdd_station_info *sta_info; + struct hdd_station_info *sta_info, *tmp = NULL; hdd_ctx = WLAN_HDD_GET_CTX(adapter); if (!hdd_ctx) { @@ -21199,7 +21201,7 @@ QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter, hapd_state, param); } - hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) { + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp) { 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)); @@ -21212,6 +21214,10 @@ QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter, if (QDF_IS_STATUS_ERROR(status)) { hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true); return status; } } diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index c3c0d35ff080..cac0768d6e42 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -775,11 +775,11 @@ static void hdd_clear_sta(struct hdd_adapter *adapter, static void hdd_clear_all_sta(struct hdd_adapter *adapter) { - struct hdd_station_info *sta_info; + struct hdd_station_info *sta_info, *tmp = NULL; hdd_enter_dev(adapter->dev); - hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) { + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp) { hdd_clear_sta(adapter, sta_info); hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true); } @@ -1537,6 +1537,7 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter, goto exit; qdf_mem_copy(cache_sta_info, stainfo, sizeof(*cache_sta_info)); + cache_sta_info->is_attached = 0; cache_sta_info->assoc_req_ies.data = qdf_mem_malloc(event->ies_len); if (cache_sta_info->assoc_req_ies.data) { @@ -1557,15 +1558,15 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter, cache_sta_info); qdf_atomic_inc(&adapter->cache_sta_count); } else { - struct hdd_station_info *temp_sta_info; + struct hdd_station_info *temp_sta_info, *tmp = NULL; 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_sta_ref(adapter->cache_sta_info_list, - temp_sta_info) { + hdd_for_each_sta_ref_safe(adapter->cache_sta_info_list, + temp_sta_info, tmp) { if (temp_sta_info->disassoc_ts && (!oldest_disassoc_sta_ts || qdf_system_time_after( @@ -1798,7 +1799,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, tSap_StationSetKeyCompleteEvent *key_complete; int ret = 0; tSap_StationDisassocCompleteEvent *disassoc_comp; - struct hdd_station_info *stainfo, *cache_stainfo; + struct hdd_station_info *stainfo, *cache_stainfo, *tmp = NULL; mac_handle_t mac_handle; struct sap_config *sap_config; @@ -2426,12 +2427,17 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, ap_ctx->ap_active = false; - hdd_for_each_sta_ref(adapter->sta_info_list, stainfo) { + hdd_for_each_sta_ref_safe(adapter->sta_info_list, stainfo, + tmp) { if (!qdf_is_macaddr_broadcast( &stainfo->sta_mac)) { ap_ctx->ap_active = true; hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true); break; } hdd_put_sta_info_ref(&adapter->sta_info_list, @@ -6832,19 +6838,22 @@ bool hdd_is_peer_associated(struct hdd_adapter *adapter, struct qdf_mac_addr *mac_addr) { bool is_associated = false; - struct hdd_station_info *sta_info; + struct hdd_station_info *sta_info, *tmp = NULL; if (!adapter || !mac_addr) { hdd_err("Invalid adapter or mac_addr"); return false; } - hdd_for_each_sta_ref(adapter->sta_info_list, sta_info) { + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp) { 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); + if (tmp) + hdd_put_sta_info_ref(&adapter->sta_info_list, + &tmp, true); break; } hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true); diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index c053d55671aa..3127a5ee37f3 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -933,12 +933,17 @@ static QDF_STATUS hdd_sta_info_re_attach( qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); - hdd_reset_sta_info_during_reattach(sta_info); + if (sta_info->is_attached) { + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + hdd_err("sta info is alredy attached"); + return QDF_STATUS_SUCCESS; + } + hdd_reset_sta_info_during_reattach(sta_info); /* Add one extra ref for reattach */ qdf_atomic_inc(&sta_info->ref_cnt); qdf_mem_copy(&sta_info->sta_mac, sta_mac, sizeof(struct qdf_mac_addr)); - + sta_info->is_attached = true; qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); return QDF_STATUS_SUCCESS; diff --git a/core/hdd/src/wlan_hdd_sta_info.c b/core/hdd/src/wlan_hdd_sta_info.c index 98fb4dd130e8..eab8b125eda5 100644 --- a/core/hdd/src/wlan_hdd_sta_info.c +++ b/core/hdd/src/wlan_hdd_sta_info.c @@ -65,6 +65,7 @@ QDF_STATUS hdd_sta_info_attach(struct hdd_sta_info_obj *sta_info_container, qdf_atomic_set(&sta_info->ref_cnt, 1); qdf_list_insert_front(&sta_info_container->sta_obj, &sta_info->sta_node); + sta_info->is_attached = true; qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); @@ -88,7 +89,12 @@ void hdd_sta_info_detach(struct hdd_sta_info_obj *sta_info_container, qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); - hdd_put_sta_info_ref(sta_info_container, sta_info, false); + if (info->is_attached) { + info->is_attached = false; + hdd_put_sta_info_ref(sta_info_container, sta_info, false); + } else { + hdd_info("Stainfo is already detached"); + } qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); } diff --git a/core/hdd/src/wlan_hdd_sta_info.h b/core/hdd/src/wlan_hdd_sta_info.h index b34db52b6007..6971cdd2706d 100644 --- a/core/hdd/src/wlan_hdd_sta_info.h +++ b/core/hdd/src/wlan_hdd_sta_info.h @@ -128,6 +128,7 @@ enum dhcp_nego_status { * @assoc_req_ies: Assoc request IEs of the peer station * @ref_cnt: Reference count to synchronize sta_info access * @pending_eap_frm_type: EAP frame type in tx queue without tx completion + * @is_attached: Flag to check if the stainfo is attached/detached */ struct hdd_station_info { bool in_use; @@ -179,6 +180,7 @@ struct hdd_station_info { struct wlan_ies assoc_req_ies; qdf_atomic_t ref_cnt; unsigned long pending_eap_frm_type; + bool is_attached; }; /**