Prechádzať zdrojové kódy

qcacmn: Implement WIFI_POS commands

Implement following commands for WIFI_POS:
1) ANI_MSG_APP_REG_REQ
2) ANI_MSG_CHANNEL_INFO_REQ
3) ANI_MSG_SET_OEM_CAP_REQ
4) ANI_MSG_GET_OEM_CAP_REQ
5) ANI_MSG_OEM_DATA_REQ
6) ANI_MSG_PEER_STATUS_IND

Change-Id: I7e3b502660b169f4cdb654cb5f433446a24d2421
CRs-Fixed: 2003488
Naveen Rawat 8 rokov pred
rodič
commit
922724f2db

+ 226 - 9
os_if/linux/wifi_pos/src/os_if_wifi_pos.c

@@ -37,10 +37,126 @@
 #include "os_if_wifi_pos.h"
 #include "wifi_pos_api.h"
 #include "wlan_cfg80211.h"
+#include "wlan_objmgr_psoc_obj.h"
 #ifdef CNSS_GENL
 #include <net/cnss_nl.h>
 #endif
 
+/**
+ * os_if_wifi_pos_send_rsp() - send oem registration response
+ *
+ * This function sends oem message to registered application process
+ *
+ * Return:  none
+ */
+static void os_if_wifi_pos_send_rsp(uint32_t pid, uint32_t rsp_msg_type,
+				    uint32_t buf_len, uint8_t *buf)
+{
+	tAniMsgHdr *aniHdr;
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+
+	/* OEM msg is always to a specific process and cannot be a broadcast */
+	if (pid == 0) {
+		cfg80211_err("invalid dest pid");
+		return;
+	}
+
+	skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len), GFP_ATOMIC);
+	if (skb == NULL) {
+		cfg80211_alert("alloc_skb failed");
+		return;
+	}
+
+	nlh = (struct nlmsghdr *)skb->data;
+	nlh->nlmsg_pid = 0;     /* from kernel */
+	nlh->nlmsg_flags = 0;
+	nlh->nlmsg_seq = 0;
+	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
+	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + buf_len);
+
+	aniHdr = NLMSG_DATA(nlh);
+	aniHdr->type = rsp_msg_type;
+	qdf_mem_copy(&aniHdr[1], buf, buf_len);
+	aniHdr->length = buf_len;
+
+	skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len));
+	cfg80211_debug("sending oem rsp: type: %d len(%d) to pid (%d)",
+		      rsp_msg_type, buf_len, pid);
+	nl_srv_ucast_oem(skb, pid, MSG_DONTWAIT);
+}
+
+#ifdef CNSS_GENL
+static int  wifi_pos_parse_req(const void *data, int len, int pid,
+		    struct wifi_pos_req_msg *req)
+{
+	tAniMsgHdr *msg_hdr;
+	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
+
+	if (nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
+		cfg80211_err("invalid data in request");
+		return OEM_ERR_INVALID_MESSAGE_TYPE;
+	}
+
+	if (!tb[CLD80211_ATTR_DATA]) {
+		cfg80211_err("CLD80211_ATTR_DATA not present");
+		return OEM_ERR_INVALID_MESSAGE_TYPE;
+	}
+
+	msg_hdr = (tAniMsgHdr *)nla_data(tb[CLD80211_ATTR_DATA]);
+	if (!msg_hdr) {
+		cfg80211_err("msg_hdr null");
+		return OEM_ERR_NULL_MESSAGE_HEADER;
+	}
+
+	req->msg_type = msg_hdr->type;
+	req->buf_len = msg_hdr->length;
+	req->buf = (uint8_t *)&msg_hdr[1];
+	req->pid = pid;
+
+	if (tb[CLD80211_ATTR_META_DATA]) {
+		req->field_info_buf = (struct wifi_pos_field_info *)
+					nla_data(tb[CLD80211_ATTR_META_DATA]);
+		req->field_info_buf_len = nla_len(tb[CLD80211_ATTR_META_DATA]);
+	}
+
+	return 0;
+}
+#else
+static int wifi_pos_parse_req(struct sk_buff *skb, struct wifi_pos_req_msg *req)
+{
+	/* SKB->data contains NL msg */
+	/* NLMSG_DATA(nlh) contains ANI msg */
+	struct nlmsghdr *nlh;
+	tAniMsgHdr *msg_hdr;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	if (!nlh) {
+		cfg80211_err("Netlink header null");
+		return OEM_ERR_NULL_MESSAGE_HEADER;
+	}
+
+	msg_hdr = NLMSG_DATA(nlh);
+	if (!msg_hdr) {
+		cfg80211_err("Message header null");
+		return OEM_ERR_NULL_MESSAGE_HEADER;
+	}
+
+	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length)) {
+		cfg80211_err("nlmsg_len(%d) and animsg_len(%d) mis-match",
+			nlh->nlmsg_len, msg_hdr->length);
+		return OEM_ERR_INVALID_MESSAGE_LENGTH;
+	}
+
+	req->msg_type = msg_hdr->type;
+	req->buf_len = msg_hdr->length;
+	req->buf = (uint8_t *)&msg_hdr[1];
+	req->pid = nlh->nlmsg_pid;
+
+	return 0;
+}
+#endif
+
 /**
  * os_if_wifi_pos_callback() - callback registered with NL service socket to
  * process wifi pos request
@@ -52,26 +168,70 @@
 static void os_if_wifi_pos_callback(const void *data, int data_len,
 				    void *ctx, int pid)
 {
+	uint8_t err;
 	QDF_STATUS status;
 	struct wifi_pos_req_msg req = {0};
 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
 
+	cfg80211_debug("enter: pid %d", pid);
 	if (!psoc) {
 		cfg80211_err("global psoc object not registered yet.");
 		return;
 	}
 
 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_ID);
+	err = wifi_pos_parse_req(data, data_len, pid, &req);
+	if (err) {
+		os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc),
+					ANI_MSG_OEM_ERROR, sizeof(err), &err);
+		status = QDF_STATUS_E_INVAL;
+		goto release_psoc_ref;
+	}
+
+	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
+	if (QDF_IS_STATUS_ERROR(status))
+		cfg80211_err("ucfg_wifi_pos_process_req failed. status: %d",
+				status);
+
+release_psoc_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_ID);
+}
+#else
+static int os_if_wifi_pos_callback(struct sk_buff *skb)
+{
+	uint8_t err;
+	QDF_STATUS status;
+	struct wifi_pos_req_msg req = {0};
+	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
+
+	cfg80211_debug("enter");
+	if (!psoc) {
+		cfg80211_err("global psoc object not registered yet.");
+		return -EINVAL;
+	}
+
+	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_ID);
+	err = wifi_pos_parse_req(skb, &req);
+	if (err) {
+		os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc),
+					ANI_MSG_OEM_ERROR, sizeof(err), &err);
+		status = QDF_STATUS_E_INVAL;
+		goto release_psoc_ref;
+	}
 
-	/* implemention is TBD */
-	status = ucfg_wifi_pos_process_req(psoc, &req, NULL);
+	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
 	if (QDF_IS_STATUS_ERROR(status))
 		cfg80211_err("ucfg_wifi_pos_process_req failed. status: %d",
 				status);
 
