qcacld-3.0: Add support for the NAN Enable/Disable commands

Add changes in the NAN component and Target IF to support the
NAN Enable and Disable commands. Add changes to support all
the other generic NAN commands as well. Add a state machine
to keep track of the status of the NAN Discovery in the Target.

Add support for the NAN Enable/Disable commands

Change-Id: I20c303cad8b7a30deba50345032b33b1deba4802
CRs-Fixed: 2338054
This commit is contained in:
Nachiket Kukade 2018-11-02 21:09:00 +05:30 committed by nshrivas
parent 85aa3788b6
commit d5a7683c8a
7 changed files with 486 additions and 30 deletions

View File

@ -690,18 +690,22 @@ struct nan_callbacks {
/**
* struct wlan_nan_tx_ops - structure of tx function pointers for nan component
* @nan_req_tx: Message handler for TX operations for the NAN Datapath
* @nan_discovery_req_tx: Msg handler for TX operations for the NAN Discovery
* @nan_datapath_req_tx: Msg handler for TX operations for the NAN Datapath
*/
struct wlan_nan_tx_ops {
QDF_STATUS (*nan_req_tx)(void *req, uint32_t req_id);
QDF_STATUS (*nan_discovery_req_tx)(void *nan_req, uint32_t req_type);
QDF_STATUS (*nan_datapath_req_tx)(void *req, uint32_t req_id);
};
/**
* struct wlan_nan_rx_ops - structure of rx function pointers for nan component
* @nan_event_rx: Event handler for RX operations for the NAN Datapath
* @nan_discovery_event_rx: Evt handler for RX operations for the NAN Discovery
* @nan_datapath_event_rx: Evt handler for RX operations for the NAN Datapath
*/
struct wlan_nan_rx_ops {
QDF_STATUS (*nan_event_rx)(struct scheduler_msg *event);
QDF_STATUS (*nan_discovery_event_rx)(struct scheduler_msg *event);
QDF_STATUS (*nan_datapath_event_rx)(struct scheduler_msg *event);
};
/**

View File

@ -31,6 +31,67 @@
#include "wlan_objmgr_pdev_obj.h"
#include "wlan_objmgr_vdev_obj.h"
QDF_STATUS nan_set_discovery_state(struct wlan_objmgr_psoc *psoc,
enum nan_disc_state new_state)
{
enum nan_disc_state cur_state;
struct nan_psoc_priv_obj *psoc_priv = nan_get_psoc_priv_obj(psoc);
bool nan_state_change_allowed = false;
QDF_STATUS status = QDF_STATUS_E_INVAL;
if (!psoc_priv) {
nan_err("nan psoc priv object is NULL");
return QDF_STATUS_E_INVAL;
}
qdf_spin_lock_bh(&psoc_priv->lock);
cur_state = psoc_priv->disc_state;
switch (new_state) {
case NAN_DISC_DISABLED:
nan_state_change_allowed = true;
break;
case NAN_DISC_ENABLE_IN_PROGRESS:
if (cur_state == NAN_DISC_DISABLED)
nan_state_change_allowed = true;
break;
case NAN_DISC_ENABLED:
if (cur_state == NAN_DISC_ENABLE_IN_PROGRESS)
nan_state_change_allowed = true;
break;
case NAN_DISC_DISABLE_IN_PROGRESS:
if (cur_state == NAN_DISC_ENABLE_IN_PROGRESS ||
cur_state == NAN_DISC_ENABLED)
nan_state_change_allowed = true;
break;
default:
break;
}
if (nan_state_change_allowed) {
psoc_priv->disc_state = new_state;
status = QDF_STATUS_SUCCESS;
}
qdf_spin_unlock_bh(&psoc_priv->lock);
nan_info("NAN State transitioned from %d -> %d", cur_state,
psoc_priv->disc_state);
return status;
}
enum nan_disc_state nan_get_discovery_state(struct wlan_objmgr_psoc *psoc)
{
struct nan_psoc_priv_obj *psoc_priv = nan_get_psoc_priv_obj(psoc);
if (!psoc_priv) {
nan_err("nan psoc priv object is NULL");
return NAN_DISC_DISABLED;
}
return psoc_priv->disc_state;
}
void nan_release_cmd(void *in_req, uint32_t cmdtype)
{
@ -135,7 +196,7 @@ static void nan_req_activated(void *in_req, uint32_t cmdtype)
}
/* send ndp_intiator_req/responder_req/end_req to FW */
tx_ops->nan_req_tx(in_req, req_type);
tx_ops->nan_datapath_req_tx(in_req, req_type);
}
static QDF_STATUS nan_serialized_cb(void *cmd,
@ -445,7 +506,7 @@ static QDF_STATUS nan_handle_schedule_update(
return QDF_STATUS_SUCCESS;
}
QDF_STATUS nan_event_handler(struct scheduler_msg *pe_msg)
QDF_STATUS nan_datapath_event_handler(struct scheduler_msg *pe_msg)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct wlan_serialization_queued_cmd_info cmd;
@ -498,3 +559,143 @@ QDF_STATUS nan_event_handler(struct scheduler_msg *pe_msg)
}
return status;
}
QDF_STATUS nan_discovery_pre_enable(struct wlan_objmgr_psoc *psoc,
uint8_t nan_social_channel)
{
return nan_set_discovery_state(psoc, NAN_DISC_ENABLE_IN_PROGRESS);
}
static QDF_STATUS nan_discovery_disable_req(struct nan_disable_req *req)
{
struct nan_psoc_priv_obj *psoc_nan_obj;
struct wlan_nan_tx_ops *tx_ops;
/*
* State was already set to Disabled by failed Enable
* request OR by the Disable Indication event, drop the
* Disable request.
*/
if (NAN_DISC_DISABLED == nan_get_discovery_state(req->psoc))
return QDF_STATUS_SUCCESS;
psoc_nan_obj = nan_get_psoc_priv_obj(req->psoc);
if (!psoc_nan_obj) {
nan_err("psoc_nan_obj is null");
return QDF_STATUS_E_NULL_VALUE;
}
tx_ops = &psoc_nan_obj->tx_ops;
if (!tx_ops->nan_discovery_req_tx) {
nan_err("NAN Discovery tx op is NULL");
return QDF_STATUS_E_NULL_VALUE;
}
return tx_ops->nan_discovery_req_tx(req, NAN_DISABLE_REQ);
}
static QDF_STATUS nan_discovery_enable_req(struct nan_enable_req *req)
{
struct nan_psoc_priv_obj *psoc_nan_obj;
struct wlan_nan_tx_ops *tx_ops;
/*
* State was already set to Disable in progress by a
* disable request, drop the Enable request and move
* back to Disabled state.
*/
if (NAN_DISC_DISABLE_IN_PROGRESS == nan_get_discovery_state(req->psoc))
return nan_set_discovery_state(req->psoc, NAN_DISC_DISABLED);
psoc_nan_obj = nan_get_psoc_priv_obj(req->psoc);
if (!psoc_nan_obj) {
nan_err("psoc_nan_obj is null");
return QDF_STATUS_E_NULL_VALUE;
}
tx_ops = &psoc_nan_obj->tx_ops;
if (!tx_ops->nan_discovery_req_tx) {
nan_err("NAN Discovery tx op is NULL");
return QDF_STATUS_E_NULL_VALUE;
}
return tx_ops->nan_discovery_req_tx(req, NAN_ENABLE_REQ);
}
static QDF_STATUS nan_discovery_generic_req(struct nan_generic_req *req)
{
struct nan_psoc_priv_obj *psoc_nan_obj;
struct wlan_nan_tx_ops *tx_ops;
psoc_nan_obj = nan_get_psoc_priv_obj(req->psoc);
if (!psoc_nan_obj) {
nan_err("psoc_nan_obj is null");
return QDF_STATUS_E_NULL_VALUE;
}
tx_ops = &psoc_nan_obj->tx_ops;
if (!tx_ops->nan_discovery_req_tx) {
nan_err("NAN Discovery tx op is NULL");
return QDF_STATUS_E_NULL_VALUE;
}
return tx_ops->nan_discovery_req_tx(req, NAN_GENERIC_REQ);
}
void nan_discovery_flush_callback(struct scheduler_msg *msg)
{
struct wlan_objmgr_psoc *psoc;
if (!msg || !msg->bodyptr) {
nan_err("Null pointer for NAN Discovery message");
return;
}
switch (msg->type) {
case NAN_ENABLE_REQ:
psoc = ((struct nan_enable_req *)msg->bodyptr)->psoc;
break;
case NAN_DISABLE_REQ:
psoc = ((struct nan_disable_req *)msg->bodyptr)->psoc;
break;
case NAN_GENERIC_REQ:
psoc = ((struct nan_generic_req *)msg->bodyptr)->psoc;
break;
default:
nan_err("Unsupported request type: %d", msg->type);
qdf_mem_free(msg->bodyptr);
return;
}
wlan_objmgr_psoc_release_ref(psoc, WLAN_NAN_ID);
qdf_mem_free(msg->bodyptr);
}
QDF_STATUS nan_discovery_scheduled_handler(struct scheduler_msg *msg)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!msg || !msg->bodyptr) {
nan_alert("msg or bodyptr is null");
return QDF_STATUS_E_NULL_VALUE;
}
switch (msg->type) {
case NAN_ENABLE_REQ:
status = nan_discovery_enable_req(msg->bodyptr);
break;
case NAN_DISABLE_REQ:
status = nan_discovery_disable_req(msg->bodyptr);
break;
case NAN_GENERIC_REQ:
status = nan_discovery_generic_req(msg->bodyptr);
break;
default:
nan_err("Unsupported request type: %d", msg->type);
qdf_mem_free(msg->bodyptr);
return QDF_STATUS_E_FAILURE;
}
nan_discovery_flush_callback(msg);
return status;
}

