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:
parent
705e9a43d7
commit
1e937d5c37
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user