+release_psoc_ref:
 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_ID);
+
+	return qdf_status_to_os_return(status);
 }
+#endif
 
+#ifdef CNSS_GENL
 int os_if_wifi_pos_register_nl(void)
 {
 	int ret = register_cld_cmd_cb(WLAN_NL_MSG_OEM,
@@ -81,7 +241,14 @@ int os_if_wifi_pos_register_nl(void)
 
 	return ret;
 }
+#else
+int os_if_wifi_pos_register_nl(void)
+{
+	return nl_srv_register(WLAN_NL_MSG_OEM, os_if_wifi_pos_callback);
+}
+#endif /* CNSS_GENL */
 
+#ifdef CNSS_GENL
 int os_if_wifi_pos_deregister_nl(void)
 {
 	int ret = deregister_cld_cmd_cb(WLAN_NL_MSG_OEM);
@@ -91,16 +258,11 @@ int os_if_wifi_pos_deregister_nl(void)
 	return ret;
 }
 #else
-int os_if_wifi_pos_register_nl(void)
-{
-	return 0;
-}
-
 int os_if_wifi_pos_deregister_nl(void)
 {
 	return 0;
 }
-#endif
+#endif /* CNSS_GENL */
 
 void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac,
 				uint8_t peer_status,
@@ -109,7 +271,62 @@ void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac,
 				struct wifi_pos_ch_info *chan_info,
 				enum tQDF_ADAPTER_MODE dev_mode)
 {
-	/* implemention TBD */
+	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
+	struct wmi_pos_peer_status_info *peer_info;
+
+	if (!psoc) {
+		cfg80211_err("global wifi_pos psoc object not registered");
+		return;
+	}
+
+	if (!wifi_pos_is_app_registered(psoc) ||
+			wifi_pos_get_app_pid(psoc) == 0) {
+		cfg80211_err("app is not registered or pid is invalid");
+		return;
+	}
+
+	peer_info = qdf_mem_malloc(sizeof(*peer_info));
+	if (!peer_info) {
+		cfg80211_alert("malloc failed");
+		return;
+	}
+	qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes,
+		     sizeof(peer_mac->bytes));
+	peer_info->peer_status = peer_status;
+	peer_info->vdev_id = session_id;
+	peer_info->peer_capability = peer_timing_meas_cap;
+	peer_info->reserved0 = 0;
+	/* Set 0th bit of reserved0 for STA mode */
+	if (QDF_STA_MODE == dev_mode)
+		peer_info->reserved0 |= 0x01;
+
+	if (chan_info) {
+		peer_info->peer_chan_info.chan_id = chan_info->chan_id;
+		peer_info->peer_chan_info.reserved0 = 0;
+		peer_info->peer_chan_info.mhz = chan_info->mhz;
+		peer_info->peer_chan_info.band_center_freq1 =
+			chan_info->band_center_freq1;
+		peer_info->peer_chan_info.band_center_freq2 =
+			chan_info->band_center_freq2;
+		peer_info->peer_chan_info.info = chan_info->info;
+		peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
+		peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
+	}
+
+	os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc),
+				ANI_MSG_PEER_STATUS_IND,
+				sizeof(*peer_info), (uint8_t *)peer_info);
+	return;
+}
+
+void os_if_wifi_pos_set_ftm_cap(struct wlan_objmgr_psoc *psoc, uint32_t val)
+{
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	wifi_pos_set_ftm_cap(psoc, val);
 }
 
 int os_if_wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,