View File

@ -62,6 +62,20 @@ struct scheduler_msg;
#define MAX_PEERS 32
#endif
/**
* enum nan_disc_state - NAN Discovery states
* @NAN_DISC_DISABLED: NAN Discovery is disabled
* @NAN_DISC_ENABLE_IN_PROGRESS: NAN Discovery enable is in progress
* @NAN_DISC_ENABLED: NAN Discovery is enabled
* @NAN_DISC_DISABLE_IN_PROGRESS: NAN Discovery disable is in progress
*/
enum nan_disc_state {
NAN_DISC_DISABLED,
NAN_DISC_ENABLE_IN_PROGRESS,
NAN_DISC_ENABLED,
NAN_DISC_DISABLE_IN_PROGRESS,
};
/**
* struct nan_cfg_params - NAN INI config params
* @enable: NAN feature enable
@ -86,8 +100,9 @@ struct nan_cfg_params {
* @cb_obj: struct contaning callback pointers
* @cfg_param: NAN Config parameters in INI
* @nan_caps: NAN Target capabilities
* @tx_ops: NAN Tx operations
* @rx_ops: NAN Rx operations
* @tx_ops: Tx ops registered with Target IF interface
* @rx_ops: Rx ops registered with Target IF interface
* @disc_state: Present NAN Discovery state
*/
struct nan_psoc_priv_obj {
qdf_spinlock_t lock;
@ -96,6 +111,7 @@ struct nan_psoc_priv_obj {
struct nan_tgt_caps nan_caps;
struct wlan_nan_tx_ops tx_ops;
struct wlan_nan_rx_ops rx_ops;
enum nan_disc_state disc_state;
};
/**
@ -139,13 +155,58 @@ void nan_release_cmd(void *in_req, uint32_t req_type);
*/
QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg);
/**
* nan_discovery_flush_callback: callback to flush the NAN scheduler msg
* @msg: pointer to msg
*
* Return: None
*/
void nan_discovery_flush_callback(struct scheduler_msg *msg);
/**
* nan_discovery_scheduled_handler: callback pointer to be called when scheduler
* starts executing enqueued NAN command.
* @msg: pointer to msg
*
* Return: status of operation
*/
QDF_STATUS nan_discovery_scheduled_handler(struct scheduler_msg *msg);
/*
* nan_event_handler: function to process events from firmware
* nan_datapath_event_handler: function to process events from firmware
* @msg: message received from lmac
*
* Return: status of operation
*/
QDF_STATUS nan_event_handler(struct scheduler_msg *msg);
QDF_STATUS nan_datapath_event_handler(struct scheduler_msg *msg);
/*
* nan_set_discovery_state: Attempts to set NAN Discovery state as the given one
* @psoc: PSOC object
* @new_state: Attempting to this NAN discovery state
*
* Return: status of operation
*/
QDF_STATUS nan_set_discovery_state(struct wlan_objmgr_psoc *psoc,
enum nan_disc_state new_state);
/*
* nan_discovery_pre_enable: Takes steps before sending NAN Enable to Firmware
* @psoc: PSOC object
* @nan_social_channel: Primary social channel for NAN Discovery
*
* Return: status of operation
*/
QDF_STATUS nan_discovery_pre_enable(struct wlan_objmgr_psoc *psoc,
uint8_t nan_social_channel);
/*
* nan_get_discovery_state: Returns the current NAN Discovery state
* @psoc: PSOC object
*
* Return: Current NAN Discovery state
*/
enum nan_disc_state nan_get_discovery_state(struct wlan_objmgr_psoc *psoc);
#endif /* _WLAN_NAN_MAIN_I_H_ */
#endif /* WLAN_FEATURE_NAN_CONVERGENCE */

