qcacld-3.0: Process NAN enable/disable synchronously
In the current implementation, NAN enable and disable request are processed asynchronously, because of which some race conditions are seen. Example: If NDI is having multiple NDPs and without terminating NDPs if NAN disable and NDI delete are issued back to back then, NDP_END sequence is not initiated and causing deviation from NAN spec. Root-cause is firmware deleting NDP peer as a part of NDI delete before initiating NDP end sequence. To fix this, process NAN enable and disable requests synchronously. Change-Id: I467419370187b0dc8d879e1806347c9f21ebb23a CRs-Fixed: 2528599
This commit is contained in:

committed by
nshrivas

parent
91e874ef20
commit
cbc6c3b8d1
@@ -722,8 +722,8 @@ struct nan_datapath_host_event {
|
|||||||
* struct nan_callbacks - struct containing callback to non-converged driver
|
* struct nan_callbacks - struct containing callback to non-converged driver
|
||||||
* @os_if_nan_event_handler: OS IF Callback for handling NAN Discovery events
|
* @os_if_nan_event_handler: OS IF Callback for handling NAN Discovery events
|
||||||
* @os_if_ndp_event_handler: OS IF Callback for handling NAN Datapath events
|
* @os_if_ndp_event_handler: OS IF Callback for handling NAN Datapath events
|
||||||
* @ucfg_explicit_disable_cb: UCFG Callback to indicate NAN explicit disable is
|
* @ucfg_nan_request_process_cb: Callback to indicate NAN enable/disable
|
||||||
* complete
|
* request processing is complete
|
||||||
* @ndi_open: HDD callback for creating the NAN Datapath Interface
|
* @ndi_open: HDD callback for creating the NAN Datapath Interface
|
||||||
* @ndi_start: HDD callback for starting the NAN Datapath Interface
|
* @ndi_start: HDD callback for starting the NAN Datapath Interface
|
||||||
* @ndi_close: HDD callback for closing the NAN Datapath Interface
|
* @ndi_close: HDD callback for closing the NAN Datapath Interface
|
||||||
@@ -743,7 +743,7 @@ struct nan_callbacks {
|
|||||||
void (*os_if_ndp_event_handler)(struct wlan_objmgr_psoc *psoc,
|
void (*os_if_ndp_event_handler)(struct wlan_objmgr_psoc *psoc,
|
||||||
struct wlan_objmgr_vdev *vdev,
|
struct wlan_objmgr_vdev *vdev,
|
||||||
uint32_t type, void *msg);
|
uint32_t type, void *msg);
|
||||||
void (*ucfg_explicit_disable_cb)(void *cookie);
|
void (*ucfg_nan_request_process_cb)(void *cookie);
|
||||||
int (*ndi_open)(char *iface_name);
|
int (*ndi_open)(char *iface_name);
|
||||||
int (*ndi_start)(char *iface_name, uint16_t);
|
int (*ndi_start)(char *iface_name, uint16_t);
|
||||||
void (*ndi_close)(uint8_t);
|
void (*ndi_close)(uint8_t);
|
||||||
|
@@ -51,6 +51,12 @@ QDF_STATUS nan_set_discovery_state(struct wlan_objmgr_psoc *psoc,
|
|||||||
|
|
||||||
qdf_spin_lock_bh(&psoc_priv->lock);
|
qdf_spin_lock_bh(&psoc_priv->lock);
|
||||||
cur_state = psoc_priv->disc_state;
|
cur_state = psoc_priv->disc_state;
|
||||||
|
if (cur_state == new_state) {
|
||||||
|
qdf_spin_unlock_bh(&psoc_priv->lock);
|
||||||
|
nan_err("curr_state: %u and new state: %u are same",
|
||||||
|
cur_state, new_state);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
switch (new_state) {
|
switch (new_state) {
|
||||||
case NAN_DISC_DISABLED:
|
case NAN_DISC_DISABLED:
|
||||||
@@ -804,6 +810,7 @@ static QDF_STATUS nan_handle_enable_rsp(struct nan_event_params *nan_event)
|
|||||||
struct nan_psoc_priv_obj *psoc_nan_obj;
|
struct nan_psoc_priv_obj *psoc_nan_obj;
|
||||||
struct wlan_objmgr_psoc *psoc;
|
struct wlan_objmgr_psoc *psoc;
|
||||||
QDF_STATUS status;
|
QDF_STATUS status;
|
||||||
|
void (*call_back)(void *cookie);
|
||||||
|
|
||||||
psoc = nan_event->psoc;
|
psoc = nan_event->psoc;
|
||||||
psoc_nan_obj = nan_get_psoc_priv_obj(psoc);
|
psoc_nan_obj = nan_get_psoc_priv_obj(psoc);
|
||||||
@@ -843,6 +850,10 @@ static QDF_STATUS nan_handle_enable_rsp(struct nan_event_params *nan_event)
|
|||||||
policy_mgr_check_n_start_opportunistic_timer(psoc);
|
policy_mgr_check_n_start_opportunistic_timer(psoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
call_back = psoc_nan_obj->cb_obj.ucfg_nan_request_process_cb;
|
||||||
|
if (call_back)
|
||||||
|
call_back(psoc_nan_obj->request_context);
|
||||||
|
|
||||||
return QDF_STATUS_SUCCESS;
|
return QDF_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -862,16 +873,17 @@ static QDF_STATUS nan_handle_disable_ind(struct nan_event_params *nan_event)
|
|||||||
status = nan_set_discovery_state(nan_event->psoc,
|
status = nan_set_discovery_state(nan_event->psoc,
|
||||||
NAN_DISC_DISABLED);
|
NAN_DISC_DISABLED);
|
||||||
if (QDF_IS_STATUS_SUCCESS(status)) {
|
if (QDF_IS_STATUS_SUCCESS(status)) {
|
||||||
|
void (*call_back)(void *cookie);
|
||||||
|
|
||||||
|
call_back = psoc_nan_obj->cb_obj.ucfg_nan_request_process_cb;
|
||||||
policy_mgr_decr_session_set_pcl(psoc, QDF_NAN_DISC_MODE,
|
policy_mgr_decr_session_set_pcl(psoc, QDF_NAN_DISC_MODE,
|
||||||
NAN_PSEUDO_VDEV_ID);
|
NAN_PSEUDO_VDEV_ID);
|
||||||
|
|
||||||
if (psoc_nan_obj->is_explicit_disable) {
|
if (psoc_nan_obj->is_explicit_disable) {
|
||||||
if (psoc_nan_obj->cb_obj.ucfg_explicit_disable_cb)
|
if (call_back)
|
||||||
psoc_nan_obj->cb_obj.ucfg_explicit_disable_cb(
|
call_back(psoc_nan_obj->request_context);
|
||||||
psoc_nan_obj->disable_context);
|
|
||||||
} else {
|
|
||||||
policy_mgr_nan_sap_post_disable_conc_check(psoc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policy_mgr_nan_sap_post_disable_conc_check(psoc);
|
||||||
} else {
|
} else {
|
||||||
/* Should not happen, NAN state can always be disabled */
|
/* Should not happen, NAN state can always be disabled */
|
||||||
nan_err("Cannot set NAN state to disabled!");
|
nan_err("Cannot set NAN state to disabled!");
|
||||||
|
@@ -102,8 +102,8 @@ struct nan_cfg_params {
|
|||||||
* @nan_social_ch_5g: NAN 5G Social channel for discovery
|
* @nan_social_ch_5g: NAN 5G Social channel for discovery
|
||||||
* @nan_disc_mac_id: MAC id used for NAN Discovery
|
* @nan_disc_mac_id: MAC id used for NAN Discovery
|
||||||
* @is_explicit_disable: Flag to indicate that NAN is being explicitly
|
* @is_explicit_disable: Flag to indicate that NAN is being explicitly
|
||||||
* disabled by driver
|
* disabled by driver or user-space
|
||||||
* @disable_context: Explicit disable context
|
* @request_context: NAN enable/disable request context
|
||||||
*/
|
*/
|
||||||
struct nan_psoc_priv_obj {
|
struct nan_psoc_priv_obj {
|
||||||
qdf_spinlock_t lock;
|
qdf_spinlock_t lock;
|
||||||
@@ -117,7 +117,7 @@ struct nan_psoc_priv_obj {
|
|||||||
uint8_t nan_social_ch_5g;
|
uint8_t nan_social_ch_5g;
|
||||||
uint8_t nan_disc_mac_id;
|
uint8_t nan_disc_mac_id;
|
||||||
bool is_explicit_disable;
|
bool is_explicit_disable;
|
||||||
void *disable_context;
|
void *request_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -419,13 +419,13 @@ void ucfg_nan_datapath_event_handler(struct wlan_objmgr_psoc *psoc,
|
|||||||
psoc_obj->cb_obj.os_if_ndp_event_handler(psoc, vdev, type, msg);
|
psoc_obj->cb_obj.os_if_ndp_event_handler(psoc, vdev, type, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ucfg_concurrency_nan_disable_callback(void *cookie)
|
static void ucfg_nan_request_process_cb(void *cookie)
|
||||||
{
|
{
|
||||||
struct osif_request *request;
|
struct osif_request *request;
|
||||||
|
|
||||||
request = osif_request_get(cookie);
|
request = osif_request_get(cookie);
|
||||||
|
|
||||||
if (request) {
|
if (request) {
|
||||||
|
nan_debug("request (cookie:0x%pK) completed", cookie);
|
||||||
osif_request_complete(request);
|
osif_request_complete(request);
|
||||||
osif_request_put(request);
|
osif_request_put(request);
|
||||||
} else {
|
} else {
|
||||||
@@ -458,8 +458,8 @@ int ucfg_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
|
|||||||
cb_obj->os_if_ndp_event_handler;
|
cb_obj->os_if_ndp_event_handler;
|
||||||
psoc_obj->cb_obj.os_if_nan_event_handler =
|
psoc_obj->cb_obj.os_if_nan_event_handler =
|
||||||
cb_obj->os_if_nan_event_handler;
|
cb_obj->os_if_nan_event_handler;
|
||||||
psoc_obj->cb_obj.ucfg_explicit_disable_cb =
|
psoc_obj->cb_obj.ucfg_nan_request_process_cb =
|
||||||
ucfg_concurrency_nan_disable_callback;
|
ucfg_nan_request_process_cb;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -564,6 +564,13 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
|
|||||||
struct scheduler_msg msg = {0};
|
struct scheduler_msg msg = {0};
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
QDF_STATUS status;
|
QDF_STATUS status;
|
||||||
|
struct nan_psoc_priv_obj *psoc_priv;
|
||||||
|
struct osif_request *request = NULL;
|
||||||
|
static const struct osif_request_params params = {
|
||||||
|
.priv_size = 0,
|
||||||
|
.timeout_ms = 1000,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!in_req) {
|
if (!in_req) {
|
||||||
nan_alert("NAN Discovery req is null");
|
nan_alert("NAN Discovery req is null");
|
||||||
@@ -575,6 +582,12 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
|
|||||||
struct nan_enable_req *req = in_req;
|
struct nan_enable_req *req = in_req;
|
||||||
|
|
||||||
psoc = req->psoc;
|
psoc = req->psoc;
|
||||||
|
psoc_priv = nan_get_psoc_priv_obj(psoc);
|
||||||
|
if (!psoc_priv) {
|
||||||
|
nan_err("nan psoc priv object is NULL");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Take a psoc reference while it is being used by the
|
* Take a psoc reference while it is being used by the
|
||||||
* NAN requests.
|
* NAN requests.
|
||||||
@@ -602,6 +615,12 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
|
|||||||
struct nan_disable_req *req = in_req;
|
struct nan_disable_req *req = in_req;
|
||||||
|
|
||||||
psoc = req->psoc;
|
psoc = req->psoc;
|
||||||
|
psoc_priv = nan_get_psoc_priv_obj(psoc);
|
||||||
|
if (!psoc_priv) {
|
||||||
|
nan_err("nan psoc priv object is NULL");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
status = wlan_objmgr_psoc_try_get_ref(psoc,
|
status = wlan_objmgr_psoc_try_get_ref(psoc,
|
||||||
WLAN_NAN_ID);
|
WLAN_NAN_ID);
|
||||||
if (QDF_IS_STATUS_ERROR(status)) {
|
if (QDF_IS_STATUS_ERROR(status)) {
|
||||||
@@ -626,6 +645,12 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
|
|||||||
struct nan_generic_req *req = in_req;
|
struct nan_generic_req *req = in_req;
|
||||||
|
|
||||||
psoc = req->psoc;
|
psoc = req->psoc;
|
||||||
|
psoc_priv = nan_get_psoc_priv_obj(psoc);
|
||||||
|
if (!psoc_priv) {
|
||||||
|
nan_err("nan psoc priv object is NULL");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
status = wlan_objmgr_psoc_try_get_ref(psoc,
|
status = wlan_objmgr_psoc_try_get_ref(psoc,
|
||||||
WLAN_NAN_ID);
|
WLAN_NAN_ID);
|
||||||
if (QDF_IS_STATUS_ERROR(status)) {
|
if (QDF_IS_STATUS_ERROR(status)) {
|
||||||
@@ -651,6 +676,23 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
|
|||||||
msg.type = req_type;
|
msg.type = req_type;
|
||||||
msg.callback = nan_discovery_scheduled_handler;
|
msg.callback = nan_discovery_scheduled_handler;
|
||||||
msg.flush_callback = nan_discovery_flush_callback;
|
msg.flush_callback = nan_discovery_flush_callback;
|
||||||
|
|
||||||
|
if (req_type == NAN_GENERIC_REQ)
|
||||||
|
goto post_msg;
|
||||||
|
|
||||||
|
request = osif_request_alloc(¶ms);
|
||||||
|
if (!request) {
|
||||||
|
nan_err("Request allocation failure");
|
||||||
|
nan_discovery_flush_callback(&msg);
|
||||||
|
return QDF_STATUS_E_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
psoc_priv->request_context = osif_request_cookie(request);
|
||||||
|
if (req_type == NAN_DISABLE_REQ)
|
||||||
|
psoc_priv->is_explicit_disable = true;
|
||||||
|
|
||||||
|
post_msg:
|
||||||
|
nan_debug("posting request: %u", req_type);
|
||||||
status = scheduler_post_message(QDF_MODULE_ID_NAN,
|
status = scheduler_post_message(QDF_MODULE_ID_NAN,
|
||||||
QDF_MODULE_ID_NAN,
|
QDF_MODULE_ID_NAN,
|
||||||
QDF_MODULE_ID_OS_IF, &msg);
|
QDF_MODULE_ID_OS_IF, &msg);
|
||||||
@@ -660,6 +702,21 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
|
|||||||
nan_discovery_flush_callback(&msg);
|
nan_discovery_flush_callback(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req_type != NAN_GENERIC_REQ) {
|
||||||
|
err = osif_request_wait_for_response(request);
|
||||||
|
if (err)
|
||||||
|
nan_err("NAN request: %u timed out: %d",
|
||||||
|
req_type, err);
|
||||||
|
else
|
||||||
|
nan_debug("NAN request: %u serviced successfully",
|
||||||
|
req_type);
|
||||||
|
|
||||||
|
if (req_type == NAN_DISABLE_REQ)
|
||||||
|
psoc_priv->is_explicit_disable = false;
|
||||||
|
|
||||||
|
osif_request_put(request);
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,13 +725,7 @@ void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc)
|
|||||||
struct nan_disable_req nan_req = {0};
|
struct nan_disable_req nan_req = {0};
|
||||||
enum nan_disc_state curr_nan_state;
|
enum nan_disc_state curr_nan_state;
|
||||||
struct nan_psoc_priv_obj *psoc_priv;
|
struct nan_psoc_priv_obj *psoc_priv;
|
||||||
struct osif_request *request;
|
|
||||||
static const struct osif_request_params params = {
|
|
||||||
.priv_size = 0,
|
|
||||||
.timeout_ms = 1000,
|
|
||||||
};
|
|
||||||
QDF_STATUS status;
|
QDF_STATUS status;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!psoc) {
|
if (!psoc) {
|
||||||
nan_err("psoc object is NULL, no action will be taken");
|
nan_err("psoc object is NULL, no action will be taken");
|
||||||
@@ -700,35 +751,17 @@ void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc)
|
|||||||
}
|
}
|
||||||
qdf_spin_unlock_bh(&psoc_priv->lock);
|
qdf_spin_unlock_bh(&psoc_priv->lock);
|
||||||
|
|
||||||
request = osif_request_alloc(¶ms);
|
|
||||||
if (!request) {
|
|
||||||
nan_err("Request allocation failure");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nan_req.psoc = psoc;
|
nan_req.psoc = psoc;
|
||||||
nan_req.disable_2g_discovery = true;
|
nan_req.disable_2g_discovery = true;
|
||||||
nan_req.disable_5g_discovery = true;
|
nan_req.disable_5g_discovery = true;
|
||||||
psoc_priv->disable_context = osif_request_cookie(request);
|
|
||||||
|
|
||||||
status = ucfg_nan_discovery_req(&nan_req, NAN_DISABLE_REQ);
|
status = ucfg_nan_discovery_req(&nan_req, NAN_DISABLE_REQ);
|
||||||
if (QDF_IS_STATUS_ERROR(status)) {
|
if (QDF_IS_STATUS_ERROR(status)) {
|
||||||
nan_err("Unable to disable NAN Discovery");
|
nan_err("Unable to disable NAN Discovery");
|
||||||
osif_request_put(request);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
psoc_priv->is_explicit_disable = true;
|
nan_debug("NAN Disabled successfully");
|
||||||
nan_debug("Successfully sent NAN Disable request");
|
|
||||||
|
|
||||||
err = osif_request_wait_for_response(request);
|
|
||||||
if (err)
|
|
||||||
nan_err("NAN Disable timed out waiting for disable ind-%d",
|
|
||||||
err);
|
|
||||||
else
|
|
||||||
nan_debug("NAN Disabled successfully");
|
|
||||||
psoc_priv->is_explicit_disable = false;
|
|
||||||
osif_request_put(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QDF_STATUS
|
static QDF_STATUS
|
||||||
|
Reference in New Issue
Block a user