瀏覽代碼

qcacmn: Add framework for NDP cmd execution

Add NDP command execution framework:
1) Define UCFG apis, that will be called from OS_IF layer
2) Define request proccessing functions to post to scheduler and callback.
3) Define request proccessing functions to post to serializer and callback.
4) Define functions handling activated, cancelled and timed out NDP req.

Change-Id: Ibc6fe32c65f8de0c24e0537f2eb538f806cf5284
CRs-Fixed: 2014795
Naveen Rawat 8 年之前
父節點
當前提交
7358d18e39

+ 29 - 0
os_if/linux/nan/inc/os_if_nan.h

@@ -23,6 +23,11 @@
 #ifndef _OS_IF_NAN_H_
 #define _OS_IF_NAN_H_
 
+#include "qdf_types.h"
+
+struct wlan_objmgr_psoc;
+struct wlan_objmgr_vdev;
+
 #ifdef WLAN_FEATURE_NAN_CONVERGENCE
 
 #define NDP_QOS_INFO_LEN 255
@@ -114,4 +119,28 @@ enum qca_wlan_vendor_attr_ndp_sub_cmd_value {
 
 #endif /* WLAN_FEATURE_NAN_CONVERGENCE */
 
+/**
+ * os_if_nan_process_ndp_cmd: os_if api to handle nan request message
+ * @psoc: pointer to psoc object
+ * @data: request data. contains vendor cmd tlvs
+ * @data_len: length of data
+ *
+ * Return: status of operation
+ */
+int os_if_nan_process_ndp_cmd(struct wlan_objmgr_psoc *psoc,
+				const void *data, int data_len);
+
+/**
+ * os_if_nan_event_handler: os_if handler api for nan response messages
+ * @psoc: pointer to psoc object
+ * @vdev: pointer to vdev object
+ * @type: message type
+ * @msg: msg buffer
+ *
+ * Return: None
+ */
+void os_if_nan_event_handler(struct wlan_objmgr_psoc *psoc,
+			     struct wlan_objmgr_vdev *vdev,
+			     uint32_t type, void *msg);
+
 #endif

+ 96 - 0
os_if/linux/nan/src/os_if_nan.c

@@ -20,3 +20,99 @@
  * DOC: defines nan component os interface APIs
  */
 
+#include "qdf_types.h"
+#include "qdf_trace.h"
+#include "os_if_nan.h"
+#include "wlan_nlink_srv.h"
+#include "nan_public_structs.h"
+#include "wlan_cfg80211.h"
+
+/* NLA policy */
+static const struct nla_policy
+vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID] = { .type = NLA_U16 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR] = { .type = NLA_STRING,
+					.len = IFNAMSIZ },
+	[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR] = {
+					.type = NLA_BINARY,
+					.len = QDF_MAC_ADDR_SIZE },
+	[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY] = { .type = NLA_U16 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS] = { .type = NLA_BINARY,
+					.len = NDP_QOS_INFO_LEN },
+	[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO] = { .type = NLA_BINARY,
+					.len = NDP_APP_INFO_LEN },
+	[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE] = { .type = NLA_U16 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR] = { .type = NLA_BINARY,
+					.len = QDF_MAC_ADDR_SIZE },
+	[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY] = { .type = NLA_BINARY,
+					.len = NDP_NUM_INSTANCE_ID },
+	[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE] = { .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_PMK] = { .type = NLA_BINARY,
+					.len = NDP_PMK_LEN },
+	[QCA_WLAN_VENDOR_ATTR_NDP_SCID] = { .type = NLA_BINARY,
+					.len = NDP_SCID_BUF_LEN },
+	[QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE] = { .type =
+					NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE] = { .type = NLA_U32 },
+};
+
+int os_if_nan_process_ndp_cmd(void *ctx, struct wlan_objmgr_psoc *psoc,
+			      const void *data, int data_len)
+{
+	uint32_t ndp_cmd_type;
+	uint16_t transaction_id;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1];
+	char *iface_name;
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX,
+			data, data_len, vendor_attr_policy)) {
+		cfg80211_err("Invalid NDP vendor command attributes");
+		return -EINVAL;
+	}
+
+	/* Parse and fetch NDP Command Type*/
+	if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]) {
+		cfg80211_err("NAN datapath cmd type failed");
+		return -EINVAL;
+	}
+	ndp_cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) {
+		cfg80211_err("attr transaction id failed");
+		return -EINVAL;
+	}
+	transaction_id = nla_get_u16(
+			tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]);
+
+	if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) {
+		iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]);
+		cfg80211_err("Transaction Id: %d NDPCmd: %d iface_name: %s",
+			transaction_id, ndp_cmd_type, iface_name);
+	} else {
+		cfg80211_err("Transaction Id: %d NDPCmd: %d iface_name: unspecified",
+			transaction_id, ndp_cmd_type);
+	}
+
+	switch (ndp_cmd_type) {
+	default:
+		cfg80211_err("Unrecognized NDP vendor cmd %d", ndp_cmd_type);
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+void os_if_nan_event_handler(struct wlan_objmgr_psoc *psoc,
+			     struct wlan_objmgr_vdev *vdev,
+			     uint32_t type, void *msg)
+{
+	switch (type) {
+	default:
+		break;
+	}
+}

+ 201 - 1
umac/nan/core/src/nan_main.c

@@ -21,6 +21,13 @@
  */
 
 #include "nan_main_i.h"
+#include "nan_ucfg_api.h"
+#include "wlan_nan_api.h"
+#include "target_if_nan.h"
+#include "scheduler_api.h"
+#include "wlan_serialization_api.h"
+#include "wlan_objmgr_cmn.h"
+#include "wlan_objmgr_global_obj.h"
 #include "wlan_objmgr_psoc_obj.h"
 #include "wlan_objmgr_pdev_obj.h"
 #include "wlan_objmgr_vdev_obj.h"
@@ -55,4 +62,197 @@ struct nan_psoc_priv_obj *nan_get_psoc_priv_obj(
 	wlan_psoc_obj_unlock(psoc);
 
 	return obj;
-}
+}
+
+void nan_release_cmd(void *in_req, uint32_t req_type)
+{
+	struct wlan_objmgr_vdev *vdev = NULL;
+
+	if (!in_req)
+		return;
+
+	switch (req_type) {
+	case NDP_INITIATOR_REQ: {
+		struct nan_datapath_initiator_req *req = in_req;
+		vdev = req->vdev;
+		qdf_mem_free(req->pmk.pmk);
+		qdf_mem_free(req->ndp_info.ndp_app_info);
+		qdf_mem_free(req->ndp_config.ndp_cfg);
+		break;
+	}
+	case NDP_RESPONDER_REQ: {
+		struct nan_datapath_responder_req *req = in_req;
+		vdev = req->vdev;
+		qdf_mem_free(req->pmk.pmk);
+		qdf_mem_free(req->ndp_info.ndp_app_info);
+		qdf_mem_free(req->ndp_config.ndp_cfg);
+		break;
+	}
+	case NDP_END_REQ: {
+		struct nan_datapath_end_req *req = in_req;
+		vdev = req->vdev;
+		qdf_mem_free(req->ndp_ids);
+		break;
+	}
+	default:
+		nan_err("invalid req type: %d", req_type);
+		break;
+	}
+
+	if (vdev)
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
+	else
+		nan_err("vdev is null");
+
+	qdf_mem_free(in_req);
+}
+
+static void nan_req_incomplete(void *req, uint32_t cmdtype)
+{
+	/* send msg to userspace if needed that cmd got incomplete */
+}
+
+static void nan_req_activated(void *in_req, uint32_t cmdtype)
+{
+	uint32_t req_type;
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_lmac_if_nan_tx_ops *tx_ops;
+
+	switch (cmdtype) {
+	case WLAN_SER_CMD_NDP_INIT_REQ: {
+		struct nan_datapath_initiator_req *req = in_req;
+		vdev = req->vdev;
+		req_type = NDP_INITIATOR_REQ;
+		break;
+	}
+	case WLAN_SER_CMD_NDP_RESP_REQ: {
+		struct nan_datapath_responder_req *req = in_req;
+		vdev = req->vdev;
+		req_type = NDP_RESPONDER_REQ;
+		break;
+	}
+	case WLAN_SER_CMD_NDP_DATA_END_INIT_REQ: {
+		struct nan_datapath_end_req *req = in_req;
+		vdev = req->vdev;
+		req_type = NDP_END_REQ;
+		break;
+	}
+	default:
+		nan_alert("in correct cmdtype: %d", cmdtype);
+		return;
+	}
+
+	if (!vdev) {
+		nan_alert("vdev is null");
+		return;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		nan_alert("psoc is null");
+		return;
+	}
+
+	tx_ops = target_if_nan_get_tx_ops(psoc);
+	if (!tx_ops) {
+		nan_alert("tx_ops is null");
+		return;
+	}
+
+	/* send ndp_intiator_req/responder_req/end_req to FW */
+	tx_ops->nan_req_tx(in_req, req_type);
+}
+
+static QDF_STATUS nan_serialized_cb(void *cmd,
+				enum wlan_serialization_cb_reason reason)
+{
+	void *req;
+	struct wlan_serialization_command *ser_cmd = cmd;
+
+	if (!ser_cmd || !ser_cmd->umac_cmd) {
+		nan_alert("cmd or umac_cmd is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = ser_cmd->umac_cmd;
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		nan_req_activated(req, ser_cmd->cmd_type);
+		break;
+	case WLAN_SER_CB_CANCEL_CMD:
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		nan_req_incomplete(req, ser_cmd->cmd_type);
+		break;
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		nan_release_cmd(req, ser_cmd->cmd_type);
+		break;
+	default:
+		/* Do nothing but logging */
+		nan_alert("invalid serialized cb reason: %d", reason);
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg)
+{
+	QDF_STATUS ref_status;
+	enum wlan_serialization_status status = 0;
+	struct wlan_serialization_command cmd = {0};
+
+	if (!msg || !msg->bodyptr) {
+		nan_alert("msg or bodyptr is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	switch (msg->type) {
+	case NDP_INITIATOR_REQ: {
+		struct nan_datapath_initiator_req *req = msg->bodyptr;
+		cmd.cmd_type = WLAN_SER_CMD_NDP_INIT_REQ;
+		cmd.vdev = req->vdev;
+		break;
+	}
+	case NDP_RESPONDER_REQ: {
+		struct nan_datapath_responder_req *req = msg->bodyptr;
+		cmd.cmd_type = WLAN_SER_CMD_NDP_RESP_REQ;
+		cmd.vdev = req->vdev;
+		break;
+	}
+	case NDP_END_REQ: {
+		struct nan_datapath_end_req *req = msg->bodyptr;
+		cmd.cmd_type = WLAN_SER_CMD_NDP_DATA_END_INIT_REQ;
+		cmd.vdev = req->vdev;
+		break;
+	}
+	default:
+		nan_err("wrong request type: %d", msg->type);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* try get ref now, if failure, then vdev may have been deleted */
+	ref_status = wlan_objmgr_vdev_try_get_ref(cmd.vdev, WLAN_NAN_ID);
+	if (QDF_IS_STATUS_ERROR(ref_status)) {
+		nan_alert("couldn't get ref. vdev maybe deleted");
+		return QDF_STATUS_E_INVAL;
+	}
+	/* reference will be released when ser command finishes */
+
+	/* TBD - support more than one req of same type or avoid */
+	cmd.cmd_id = 0;
+	cmd.cmd_cb = nan_serialized_cb;
+	cmd.umac_cmd = msg->bodyptr;
+	cmd.source = WLAN_UMAC_COMP_NAN;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = 30000 /* 30 sec for now. TBD */;
+
+	status = wlan_serialization_request(&cmd);
+	/* following is TBD */
+	if (status != WLAN_SER_CMD_ACTIVE && status != WLAN_SER_CMD_PENDING) {
+		nan_err("unable to serialize command");
+		wlan_objmgr_vdev_release_ref(cmd.vdev, WLAN_NAN_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+	return QDF_STATUS_SUCCESS;
+}

+ 18 - 0
umac/nan/core/src/nan_main_i.h

@@ -104,4 +104,22 @@ struct nan_vdev_priv_obj *nan_get_vdev_priv_obj(struct wlan_objmgr_vdev *vdev);
  */
 struct nan_psoc_priv_obj *nan_get_psoc_priv_obj(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * nan_release_cmd: frees resources for NAN command.
+ * @in_req: pointer to msg buffer to be freed
+ * @req_type: type of request
+ *
+ * Return: None
+ */
+void nan_release_cmd(void *in_req, uint32_t req_type);
+
+/**
+ * nan_scheduled_msg_handler: callback pointer to be called when scheduler
+ * starts executing enqueued NAN command.
+ * @msg: pointer to msg
+ *
+ * Return: status of operation
+ */
+QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg);
+
 #endif

+ 11 - 0
umac/nan/dispatcher/inc/nan_ucfg_api.h

@@ -170,4 +170,15 @@ uint32_t ucfg_nan_get_ndi_delete_rsp_status(struct wlan_objmgr_vdev *vdev);
 QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc,
 				  struct nan_callbacks *cb_obj);
 
+/**
+ * ucfg_nan_req_processor: ucfg API to be called from HDD/OS_IF to
+ * process nan datapath initiator request from userspace
+ * @in_req: NDP request
+ * @psoc: pointer to psoc object
+ * @req_type: type of request
+ *
+ * Return: status of operation
+ */
+QDF_STATUS ucfg_nan_req_processor(void *in_req, uint32_t req_type);
+
 #endif /* _NAN_UCFG_API_H_ */

+ 23 - 0
umac/nan/dispatcher/src/nan_ucfg_api.c

@@ -23,6 +23,7 @@
 #include "nan_ucfg_api.h"
 #include "nan_public_structs.h"
 #include "../../core/src/nan_main_i.h"
+#include "scheduler_api.h"
 
 inline QDF_STATUS ucfg_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev,
 					 uint32_t state)
@@ -294,3 +295,25 @@ inline QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS ucfg_nan_req_processor(void *in_req, uint32_t req_type)
+{
+	QDF_STATUS status;
+	struct scheduler_msg msg = {0};
+
+	if (!in_req) {
+		nan_alert("req is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	msg.type = req_type;
+	msg.bodyptr = in_req;
+	msg.callback = nan_scheduled_msg_handler;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		nan_err("faild to post msg to NAN component, status: %d",
+			status);
+	}
+
+	return status;
+}