diff --git a/components/nan/dispatcher/inc/nan_ucfg_api.h b/components/nan/dispatcher/inc/nan_ucfg_api.h index dac07f9299..769f921d77 100644 --- a/components/nan/dispatcher/inc/nan_ucfg_api.h +++ b/components/nan/dispatcher/inc/nan_ucfg_api.h @@ -404,6 +404,20 @@ bool ucfg_nan_is_sta_nan_ndi_4_port_allowed(struct wlan_objmgr_psoc *psoc); */ QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc, uint8_t *data, uint32_t data_len); + +/** + * ucfg_nan_disable_ndi() - Disable the NDI with given vdev_id + * @psoc: pointer to psoc object + * @ndi_vdev_id: vdev_id of the NDI to be disabled + * + * Disable all the NDPs present on the given NDI by sending NDP_END_ALL + * to firmware. Firmwere sends an immediate response(NDP_HOST_UPDATE) with + * ndp_disable param as 1 followed by NDP_END indication for all the NDPs. + * + * Return: status of operation + */ +QDF_STATUS +ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id); #else /* WLAN_FEATURE_NAN */ static inline @@ -479,5 +493,12 @@ QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc, { return QDF_STATUS_SUCCESS; } + +static inline +QDF_STATUS +ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id) +{ + return QDF_STATUS_E_INVAL; +} #endif /* WLAN_FEATURE_NAN */ #endif /* _NAN_UCFG_API_H_ */ diff --git a/components/nan/dispatcher/src/nan_ucfg_api.c b/components/nan/dispatcher/src/nan_ucfg_api.c index b95a8779b7..b1bb5d2015 100644 --- a/components/nan/dispatcher/src/nan_ucfg_api.c +++ b/components/nan/dispatcher/src/nan_ucfg_api.c @@ -807,7 +807,7 @@ void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc) nan_debug("NAN Disabled successfully"); } -static QDF_STATUS +QDF_STATUS ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id) { enum nan_datapath_state curr_ndi_state; @@ -842,9 +842,12 @@ ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id) qdf_spin_lock_bh(&ndi_vdev_priv->lock); curr_ndi_state = ndi_vdev_priv->state; - /* Nothing to do if NDI is in DELETING or DATA_END state */ - if (curr_ndi_state == NAN_DATA_NDI_DELETING_STATE || - curr_ndi_state == NAN_DATA_END_STATE) { + /* + * Nothing to do if NDI is in DATA_END state. + * Continue cleanup in NAN_DATA_NDI_DELETING_STATE as this API + * can be called from hdd_ndi_delete. + */ + if (curr_ndi_state == NAN_DATA_END_STATE) { qdf_spin_unlock_bh(&ndi_vdev_priv->lock); wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID); return QDF_STATUS_SUCCESS; diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h index 56e703e263..9dce717306 100644 --- a/core/hdd/inc/wlan_hdd_assoc.h +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -496,4 +496,15 @@ void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap, */ void hdd_roam_profile_init(struct hdd_adapter *adapter); +/** + * hdd_any_valid_peer_present() - Check if any valid peer is present + * @adapter: The HDD adapter + * + * Check if there is any peer present with non-zero mac address other than + * broadcast address. + * + * Return: True if there is any valid peer present + */ +bool hdd_any_valid_peer_present(struct hdd_adapter *adapter); + #endif diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 01a010b65a..f7ddc4bbbf 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -252,6 +252,8 @@ enum hdd_adapter_flags { /* rcpi request timeout in milli seconds */ #define WLAN_WAIT_TIME_RCPI 500 +#define WLAN_WAIT_PEER_CLEANUP 5000 + #define MAX_CFG_STRING_LEN 255 /* Maximum time(ms) to wait for external acs response */ @@ -1384,6 +1386,7 @@ struct hdd_adapter { uint32_t periodic_stats_timer_counter; qdf_mutex_t sta_periodic_stats_lock; #endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ + qdf_event_t peer_cleanup_done; }; #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 5e07c3ba3f..d4d860a3b6 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -3790,6 +3790,25 @@ void hdd_delete_peer(struct hdd_station_ctx *sta_ctx, } } +bool hdd_any_valid_peer_present(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + int i; + struct qdf_mac_addr *mac_addr; + + for (i = 0; i < SIR_MAX_NUM_STA_IN_IBSS; i++) { + mac_addr = &sta_ctx->conn_info.peer_macaddr[i]; + if (!qdf_is_macaddr_zero(mac_addr) && + !qdf_is_macaddr_broadcast(mac_addr)) { + hdd_debug("peer: index: %u " QDF_MAC_ADDR_STR, i, + QDF_MAC_ADDR_ARRAY(mac_addr->bytes)); + return true; + } + } + + return false; +} + /** * roam_remove_ibss_station() - Remove the IBSS peer MAC address in the adapter * @adapter: pointer to adapter diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index f75e019d4b..aeb9d1cb93 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -6174,6 +6174,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio qdf_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT); qdf_mutex_create(&adapter->blocked_scan_request_q_lock); qdf_event_create(&adapter->acs_complete_event); + qdf_event_create(&adapter->peer_cleanup_done); hdd_sta_info_init(&adapter->sta_info_list); hdd_sta_info_init(&adapter->cache_sta_info_list); @@ -6234,6 +6235,7 @@ static void __hdd_close_adapter(struct hdd_context *hdd_ctx, qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); qdf_event_destroy(&adapter->acs_complete_event); + qdf_event_destroy(&adapter->peer_cleanup_done); hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); if (hdd_ctx->current_intf_count != 0) @@ -6347,6 +6349,28 @@ void hdd_ipa_ap_disconnect_evt(struct hdd_context *hdd_ctx, } } +static void +hdd_peer_cleanup(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + /* Check if there is any peer present on the adapter */ + if (!hdd_any_valid_peer_present(adapter)) + return; + + if (adapter->device_mode == QDF_NDI_MODE) + qdf_status = ucfg_nan_disable_ndi(hdd_ctx->psoc, + adapter->vdev_id); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + qdf_status = qdf_wait_for_event_completion(&adapter->peer_cleanup_done, + WLAN_WAIT_PEER_CLEANUP); + if (QDF_IS_STATUS_ERROR(qdf_status)) + hdd_debug("peer_cleanup_done wait fail"); +} + QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter) { @@ -6401,13 +6425,14 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, reason = eSIR_MAC_DEVICE_RECOVERY; /* For NDI do not use roam_profile */ - if (adapter->device_mode == QDF_NDI_MODE) + if (adapter->device_mode == QDF_NDI_MODE) { + hdd_peer_cleanup(hdd_ctx, adapter); status = sme_roam_disconnect( mac_handle, adapter->vdev_id, eCSR_DISCONNECT_REASON_NDI_DELETE, reason); - else if (roam_profile->BSSType == + } else if (roam_profile->BSSType == eCSR_BSS_TYPE_START_IBSS) status = sme_roam_disconnect( mac_handle, diff --git a/core/hdd/src/wlan_hdd_nan_datapath.c b/core/hdd/src/wlan_hdd_nan_datapath.c index cc1273f196..10ad9901c8 100644 --- a/core/hdd/src/wlan_hdd_nan_datapath.c +++ b/core/hdd/src/wlan_hdd_nan_datapath.c @@ -957,5 +957,6 @@ void hdd_ndp_peer_departed_handler(uint8_t vdev_id, uint16_t sta_id, if (last_peer) { hdd_debug("No more ndp peers."); hdd_cleanup_ndi(hdd_ctx, adapter); + qdf_event_set(&adapter->peer_cleanup_done); } }