+ 31 - 4
target_if/wifi_pos/src/target_if_wifi_pos.c

@@ -49,17 +49,44 @@ static int wifi_pos_oem_rsp_ev_handler(ol_scn_t scn,
 					uint8_t *data_buf,
 					uint32_t data_len)
 {
-	struct oem_data_rsp *oem_rsp = NULL;
-	struct wlan_objmgr_psoc *psoc = NULL;
+	int ret;
+	struct oem_data_rsp oem_rsp = {0};
+	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc;
+	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
 	struct wlan_lmac_if_wifi_pos_rx_ops *wifi_pos_rx_ops = NULL;
+	WMI_OEM_RESPONSE_EVENTID_param_tlvs *param_buf =
+		(WMI_OEM_RESPONSE_EVENTID_param_tlvs *)data_buf;
 
+	if (!psoc) {
+		wifi_pos_err("psoc is null");
+		return QDF_STATUS_NOT_INITIALIZED;
+	}
+	wifi_pos_psoc = wifi_pos_get_psoc_priv_obj(psoc);
+	if (!wifi_pos_psoc) {
+		wifi_pos_err("wifi_pos_psoc is null");
+		return QDF_STATUS_NOT_INITIALIZED;
+	}
+	qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock);
+	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_ID);
+
+	wifi_pos_rx_ops = target_if_wifi_pos_get_rxops(psoc);
 	/* this will be implemented later */
 	if (!wifi_pos_rx_ops || !wifi_pos_rx_ops->oem_rsp_event_rx) {
 		wifi_pos_err("lmac callbacks not registered");
-		return QDF_STATUS_NOT_INITIALIZED;
+		ret = QDF_STATUS_NOT_INITIALIZED;
+		goto release_psoc_ref;
 	}
 
-	return wifi_pos_rx_ops->oem_rsp_event_rx(psoc, oem_rsp);
+	oem_rsp.rsp_len = param_buf->num_data;
+	oem_rsp.data = param_buf->data;
+
+	ret = wifi_pos_rx_ops->oem_rsp_event_rx(psoc, &oem_rsp);
+
+release_psoc_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_ID);
+	qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock);
+
+	return ret;
 }
 
 /**

+ 49 - 0
umac/wifi_pos/inc/wifi_pos_api.h

@@ -34,6 +34,8 @@
 
 /* Include files */
 #include "qdf_types.h"
+#include "qdf_status.h"
+#include "qdf_trace.h"
 
 /* forward reference */
 struct wlan_objmgr_psoc;
@@ -134,6 +136,19 @@ struct wifi_pos_req_msg {
 	uint32_t field_info_buf_len;
 };
 
+/**
+ * ucfg_wifi_pos_process_req: ucfg API to be called from HDD/OS_IF to process a
+ * wifi_pos request from userspace
+ * @psoc: pointer to psoc object
+ * @req: wifi_pos request msg
+ * @send_rsp_cb: callback pointer required to send msg to userspace
+ *
+ * Return: status of operation
+ */
+QDF_STATUS ucfg_wifi_pos_process_req(struct wlan_objmgr_psoc *psoc,
+		struct wifi_pos_req_msg *req,
+		void (*send_rsp_cb)(uint32_t, uint32_t, uint32_t, uint8_t *));
+
 /**
  * wifi_pos_init: initializes WIFI POS component, called by dispatcher init
  *
@@ -276,6 +291,40 @@ void wifi_pos_set_current_dwell_time_max(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
 			   struct wifi_pos_driver_caps *caps);
 
+/**
+ * wifi_pos_set_ftm_cap: API to set fine timing measurement caps
+ * @psoc: psoc object
+ * @val: value to set
+ *
+ * Return: None
+ */
+void wifi_pos_set_ftm_cap(struct wlan_objmgr_psoc *psoc, uint32_t val);
+
+/**
+ * wifi_pos_get_app_pid: returns oem app pid.
+ * @psoc: pointer to psoc object
+ *
+ * Return: oem app pid
+ */
+uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wifi_pos_is_app_registered: indicates if oem app is registered.
+ * @psoc: pointer to psoc object
+ *
+ * Return: true if app is registered, false otherwise
+ */
+bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wifi_pos_get_psoc: API to get global PSOC object
+ *
+ * Since request from userspace is not associated with any vdev/pdev/psoc, this
+ * API is used to get global psoc object.
+ * Return: global psoc object.
+ */
+struct wlan_objmgr_psoc *wifi_pos_get_psoc(void);
+
 #else
 static inline QDF_STATUS wifi_pos_init(void)
 {

+ 53 - 0
umac/wifi_pos/src/wifi_pos_api.c

@@ -204,3 +204,56 @@ void wifi_pos_set_current_dwell_time_min(struct wlan_objmgr_psoc *psoc,
 	wifi_pos_psoc->current_dwell_time_max = val;
 	qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock);
 }