View File

@ -236,10 +236,7 @@ QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc,
*
* Return: status of operation
*/
static inline QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
{
return QDF_STATUS_SUCCESS;
}
QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type);
/**
* ucfg_is_nan_dbs_supported() - ucfg API to query NAN DBS support

View File

@ -471,3 +471,108 @@ bool ucfg_is_nan_dbs_supported(struct wlan_objmgr_psoc *psoc)
return (psoc_priv->nan_caps.nan_dbs_supported == 1);
}
QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
{
struct wlan_objmgr_psoc *psoc;
struct scheduler_msg msg = {0};
uint32_t len;
QDF_STATUS status;
if (!in_req) {
nan_alert("NAN Discovery req is null");
return QDF_STATUS_E_NULL_VALUE;
}
switch (req_type) {
case NAN_ENABLE_REQ: {
struct nan_enable_req *req = in_req;
psoc = req->psoc;
/*
* Take a psoc reference while it is being used by the
* NAN requests.
*/
status = wlan_objmgr_psoc_try_get_ref(psoc,
WLAN_NAN_ID);
if (QDF_IS_STATUS_ERROR(status)) {
nan_err("Couldn't obtain psoc ref");
return status;
}
status = nan_discovery_pre_enable(psoc,
req->social_chan_2g);
if (QDF_IS_STATUS_SUCCESS(status)) {
len = sizeof(struct nan_enable_req) +
req->params.request_data_len;
} else {
wlan_objmgr_psoc_release_ref(psoc,
WLAN_NAN_ID);
return status;
}
break;
}
case NAN_DISABLE_REQ: {
struct nan_disable_req *req = in_req;
psoc = req->psoc;
status = wlan_objmgr_psoc_try_get_ref(psoc,
WLAN_NAN_ID);
if (QDF_IS_STATUS_ERROR(status)) {
nan_err("Couldn't obtain psoc ref");
return status;
}
status =
nan_set_discovery_state(req->psoc,
NAN_DISC_DISABLE_IN_PROGRESS);
if (QDF_IS_STATUS_SUCCESS(status)) {
len = sizeof(struct nan_disable_req) +
req->params.request_data_len;
} else {
wlan_objmgr_psoc_release_ref(psoc,
WLAN_NAN_ID);
return status;
}
break;
}
case NAN_GENERIC_REQ: {
struct nan_generic_req *req = in_req;
psoc = req->psoc;
status = wlan_objmgr_psoc_try_get_ref(psoc,
WLAN_NAN_ID);
if (QDF_IS_STATUS_ERROR(status)) {
nan_err("Couldn't obtain psoc ref");
return status;
}
len = sizeof(struct nan_generic_req) +
req->params.request_data_len;
break;
}
default:
nan_err("in correct message req type: %d", req_type);
return QDF_STATUS_E_INVAL;
}
msg.bodyptr = qdf_mem_malloc(len);
if (!msg.bodyptr) {
wlan_objmgr_psoc_release_ref(psoc, WLAN_NAN_ID);
return QDF_STATUS_E_NOMEM;
}
qdf_mem_copy(msg.bodyptr, in_req, len);
msg.type = req_type;
msg.callback = nan_discovery_scheduled_handler;
msg.flush_callback = nan_discovery_flush_callback;
status = scheduler_post_message(QDF_MODULE_ID_NAN,
QDF_MODULE_ID_NAN,
QDF_MODULE_ID_OS_IF, &msg);
if (QDF_IS_STATUS_ERROR(status)) {
nan_err("failed to post msg to NAN component, status: %d",
status);
nan_discovery_flush_callback(&msg);
}
return status;
}

