qcacmn: Enqueue scan request only after scan scheduling is success
Currently, vendor scan request is enqueued in the scan queue first and then posted into the scheduler queue. Now if there is an SSR in between, then scan request will be freed twice. Once in SSR context and again in the caller context because scan scheduling fails due to user disabled the scan. To resolve this, post the scan request in scheduler queue first. Once scan request scheduling is success, then enqueue the scan request in scan queue. This approach can lead to a race condition like after scheduling scan request, host may get scan response from firmware even before the scan request is queued. To avoid this race, scan request scheduling and enqueue should be protected by scan_req_q_lock. Change-Id: Ic26da0181fb9a902a8a4abb8f68d9fc668f1b3f2 CRs-Fixed: 2714495
此提交包含在:
@@ -649,20 +649,22 @@ wlan_copy_bssid_scan_request(struct scan_start_request *scan_req,
|
||||
#endif
|
||||
|
||||
/**
|
||||
* wlan_scan_request_enqueue() - enqueue Scan Request
|
||||
* wlan_schedule_scan_start_request() - Schedule scan start request
|
||||
* @pdev: pointer to pdev object
|
||||
* @req: Pointer to the scan request
|
||||
* @source: source of the scan request
|
||||
* @scan_id: scan identifier
|
||||
* @scan_start_req: pointer to scan start request
|
||||
*
|
||||
* Enqueue scan request in the global scan list.This list
|
||||
* stores the active scan request information.
|
||||
* Schedule scan start request and enqueue scan request in the global scan
|
||||
* list. This list stores the active scan request information.
|
||||
*
|
||||
* Return: 0 on success, error number otherwise
|
||||
*/
|
||||
static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
|
||||
struct cfg80211_scan_request *req,
|
||||
uint8_t source, uint32_t scan_id)
|
||||
static int
|
||||
wlan_schedule_scan_start_request(struct wlan_objmgr_pdev *pdev,
|
||||
struct cfg80211_scan_request *req,
|
||||
uint8_t source,
|
||||
struct scan_start_request *scan_start_req)
|
||||
{
|
||||
struct scan_req *scan_req;
|
||||
QDF_STATUS status;
|
||||
@@ -670,23 +672,35 @@ static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
|
||||
struct osif_scan_pdev *osif_scan;
|
||||
|
||||
scan_req = qdf_mem_malloc(sizeof(*scan_req));
|
||||
if (!scan_req)
|
||||
if (!scan_req) {
|
||||
ucfg_scm_scan_free_scan_request_mem(scan_start_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Get NL global context from objmgr*/
|
||||
osif_ctx = wlan_pdev_get_ospriv(pdev);
|
||||
osif_scan = osif_ctx->osif_scan;
|
||||
scan_req->scan_request = req;
|
||||
scan_req->source = source;
|
||||
scan_req->scan_id = scan_id;
|
||||
scan_req->scan_id = scan_start_req->scan_req.scan_id;
|
||||
scan_req->dev = req->wdev->netdev;
|
||||
|
||||
qdf_mutex_acquire(&osif_scan->scan_req_q_lock);
|
||||
if (qdf_list_size(&osif_scan->scan_req_q) < WLAN_MAX_SCAN_COUNT)
|
||||
status = qdf_list_insert_back(&osif_scan->scan_req_q,
|
||||
&scan_req->node);
|
||||
else
|
||||
if (qdf_list_size(&osif_scan->scan_req_q) < WLAN_MAX_SCAN_COUNT) {
|
||||
status = ucfg_scan_start(scan_start_req);
|
||||
if (QDF_IS_STATUS_SUCCESS(status)) {
|
||||
qdf_list_insert_back(&osif_scan->scan_req_q,
|
||||
&scan_req->node);
|
||||
} else {
|
||||
osif_err("scan req failed with error %d", status);
|
||||
if (status == QDF_STATUS_E_RESOURCES)
|
||||
osif_err("HO is in progress.So defer the scan by informing busy");
|
||||
}
|
||||
} else {
|
||||
ucfg_scm_scan_free_scan_request_mem(scan_start_req);
|
||||
status = QDF_STATUS_E_RESOURCES;
|
||||
}
|
||||
|
||||
qdf_mutex_release(&osif_scan->scan_req_q_lock);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
osif_rl_debug("Failed to enqueue Scan Req as max scan %d already queued",
|
||||
@@ -1291,7 +1305,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
|
||||
wlan_scan_id scan_id;
|
||||
bool is_p2p_scan = false;
|
||||
enum wlan_band band;
|
||||
struct net_device *netdev = NULL;
|
||||
QDF_STATUS qdf_status;
|
||||
enum QDF_OPMODE opmode;
|
||||
uint32_t extra_ie_len = 0;
|
||||
@@ -1346,14 +1359,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
|
||||
req->scan_req.scan_id = scan_id;
|
||||
req->scan_req.scan_req_id = req_id;
|
||||
|
||||
/* Enqueue the scan request */
|
||||
ret = wlan_scan_request_enqueue(pdev, request, params->source,
|
||||
req->scan_req.scan_id);
|
||||
if (ret) {
|
||||
qdf_mem_free(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update scan policy type flags according to cfg scan request */
|
||||
wlan_cfg80211_update_scan_policy_type_flags(request,
|
||||
&req->scan_req);
|
||||
@@ -1561,18 +1566,15 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
|
||||
qdf_runtime_pm_prevent_suspend(
|
||||
&osif_priv->osif_scan->runtime_pm_lock);
|
||||
|
||||
qdf_status = ucfg_scan_start(req);
|
||||
qdf_status = wlan_schedule_scan_start_request(pdev, request,
|
||||
params->source, req);
|
||||
if (QDF_IS_STATUS_ERROR(qdf_status)) {
|
||||
osif_err("scan req failed with error %d", qdf_status);
|
||||
if (qdf_status == QDF_STATUS_E_RESOURCES)
|
||||
osif_err("HO is in progress.So defer the scan by informing busy");
|
||||
wlan_scan_request_dequeue(pdev, scan_id, &request,
|
||||
¶ms->source, &netdev);
|
||||
if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q)) {
|
||||
qdf_runtime_pm_allow_suspend(
|
||||
&osif_priv->osif_scan->runtime_pm_lock);
|
||||
wlan_scan_release_wake_lock(psoc,
|
||||
&osif_priv->osif_scan->scan_wake_lock);
|
||||
&osif_priv->osif_scan->runtime_pm_lock);
|
||||
wlan_scan_release_wake_lock(
|
||||
psoc,
|
||||
&osif_priv->osif_scan->scan_wake_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1580,8 +1582,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
|
||||
|
||||
err:
|
||||
qdf_mem_free(req);
|
||||
wlan_scan_request_dequeue(pdev, scan_id, &request,
|
||||
¶ms->source, &netdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
新增問題並參考
封鎖使用者