+
+void wifi_pos_set_ftm_cap(struct wlan_objmgr_psoc *psoc, uint32_t val)
+{
+	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
+			wifi_pos_get_psoc_priv_obj(psoc);
+
+	if (!wifi_pos_psoc) {
+		wifi_pos_alert("unable to get wifi_pos psoc obj");
+		return;
+	}
+
+	qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock);
+	wifi_pos_psoc->fine_time_meas_cap = val;
+	qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock);
+}
+
+uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t app_pid;
+	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
+				wifi_pos_get_psoc_priv_obj(psoc);
+
+	if (!wifi_pos_psoc) {
+		wifi_pos_err("wifi_pos priv obj is null");
+		return 0;
+	}
+
+	qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock);
+	app_pid = wifi_pos_psoc->app_pid;
+	qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock);
+
+	return app_pid;
+
+}
+
+bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc)
+{
+	bool is_app_registered;
+	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
+				wifi_pos_get_psoc_priv_obj(psoc);
+
+	if (!wifi_pos_psoc) {
+		wifi_pos_err("wifi_pos priv obj is null");
+		return false;
+	}
+
+	qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock);
+	is_app_registered = wifi_pos_psoc->is_app_registered;
+	qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock);
+
+	return is_app_registered;
+}
+

+ 291 - 6
umac/wifi_pos/src/wifi_pos_main.c

@@ -31,7 +31,7 @@
  * wifi positioning to initialize and de-initialize the component.
  */
 #include "target_if_wifi_pos.h"
-#include "os_if_wifi_pos.h"
+#include "wifi_pos_oem_interface_i.h"
 #include "wifi_pos_utils_i.h"
 #include "wifi_pos_api.h"
 #include "wifi_pos_main_i.h"
@@ -39,6 +39,9 @@
 #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"
+#include "wlan_ptt_sock_svc.h"
 
 #ifdef UMAC_REG_COMPONENT
 /* enable this when regulatory component gets merged */
@@ -47,6 +50,15 @@
 struct regulatory_channel;
 #endif
 