View File

@ -123,7 +123,7 @@ static QDF_STATUS target_if_nan_event_dispatcher(struct scheduler_msg *msg)
goto free_res;
}
status = nan_rx_ops->nan_event_rx(msg);
status = nan_rx_ops->nan_datapath_event_rx(msg);
free_res:
if (vdev)
wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
@ -175,8 +175,8 @@ static QDF_STATUS target_if_nan_ndp_initiator_req(
ndp_rsp.status = NAN_DATAPATH_DATA_INITIATOR_REQ_FAILED;
pe_msg.type = NDP_INITIATOR_RSP;
pe_msg.bodyptr = &ndp_rsp;
if (nan_rx_ops->nan_event_rx)
nan_rx_ops->nan_event_rx(&pe_msg);
if (nan_rx_ops->nan_datapath_event_rx)
nan_rx_ops->nan_datapath_event_rx(&pe_msg);
return status;
}
@ -377,8 +377,8 @@ static QDF_STATUS target_if_nan_ndp_responder_req(
rsp.reason = NAN_DATAPATH_DATA_RESPONDER_REQ_FAILED;
pe_msg.bodyptr = &rsp;
pe_msg.type = NDP_RESPONDER_RSP;
if (nan_rx_ops->nan_event_rx)
nan_rx_ops->nan_event_rx(&pe_msg);
if (nan_rx_ops->nan_datapath_event_rx)
nan_rx_ops->nan_datapath_event_rx(&pe_msg);
return status;
}
@ -477,8 +477,8 @@ static QDF_STATUS target_if_nan_ndp_end_req(struct nan_datapath_end_req *req)
end_rsp.transaction_id = req->transaction_id;
msg.bodyptr = &end_rsp;
if (nan_rx_ops->nan_event_rx)
nan_rx_ops->nan_event_rx(&msg);
if (nan_rx_ops->nan_datapath_event_rx)
nan_rx_ops->nan_datapath_event_rx(&msg);
return status;
}
@ -637,7 +637,7 @@ static int target_if_ndp_sch_update_handler(ol_scn_t scn, uint8_t *data,
return 0;
}
static QDF_STATUS target_if_nan_req(void *req, uint32_t req_type)
static QDF_STATUS target_if_nan_datapath_req(void *req, uint32_t req_type)
{
/* send cmd to fw */
switch (req_type) {
@ -657,14 +657,101 @@ static QDF_STATUS target_if_nan_req(void *req, uint32_t req_type)
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS target_if_nan_generic_req(struct wlan_objmgr_psoc *psoc,
void *nan_req)
{
struct wmi_unified *wmi_handle;
if (!psoc) {
target_if_err("psoc is null.");
return QDF_STATUS_E_NULL_VALUE;
}
if (!nan_req) {
target_if_err("Invalid req.");
return QDF_STATUS_E_INVAL;
}
wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_handle) {
target_if_err("wmi_handle is null.");
return QDF_STATUS_E_NULL_VALUE;
}
return wmi_unified_nan_req_cmd(wmi_handle, nan_req);
}
static QDF_STATUS target_if_nan_disable_req(struct nan_disable_req *nan_req)
{
struct wmi_unified *wmi_handle;
struct wlan_objmgr_psoc *psoc;
if (!nan_req) {
target_if_err("Invalid req.");
return QDF_STATUS_E_INVAL;
}
psoc = nan_req->psoc;
if (!psoc) {
target_if_err("psoc is null.");
return QDF_STATUS_E_NULL_VALUE;
}
wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_handle) {
target_if_err("wmi_handle is null.");
return QDF_STATUS_E_NULL_VALUE;
}
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS target_if_nan_discovery_req(void *req, uint32_t req_type)
{
QDF_STATUS status;
if (!req) {
target_if_err("Invalid req.");
return QDF_STATUS_E_INVAL;
}
switch (req_type) {
case NAN_DISABLE_REQ:
status = target_if_nan_disable_req(req);
break;
case NAN_GENERIC_REQ: {
struct nan_generic_req *nan_req = req;
status = target_if_nan_generic_req(nan_req->psoc,
&nan_req->params);
break;
}
case NAN_ENABLE_REQ: {
struct nan_enable_req *nan_req = req;
status = target_if_nan_generic_req(nan_req->psoc,
&nan_req->params);
break;
}
default:
target_if_err("Invalid NAN req type");
status = QDF_STATUS_E_INVAL;
break;
}
return status;
}
void target_if_nan_register_tx_ops(struct wlan_nan_tx_ops *tx_ops)
{
tx_ops->nan_req_tx = target_if_nan_req;
tx_ops->nan_discovery_req_tx = target_if_nan_discovery_req;
tx_ops->nan_datapath_req_tx = target_if_nan_datapath_req;
}
void target_if_nan_register_rx_ops(struct wlan_nan_rx_ops *rx_ops)
{
rx_ops->nan_event_rx = nan_event_handler;
rx_ops->nan_discovery_event_rx = NULL;
rx_ops->nan_datapath_event_rx = nan_datapath_event_handler;
}
QDF_STATUS target_if_nan_register_events(struct wlan_objmgr_psoc *psoc)

View File

@ -2216,7 +2216,7 @@ static int os_if_nan_generic_req(struct wlan_objmgr_psoc *psoc,
status = ucfg_nan_discovery_req(nan_req, NAN_GENERIC_REQ);
if (QDF_IS_STATUS_SUCCESS(status))
cfg80211_err("Successfully sent a NAN request");
cfg80211_debug("Successfully sent a NAN request");
else
cfg80211_err("Unable to send a NAN request");
@ -2248,9 +2248,9 @@ static int os_if_process_nan_disable_req(struct wlan_objmgr_psoc *psoc,
status = ucfg_nan_discovery_req(nan_req, NAN_DISABLE_REQ);
if (QDF_IS_STATUS_SUCCESS(status))
cfg80211_err("Successfully sent NAN Disable request");
cfg80211_debug("Successfully sent NAN Disable request");
else
cfg80211_err("Unable to disable NAN Discovery");
cfg80211_err("Unable to send NAN Disable request");
qdf_mem_free(nan_req);
return qdf_status_to_os_return(status);
@ -2290,7 +2290,8 @@ static int os_if_process_nan_enable_req(struct wlan_objmgr_psoc *psoc,
return -ENOMEM;
}
nan_req->social_chan_2g = wlan_freq_to_chan(chan_freq_2g);
nan_req->social_chan_5g = wlan_freq_to_chan(chan_freq_5g);
if (chan_freq_5g)
nan_req->social_chan_5g = wlan_freq_to_chan(chan_freq_5g);
nan_req->psoc = psoc;
nan_req->params.request_data_len = buf_len;
@ -2301,9 +2302,9 @@ static int os_if_process_nan_enable_req(struct wlan_objmgr_psoc *psoc,
status = ucfg_nan_discovery_req(nan_req, NAN_ENABLE_REQ);
if (QDF_IS_STATUS_SUCCESS(status))
cfg80211_err("Successfully sent NAN Enable");
cfg80211_debug("Successfully sent NAN Enable request");
else
cfg80211_err("Unable to enable NAN Discovery");
cfg80211_err("Unable to send NAN Enable request");
qdf_mem_free(nan_req);
return qdf_status_to_os_return(status);