qcacld-3.0: Correct the condition to reject TDLS

Reject any incoming get_all_peers TDLS command if there
are any currently in progress.
The later commands will only be processed once the earlier
commands finish, since they are processed sequentially.
However, once a command finishes, the memory allocated for
it from userspace is freed up. Each command is passed the
same address so the later commands will end up writing to
a freed address. To avoid this, reject incoming requests
if there are any still in progress.
For this, the condition should be corrected.
We shouldn't use completion_done here for checking for
completion as this will always return false, as
tdls_user_cmd_comp.done will remain in init state always.
So, the very first command will also not work.
In general completion_done is used to check if there are
multiple threads waiting on the complete event that's
why it will return true only when tdls_user_cmd_comp.done
is set with complete().
Also, if the state is in wait_for_completion, this function
will return true after the wait timer is over or condition
is met as wait_for_completion will hold out the hold lock
and will will prevent completion_done from returning.
Better to use a flag to determine command condition.

Change-Id: I1b6b270dbb9b0b103f10e7ae22a60030ea2fbb98
CRs-Fixed: 3162184
This commit is contained in:
Utkarsh Bhatnagar 2022-04-13 03:57:46 +05:30 committed by Gerrit - the friendly Code Review server
parent 705e9a43d7
commit 1e937d5c37
2 changed files with 23 additions and 1 deletions

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@ -51,6 +52,7 @@
* @mgmt_tx_completion_status: Tdls mgmt frames TX completion status code * @mgmt_tx_completion_status: Tdls mgmt frames TX completion status code
* @tdls_user_cmd_len: tdls user command written buffer length * @tdls_user_cmd_len: tdls user command written buffer length
* @tdls_antenna_switch_status: return status after antenna switch * @tdls_antenna_switch_status: return status after antenna switch
* @tdls_user_cmd_in_progress: tdls user command progress status.
*/ */
struct osif_tdls_vdev { struct osif_tdls_vdev {
struct completion tdls_add_peer_comp; struct completion tdls_add_peer_comp;
@ -64,6 +66,7 @@ struct osif_tdls_vdev {
uint32_t mgmt_tx_completion_status; uint32_t mgmt_tx_completion_status;
uint32_t tdls_user_cmd_len; uint32_t tdls_user_cmd_len;
int tdls_antenna_switch_status; int tdls_antenna_switch_status;
bool tdls_user_cmd_in_progress;
}; };
/** /**

View File

@ -735,11 +735,29 @@ int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev,
tdls_priv = osif_priv->osif_tdls; tdls_priv = osif_priv->osif_tdls;
if (!completion_done(&tdls_priv->tdls_user_cmd_comp)) { /*
* We shouldn't use completion_done here for checking for completion
* as this will always return false, as tdls_user_cmd_comp.done will
* remain in init state always. So, the very first command will also
* not work.
* In general completion_done is used to check if there are multiple
* threads waiting on the complete event that's why it will return true
* only when tdls_user_cmd_comp.done is set with complete()
* In general completion_done will return true only when
* tdls_user_cmd_comp.done is set that will happen in complete().
* Also, if there is already a thread waiting for wait_for_completion,
* this function will
* return true only after the wait timer is over or condition is
* met as wait_for_completion will hold out the hold lock and will
* will prevent completion_done from returning.
* Better to use a flag to determine command condition.
*/
if (tdls_priv->tdls_user_cmd_in_progress) {
osif_err("TDLS user cmd still in progress, reject this one"); osif_err("TDLS user cmd still in progress, reject this one");
return -EBUSY; return -EBUSY;
} }
tdls_priv->tdls_user_cmd_in_progress = true;
wlan_cfg80211_update_tdls_peers_rssi(vdev); wlan_cfg80211_update_tdls_peers_rssi(vdev);
reinit_completion(&tdls_priv->tdls_user_cmd_comp); reinit_completion(&tdls_priv->tdls_user_cmd_comp);
@ -769,6 +787,7 @@ int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev,
len = tdls_priv->tdls_user_cmd_len; len = tdls_priv->tdls_user_cmd_len;
error_get_tdls_peers: error_get_tdls_peers:
tdls_priv->tdls_user_cmd_in_progress = false;
return len; return len;
} }