+/*
+ * obj mgr api to iterate over vdevs does not provide a direct array or vdevs,
+ * rather takes a callback that is called for every vdev. wifi pos needs to
+ * store device mode and vdev id of all active vdevs and provide this info to
+ * user space as part of APP registration response. due to this, vdev_idx is
+ * used to identify how many vdevs have been populated by obj manager API.
+ */
+static uint32_t vdev_idx;
+
 /**
  * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg
  * @psoc: psoc object
@@ -59,6 +71,263 @@ static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc)
 	return true;
 }
 
+static int wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
+					struct wifi_pos_req_msg *req)
+{
+	uint8_t idx;
+	uint32_t sub_type = 0;
+	uint32_t channel_mhz = 0;
+	void *pdev_id = NULL;
+	uint32_t offset;
+	struct oem_data_req data_req;
+	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
+
+	wifi_pos_debug("Received data req pid(%d), len(%d)",
+			req->pid, req->buf_len);
+
+	/* look for fields */
+	if (req->field_info_buf)
+		for (idx = 0; idx < req->field_info_buf->count; idx++) {
+			offset = req->field_info_buf->fields[idx].offset;
+			/*
+			 * replace following reads with read_api based on
+			 * length
+			 */
+			if (req->field_info_buf->fields[idx].id ==
+					WMIRTT_FIELD_ID_oem_data_sub_type) {
+				sub_type = *((uint32_t *)&req->buf[offset]);
+				continue;
+			}
+
+			if (req->field_info_buf->fields[idx].id ==
+					WMIRTT_FIELD_ID_channel_mhz) {
+				channel_mhz = *((uint32_t *)&req->buf[offset]);
+				continue;
+			}
+
+			if (req->field_info_buf->fields[idx].id ==
+					WMIRTT_FIELD_ID_pdev) {
+				pdev_id = &req->buf[offset];
+				continue;
+			}
+		}
+
+	switch (sub_type) {
+	case TARGET_OEM_CAPABILITY_REQ:
+		/* TBD */
+		break;
+	case TARGET_OEM_CONFIGURE_LCR:
+		/* TBD */
+		break;
+	case TARGET_OEM_CONFIGURE_LCI:
+		/* TBD */
+		break;
+	case TARGET_OEM_MEASUREMENT_REQ:
+		/* TBD */
+		break;
+	case TARGET_OEM_CONFIGURE_FTMRR:
+		/* TBD */
+		break;
+	case TARGET_OEM_CONFIGURE_WRU:
+		/* TBD */
+		break;
+	default:
+		wifi_pos_debug("invalid sub type or not passed");
+		/*
+		 * this is legacy MCL operation. pass whole msg to firmware as
+		 * it is.
+		 */
+		tx_ops = target_if_wifi_pos_get_txops(psoc);
+		data_req.data_len = req->buf_len;
+		data_req.data = req->buf;
+		tx_ops->data_req_tx(psoc, &data_req);
+		break;
+	}
+
+	return 0;
+}
+
+static int wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc,
+					struct wifi_pos_req_msg *req)
+{
+	int error_code;
+	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
+				wifi_pos_get_psoc_priv_obj(psoc);
+	struct wifi_pos_user_defined_caps *caps =
+				(struct wifi_pos_user_defined_caps *)req->buf;
+
+	wifi_pos_debug("Received set cap req pid(%d), len(%d)",
+			req->pid, req->buf_len);
+
+	wifi_pos_obj->ftm_rr = caps->ftm_rr;
+	wifi_pos_obj->lci_capability = caps->lci_capability;
+	error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS);
+	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
+					ANI_MSG_SET_OEM_CAP_RSP,
+					sizeof(error_code),
+					(uint8_t *)&error_code);
+
+	return 0;
+}
+
+static int wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc,
+					struct wifi_pos_req_msg *req)
+{
+	struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } };
+	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
+					wifi_pos_get_psoc_priv_obj(psoc);
+
+	wifi_pos_debug("Received get cap req pid(%d), len(%d)",
+			req->pid, req->buf_len);
+
+	wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap);
+	cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr;
+	cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability;
+	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
+					ANI_MSG_GET_OEM_CAP_RSP,
+					sizeof(cap_rsp),
+					(uint8_t *)&cap_rsp);
+
+	return 0;
+}
+
+static int wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
+					struct wifi_pos_req_msg *req)
+{
+	uint8_t idx;
+	uint8_t *buf;
+	uint32_t len;
+	uint8_t *channels = req->buf;
+	uint32_t num_ch = req->buf_len;
+	struct wifi_pos_ch_info_rsp *ch_info;
+	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
+					wifi_pos_get_psoc_priv_obj(psoc);
+
+	wifi_pos_debug("Received ch info req pid(%d), len(%d)",
+			req->pid, req->buf_len);
+
+	len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) * num_ch;
+	buf = qdf_mem_malloc(len);
+	if (!buf) {
+		wifi_pos_alert("malloc failed");
+		return -ENOMEM;
+	}
+
+	/* First byte of message body will have num of channels */
+	buf[0] = num_ch;
+	ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1];
+	for (idx = 0; idx < num_ch; idx++) {
+		ch_info[idx].chan_id = channels[idx];
+		ch_info[idx].reserved0 = 0;
+#ifdef UMAC_REG_COMPONENT
+		/*
+		 * please note that this is feature macro temp and will go away
+		 * once regulatory component gets merged:
+		 * identify regulatory API to get following information
+		 */
+		ch_info[idx].mhz = cds_chan_to_freq(channels[idx]);
+		ch_info[idx].band_center_freq1 = ch_info[idx].mhz;
+#endif
+		ch_info[idx].band_center_freq2 = 0;
+		ch_info[idx].info = 0;
+#ifdef UMAC_REG_COMPONENT
+		/*
+		 * please note that this is feature macro temp and will go away
+		 * once regulatory component gets merged:
+		 * identify regulatory API to replace update_channel_bw_info
+		 * and to get following information
+		 */
+		if (CHANNEL_STATE_DFS == cds_get_channel_state(channels[idx]))
+			WMI_SET_CHANNEL_FLAG(&ch_info[idx], WMI_CHAN_FLAG_DFS);
+#endif
+		ch_info[idx].reg_info_1 = 0;
+		ch_info[idx].reg_info_2 = 0;
+	}
+
+	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
+					ANI_MSG_CHANNEL_INFO_RSP,
+					len, buf);
+	qdf_mem_free(buf);
+	return 0;
+}
+
+static void wifi_pos_populate_vdev_info(struct wlan_objmgr_psoc *psoc,
+					void *vdev, void *arg)
+{
+	struct app_reg_rsp_vdev_info *vdev_info = arg;
+
+	wlan_vdev_obj_lock(vdev);
+	vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev);
+	vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev);
+	wlan_vdev_obj_unlock(vdev);
+	vdev_idx++;
+}
+
+static int wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
+					struct wifi_pos_req_msg *req)
+{
+	int ret = 0;
+	uint8_t err = 0;
+	uint32_t rsp_len;
+	char *sign_str = NULL;
+	struct wifi_app_reg_rsp *app_reg_rsp;
+	struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS]
+								= { { 0 } };
+	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
+			wifi_pos_get_psoc_priv_obj(psoc);
+
+	wifi_pos_err("Received App Req Req pid(%d), len(%d)",
+			req->pid, req->buf_len);
+
+	sign_str = (char *)req->buf;
+	/* Registration request is only allowed for Qualcomm Application */
+	if ((OEM_APP_SIGNATURE_LEN != req->buf_len) ||
+		(strncmp(sign_str, OEM_APP_SIGNATURE_STR,
+			 OEM_APP_SIGNATURE_LEN))) {
+		wifi_pos_err("Invalid signature pid(%d)", req->pid);
+		ret = -EPERM;
+		err = OEM_ERR_INVALID_SIGNATURE;
+		goto app_reg_failed;
+	}
+
+	wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid);
+	wifi_pos_obj->is_app_registered = true;
+	wifi_pos_obj->app_pid = req->pid;
+
+	vdev_idx = 0;
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
+				     wifi_pos_populate_vdev_info,
+				     vdevs_info, 1, WLAN_WIFI_POS_ID);
+	rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
+			+ sizeof(uint8_t);
+	app_reg_rsp = qdf_mem_malloc(rsp_len);
+	if (!app_reg_rsp) {
+		wifi_pos_alert("malloc failed");
+		ret = -ENOMEM;
+		err = OEM_ERR_NULL_CONTEXT;
+		goto app_reg_failed;
+	}
+
+	app_reg_rsp->num_inf = vdev_idx;
+	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
+		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
+	if (!vdev_idx)
+		wifi_pos_debug("no active vdev");
+
+	vdev_idx = 0;
+	wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_APP_REG_RSP,
+					rsp_len, (uint8_t *)app_reg_rsp);
+
+	qdf_mem_free(app_reg_rsp);
+	return ret;
+
+app_reg_failed:
+
+	wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_OEM_ERROR,
+					sizeof(err), &err);
+	return ret;
+}
+
 /**
  * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req
  * @wmi_msg: wmi type request msg
@@ -68,9 +337,23 @@ static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc)
 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc,
 					struct wifi_pos_req_msg *req)
 {
-	/* actual implementation of cmds start here */
-	/* TBD - decide if ANI_MSG_OEM_DATA_REQ goest to MC thread or not */
-	return QDF_STATUS_SUCCESS;
+	wifi_pos_debug("enter: msg_type: %d", req->msg_type);
+	switch (req->msg_type) {
+	case ANI_MSG_APP_REG_REQ:
+		return wifi_pos_process_app_reg_req(psoc, req);
+	case ANI_MSG_OEM_DATA_REQ:
+		return wifi_pos_process_data_req(psoc, req);
+	case ANI_MSG_CHANNEL_INFO_REQ:
+		return wifi_pos_process_ch_info_req(psoc, req);
+	case ANI_MSG_SET_OEM_CAP_REQ:
+		return wifi_pos_process_set_cap_req(psoc, req);
+	case ANI_MSG_GET_OEM_CAP_REQ:
+		return wifi_pos_process_get_cap_req(psoc, req);
+	default:
+		wifi_pos_err("invalid request type");
+		break;
+	}
+	return 0;
 }
 
 /**
@@ -190,8 +473,10 @@ int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc,
 
 	wifi_pos_debug("sending oem data rsp, len: %d to pid: %d",
 			oem_rsp->rsp_len, wifi_pos_obj->app_pid);
-	wifi_pos_obj->wifi_pos_send_rsp(psoc, ANI_MSG_OEM_DATA_RSP,
-					oem_rsp->rsp_len, oem_rsp->data);
+	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
+					ANI_MSG_OEM_DATA_RSP,
+					oem_rsp->rsp_len,
+					oem_rsp->data);
 	return 0;
 }
 

+ 41 - 0
umac/wifi_pos/src/wifi_pos_oem_interface_i.h

@@ -22,4 +22,45 @@
 #ifndef _WIFI_POS_OEM_INTERFACE_H_
 #define _WIFI_POS_OEM_INTERFACE_H_
 
+/* Include files */
+#include "qdf_types.h"
+#include "qdf_status.h"
+#include "wlan_objmgr_cmn.h"
+
+#define TARGET_OEM_CAPABILITY_REQ       0x01
+#define TARGET_OEM_CAPABILITY_RSP       0x02
+#define TARGET_OEM_MEASUREMENT_REQ      0x03
+#define TARGET_OEM_MEASUREMENT_RSP      0x04
+#define TARGET_OEM_ERROR_REPORT_RSP     0x05
+#define TARGET_OEM_NAN_MEAS_REQ         0x06
+#define TARGET_OEM_NAN_MEAS_RSP         0x07
+#define TARGET_OEM_NAN_PEER_INFO        0x08
+#define TARGET_OEM_CONFIGURE_LCR        0x09
+#define TARGET_OEM_CONFIGURE_LCI        0x0A
+#define TARGET_OEM_CONFIGURE_WRU        0x80
+#define TARGET_OEM_CONFIGURE_FTMRR      0x81
+
+struct wifi_pos_field {
+	uint32_t id;
+	uint32_t offset;
+	uint32_t length;
+};
+
+struct wifi_pos_field_info {
+	uint32_t count;
+	struct wifi_pos_field fields[1];
+};
+
+/**
+ * enum WMIRTT_FIELD_ID - identifies which field is being specified
+ * @WMIRTT_FIELD_ID_oem_data_sub_type: oem data req sub type
+ * @WMIRTT_FIELD_ID_channel_mhz: channel mhz info
+ * @WMIRTT_FIELD_ID_pdev: pdev info
+ */
+enum WMIRTT_FIELD_ID {
+	WMIRTT_FIELD_ID_oem_data_sub_type,
+	WMIRTT_FIELD_ID_channel_mhz,
+	WMIRTT_FIELD_ID_pdev,
+};
+
 #endif

