qcacld-3.0: Delete all NDP peers when NDI is removed

When NDI is removed from framework, driver deletes all NDPs
as part of eWNI_SME_STOP_BSS_REQ. Driver posts WMA_DELETE_STA_RSP
to lim from wma just after sending PEER_DELETE request to
firmware for NDP and ignores the DEL_STA response from firmware.
If there are multiple peers, all peer delete requests are sent
back to back to firmware. NDI peer delete and NDI VDEV delete
request also follow these immediately. All these commands
can go back to back to firmware as driver doesn't wait for
any of these responses.
But firmware needs some time to send NDP end frame to
the NDP peer after receiving NDP peer delete. Firmware might hold
the NDP peer delete request till it successfully sends the frame
to the peer.
Driver must wait till the NDP peer delete response is received to
proceed further with NDI cleanup/NDI vdev delete.
So, send NDP_END_ALL to firmware to let the firmware
initiate cleanup for all NDP peers. Use ucfg_nan_disable_ndi to
do the same which takes care of waiting for response from firmware
indicating cleanup has started. Then wait for all NDP END
indications and unblock the wait upon receiving last NDP END
indication.

Change-Id: I250883b3e9759ad903c3ce17f8c2c0b74a81f496
CRs-Fixed: 2619757
This commit is contained in:
Srinivas Dasari 2020-04-21 20:06:14 +05:30 committed by nshrivas
parent 5649248252
commit 9a0ed3383c
7 changed files with 89 additions and 6 deletions

View File

@ -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, QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc,
uint8_t *data, uint32_t data_len); 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 */ #else /* WLAN_FEATURE_NAN */
static inline static inline
@ -479,5 +493,12 @@ QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc,
{ {
return QDF_STATUS_SUCCESS; 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 /* WLAN_FEATURE_NAN */
#endif /* _NAN_UCFG_API_H_ */ #endif /* _NAN_UCFG_API_H_ */

View File

@ -807,7 +807,7 @@ void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc)
nan_debug("NAN Disabled successfully"); nan_debug("NAN Disabled successfully");
} }
static QDF_STATUS QDF_STATUS
ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id) ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id)
{ {
enum nan_datapath_state curr_ndi_state; 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); qdf_spin_lock_bh(&ndi_vdev_priv->lock);
curr_ndi_state = ndi_vdev_priv->state; 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 || * Nothing to do if NDI is in DATA_END state.
curr_ndi_state == NAN_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); qdf_spin_unlock_bh(&ndi_vdev_priv->lock);
wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID); wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID);
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;

View File

@ -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); 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 #endif

View File

@ -252,6 +252,8 @@ enum hdd_adapter_flags {
/* rcpi request timeout in milli seconds */ /* rcpi request timeout in milli seconds */
#define WLAN_WAIT_TIME_RCPI 500 #define WLAN_WAIT_TIME_RCPI 500
#define WLAN_WAIT_PEER_CLEANUP 5000
#define MAX_CFG_STRING_LEN 255 #define MAX_CFG_STRING_LEN 255
/* Maximum time(ms) to wait for external acs response */ /* Maximum time(ms) to wait for external acs response */
@ -1384,6 +1386,7 @@ struct hdd_adapter {
uint32_t periodic_stats_timer_counter; uint32_t periodic_stats_timer_counter;
qdf_mutex_t sta_periodic_stats_lock; qdf_mutex_t sta_periodic_stats_lock;
#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ #endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
qdf_event_t peer_cleanup_done;
}; };
#define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station) #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)

View File

@ -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 * roam_remove_ibss_station() - Remove the IBSS peer MAC address in the adapter
* @adapter: pointer to adapter * @adapter: pointer to adapter

View File

@ -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_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT);
qdf_mutex_create(&adapter->blocked_scan_request_q_lock); qdf_mutex_create(&adapter->blocked_scan_request_q_lock);
qdf_event_create(&adapter->acs_complete_event); 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->sta_info_list);
hdd_sta_info_init(&adapter->cache_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); qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock);
policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode);
qdf_event_destroy(&adapter->acs_complete_event); qdf_event_destroy(&adapter->acs_complete_event);
qdf_event_destroy(&adapter->peer_cleanup_done);
hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held);
if (hdd_ctx->current_intf_count != 0) 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, QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter) struct hdd_adapter *adapter)
{ {
@ -6401,13 +6425,14 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
reason = eSIR_MAC_DEVICE_RECOVERY; reason = eSIR_MAC_DEVICE_RECOVERY;
/* For NDI do not use roam_profile */ /* 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( status = sme_roam_disconnect(
mac_handle, mac_handle,
adapter->vdev_id, adapter->vdev_id,
eCSR_DISCONNECT_REASON_NDI_DELETE, eCSR_DISCONNECT_REASON_NDI_DELETE,
reason); reason);
else if (roam_profile->BSSType == } else if (roam_profile->BSSType ==
eCSR_BSS_TYPE_START_IBSS) eCSR_BSS_TYPE_START_IBSS)
status = sme_roam_disconnect( status = sme_roam_disconnect(
mac_handle, mac_handle,

View File

@ -957,5 +957,6 @@ void hdd_ndp_peer_departed_handler(uint8_t vdev_id, uint16_t sta_id,
if (last_peer) { if (last_peer) {
hdd_debug("No more ndp peers."); hdd_debug("No more ndp peers.");
hdd_cleanup_ndi(hdd_ctx, adapter); hdd_cleanup_ndi(hdd_ctx, adapter);
qdf_event_set(&adapter->peer_cleanup_done);
} }
} }