+ 33 - 4
umac/wifi_pos/src/wifi_pos_ucfg.c

@@ -23,22 +23,51 @@
 #include "wifi_pos_utils_i.h"
 #include "wifi_pos_api.h"
 #include "wifi_pos_ucfg_i.h"
+#include "wlan_ptt_sock_svc.h"
 
 QDF_STATUS ucfg_wifi_pos_process_req(struct wlan_objmgr_psoc *psoc,
 		struct wifi_pos_req_msg *req,
-		void (*send_rsp_cb)(uint32_t *,
-			uint32_t, uint32_t, uint8_t *))
+		void (*send_rsp_cb)(uint32_t, uint32_t, uint32_t, uint8_t *))
 {
+	uint8_t err;
+	uint32_t app_pid;
+	QDF_STATUS status;
+	bool is_app_registered;
 	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc_obj =
 					wifi_pos_get_psoc_priv_obj(psoc);
 
+	wifi_pos_debug("enter");
+
 	if (!wifi_pos_psoc_obj) {
 		wifi_pos_err("wifi_pos_psoc_obj is null");
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
-	/* assign callback pointer to be called for rsp or error */
+	qdf_spin_lock_bh(&wifi_pos_psoc_obj->wifi_pos_lock);
 	wifi_pos_psoc_obj->wifi_pos_send_rsp = send_rsp_cb;
+	is_app_registered = wifi_pos_psoc_obj->is_app_registered;
+	app_pid = wifi_pos_psoc_obj->app_pid;
+	if (!wifi_pos_psoc_obj->wifi_pos_req_handler) {
+		wifi_pos_err("wifi_pos_psoc_obj->wifi_pos_req_handler is null");
+		err = OEM_ERR_NULL_CONTEXT;
+		send_rsp_cb(app_pid, ANI_MSG_OEM_ERROR, sizeof(err), &err);
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto unlock_and_exit;
+	}
+
+	if (req->msg_type != ANI_MSG_APP_REG_REQ &&
+		(!is_app_registered || app_pid != req->pid)) {
+		wifi_pos_err("requesting app is not registered, app_registered: %d, requesting pid: %d, stored pid: %d",
+			is_app_registered, req->pid, app_pid);
+		err = OEM_ERR_APP_NOT_REGISTERED;
+		send_rsp_cb(app_pid, ANI_MSG_OEM_ERROR, sizeof(err), &err);
+		status = QDF_STATUS_E_INVAL;
+		goto unlock_and_exit;
+	}
+
+	status = wifi_pos_psoc_obj->wifi_pos_req_handler(psoc, req);
 
-	return wifi_pos_psoc_obj->wifi_pos_req_handler(psoc, req);
+unlock_and_exit:
+	qdf_spin_unlock_bh(&wifi_pos_psoc_obj->wifi_pos_lock);
+	return status;
 }

+ 1 - 2
umac/wifi_pos/src/wifi_pos_ucfg_i.h

@@ -42,7 +42,6 @@ struct wifi_pos_req_msg;
  */
 QDF_STATUS ucfg_wifi_pos_process_req(struct wlan_objmgr_psoc *psoc,
 		struct wifi_pos_req_msg *req,
-		void (*send_rsp_cb)(struct wlan_objmgr_psoc *,
-			uint32_t, uint32_t, uint8_t *));
+		void (*send_rsp_cb)(uint32_t, uint32_t, uint32_t, uint8_t *));
 
 #endif /* _WIFI_POS_UCFG_H_ */

+ 0 - 38
umac/wifi_pos/src/wifi_pos_utils.c

@@ -74,41 +74,3 @@ struct wifi_pos_psoc_priv_obj *wifi_pos_get_psoc_priv_obj(
 
 	return obj;
 }
-
-bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc)
-{
-	struct wifi_pos_psoc_priv_obj *obj;
-
-	if (!psoc) {
-		wifi_pos_err("psoc is null");
-		return false;
-	}
-
-	obj = wifi_pos_get_psoc_priv_obj(psoc);
-
-	if (!obj) {
-		wifi_pos_err("wifi_pos priv obj is null");
-		return false;
-	}
-
-	return obj->is_app_registered;
-}
-
-uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc)
-{
-	struct wifi_pos_psoc_priv_obj *obj;
-
-	if (!psoc) {
-		wifi_pos_err("psoc is null");
-		return 0;
-	}
-
-	obj = wifi_pos_get_psoc_priv_obj(psoc);
-
-	if (!obj) {
-		wifi_pos_err("wifi_pos priv obj is null");
-		return 0;
-	}
-
-	return obj->app_pid;
-}

+ 51 - 30
umac/wifi_pos/src/wifi_pos_utils_i.h

@@ -41,6 +41,7 @@
 #include "qdf_trace.h"
 
 struct wlan_objmgr_psoc;
+struct wifi_pos_req_msg;
 
 #define wifi_pos_log(level, args...) \
 	QDF_TRACE(QDF_MODULE_ID_WIFIPOS, level, ## args)
@@ -70,6 +71,28 @@ struct wlan_objmgr_psoc;
 #define OEM_DATA_RSP_SIZE 1724
 #endif
 
+/**
+ * struct app_reg_rsp_vdev_info - vdev info struct
+ * @dev_mode: device mode
+ * @vdev_id: vdev id
+ *
+ */
+struct qdf_packed app_reg_rsp_vdev_info {
+	uint8_t dev_mode;
+	uint8_t vdev_id;
+};
+
+/**
+ * struct wifi_app_reg_rsp - app registration response struct
+ * @num_inf: number of interfaces active
+ * @vdevs: array indicating all active vdev's information
+ *
+ */
+struct qdf_packed wifi_app_reg_rsp {
+	uint8_t num_inf;
+	struct app_reg_rsp_vdev_info vdevs[1];
+};
+
 /**
  * struct oem_data_req - data request to be sent to firmware
  * @data_len: len of data
@@ -93,7 +116,7 @@ struct oem_data_rsp {
 };
 
 /**
- * typedef wifi_pos_driver_version - Driver version identifier (w.x.y.z)
+ * struct wifi_pos_driver_version - Driver version identifier (w.x.y.z)
  * @major: Version ID major number
  * @minor: Version ID minor number
  * @patch: Version ID patch number
@@ -134,13 +157,29 @@ struct qdf_packed wifi_pos_driver_caps {
 	uint8_t channel_list[OEM_CAP_MAX_NUM_CHANNELS];
 };
 
-struct wifi_pos_req_msg {
-	uint32_t msg_type;
-	uint32_t pid;
-	uint8_t *buf;
-	uint32_t buf_len;
-	struct wifi_pos_field_info *field_info_buf;
-	uint32_t field_info_buf_len;
+/**
+ * struct wifi_pos_user_defined_caps - OEM capability to be exchanged between host
+ * and userspace
+ * @ftm_rr: FTM range report capability bit
+ * @lci_capability: LCI capability bit
+ * @reserved1: reserved
+ * @reserved2: reserved
+ */
+struct wifi_pos_user_defined_caps {
+	uint32_t ftm_rr:1;
+	uint32_t lci_capability:1;
+	uint32_t reserved1:30;
+	uint32_t reserved2;
+};
+
+/**
+ * struct wifi_pos_oem_get_cap_rsp - capabilites set by userspace and target.
+ * @driver_cap: target capabilities
+ * @user_defined_cap: capabilities set by userspace via set request
+ */
+struct qdf_packed wifi_pos_oem_get_cap_rsp {
+	struct wifi_pos_driver_caps driver_cap;
+	struct wifi_pos_user_defined_caps user_defined_cap;
 };
 
 /**
@@ -184,9 +223,7 @@ struct wifi_pos_psoc_priv_obj {
 
 	QDF_STATUS (*wifi_pos_req_handler)(struct wlan_objmgr_psoc *psoc,
 				    struct wifi_pos_req_msg *req);
-	void (*wifi_pos_send_rsp)(struct wlan_objmgr_psoc *psoc,
-				  uint32_t rsp_msg_type, uint32_t buf_len,
-				  uint8_t *buf);
+	void (*wifi_pos_send_rsp)(uint32_t, uint32_t, uint32_t, uint8_t *);
 };
 
 /**
@@ -235,14 +272,6 @@ void wifi_pos_clear_psoc(void);
 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
 				  struct wifi_pos_driver_caps *caps);
 
-/**
- * wifi_pos_is_app_registered: indicates if oem app is registered.
- * @psoc: pointer to psoc object
- *
- * Return: true if app is registered, false otherwise
- */
-bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc);
-
 /**
  * wifi_pos_get_app_pid: returns oem app pid.
  * @psoc: pointer to psoc object
@@ -252,20 +281,12 @@ bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc);
 uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc);
 
 /**
- * wifi_pos_lock: acquires wifi_pos lock
- * @psoc: pointer to psoc object
- *
- * Return: None
- */
-void wifi_pos_lock(struct wlan_objmgr_psoc *psoc);
-
-/**
- * wifi_pos_unlock: releases wifi_pos lock
+ * wifi_pos_is_app_registered: indicates if oem app is registered.
  * @psoc: pointer to psoc object
  *
- * Return: None
+ * Return: true if app is registered, false otherwise
  */
-void wifi_pos_unlock(struct wlan_objmgr_psoc *psoc);
+bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc);
 
 #endif /* _WIFI_POS_UTILS_H_ */
 #endif /* WIFI_POS_CONVERGED */