Prechádzať zdrojové kódy

qcacmn: Add support for NLA type OEM_DATA REQ-RESP in LOWI

Host driver processes cld80211 vendor subcmd
CLD80211_VENDOR_SUB_CMD_OEM_DATA and send
response in NLA format. Peer status indication
is also sent in nla format

CRs-Fixed: 2597282
Change-Id: I94f1fb7939141952ef92dbb7d3a130ba20d31608
Vinay Gannevaram 5 rokov pred
rodič
commit
7ccc84acb3

+ 71 - 0
os_if/linux/wifi_pos/inc/os_if_wifi_pos.h

@@ -211,5 +211,76 @@ enum cld80211_sub_attr_channel_rsp {
 
 };
 
+/**
+ * enum cld80211_sub_attr_oem_data_req - OEM data req sub attribute
+ * @CLD80211_SUB_ATTR_MSG_OEM_DATA_INVALID: Invalid OEM data request
+ * @CLD80211_SUB_ATTR_MSG_OEM_DATA_FW: Data to Firmware
+ * @CLD80211_SUB_ATTR_MSG_OEM_DATA_DRIVER: Data to driver
+ * @CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX: Max number for OEM data req sub
+ * attribute
+ *
+ * OEM data request sub attributes are NLA attributes in NLA type OEM data
+ * request.
+ *
+ */
+enum cld80211_sub_attr_oem_data_req {
+	CLD80211_SUB_ATTR_MSG_OEM_DATA_INVALID = 0,
+	CLD80211_SUB_ATTR_MSG_OEM_DATA_FW = 1,
+	CLD80211_SUB_ATTR_MSG_OEM_DATA_DRIVER = 2,
+
+	/* keep last */
+	CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_AFTER_LAST,
+	CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX =
+		CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_AFTER_LAST - 1
+};
+
+/**
+ * enum cld80211_sub_attr_oem_data_resp - OEM message sub attribute
+ * @CLD80211_SUB_ATTR_OEM_DATA_INVALID: Invalid oem data resp
+ * @CLD80211_SUB_ATTR_OEM_MORE_DATA: more date sub attribute
+ * @CLD80211_SUB_ATTR_BINARY_DATA: Binary data sub attribute
+ * @CLD80211_SUB_ATTR_OEM_DATA_RESP_MAX: Max number for OEM data resp
+ * sub attribute
+ *
+ * OEM message sub attributes are interface between apps and driver to
+ * process NLA type request and response messages.
+ *
+ */
+enum cld80211_sub_attr_oem_data_resp {
+	CLD80211_SUB_ATTR_OEM_DATA_INVALID = 0,
+	CLD80211_SUB_ATTR_OEM_MORE_DATA = 1,
+	CLD80211_SUB_ATTR_BINARY_DATA = 2,
+
+	/* keep last */
+	CLD80211_SUB_ATTR_OEM_DATA_RESP_AFTER_LAST,
+	CLD80211_SUB_ATTR_OEM_DATA_RESP_MAX =
+		CLD80211_SUB_ATTR_OEM_DATA_RESP_AFTER_LAST - 1
+};
+
+/**
+ * enum cld80211_sub_attr_peer_info - peer info sub attribute
+ * @CLD80211_SUB_ATTR_PEER_INVALID: Invalid peer info
+ * @CLD80211_SUB_ATTR_PEER_MAC_ADDR: peer mac address
+ * @CLD80211_SUB_ATTR_PEER_STATUS: peer status
+ * @CLD80211_SUB_ATTR_PEER_VDEV_ID: peer vdevid
+ * @CLD80211_SUB_ATTR_PEER_CAPABILITY: peer capabilities
+ * @CLD80211_SUB_ATTR_PEER_RESERVED: reserved bytes
+ * @CLD80211_SUB_ATTR_PEER_CHAN_INFO: peer channel info
+ *
+ */
+enum cld80211_sub_attr_peer_info {
+	CLD80211_SUB_ATTR_PEER_INVALID = 0,
+	CLD80211_SUB_ATTR_PEER_MAC_ADDR = 1,
+	CLD80211_SUB_ATTR_PEER_STATUS = 2,
+	CLD80211_SUB_ATTR_PEER_VDEV_ID = 3,
+	CLD80211_SUB_ATTR_PEER_CAPABILITY = 4,
+	CLD80211_SUB_ATTR_PEER_RESERVED = 5,
+	CLD80211_SUB_ATTR_PEER_CHAN_INFO = 6,
+
+	/* keep last */
+	CLD80211_SUB_ATTR_PEER_AFTER_LAST,
+	CLD80211_SUB_ATTR_PEER_MAX =
+		CLD80211_SUB_ATTR_PEER_AFTER_LAST - 1
+};
 #endif
 #endif /* _OS_IF_WIFI_POS_H_ */

+ 205 - 5
os_if/linux/wifi_pos/src/os_if_wifi_pos.c

@@ -63,6 +63,17 @@ cap_resp_sub_attr_len[CLD80211_SUB_ATTR_CAPS_MAX + 1] = {
 				sizeof(struct wifi_pos_user_defined_caps),
 };
 
+static const uint32_t
+peer_status_sub_attr_len[CLD80211_SUB_ATTR_PEER_MAX + 1] = {
+	[CLD80211_SUB_ATTR_PEER_MAC_ADDR] = ETH_ALEN,
+	[CLD80211_SUB_ATTR_PEER_STATUS] = sizeof(uint8_t),
+	[CLD80211_SUB_ATTR_PEER_VDEV_ID] = sizeof(uint8_t),
+	[CLD80211_SUB_ATTR_PEER_CAPABILITY] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_PEER_RESERVED] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_PEER_CHAN_INFO] =
+				sizeof(struct wifi_pos_ch_info_rsp),
+};
+
 static const uint32_t
 ch_resp_sub_attr_len[CLD80211_SUB_ATTR_CH_MAX + 1] = {
 	[CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN] = sizeof(uint32_t),
@@ -168,6 +179,71 @@ map_wifi_pos_cmd_to_cld_vendor_sub_cmd(
 	}
 }
 
+static void os_if_wifi_pos_send_peer_nl_status(uint32_t pid, uint8_t *buf)
+{
+	void *hdr;
+	int flags = GFP_KERNEL;
+	struct sk_buff *msg = NULL;
+	struct nlattr *nest1, *nest2, *nest3;
+	struct wifi_pos_peer_status_info *peer_info;
+	struct wifi_pos_ch_info_rsp *chan_info;
+
+	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
+	if (!msg) {
+		osif_err("alloc_skb failed");
+		return;
+	}
+
+	peer_info = (struct wifi_pos_peer_status_info *)buf;
+	chan_info = &peer_info->peer_chan_info;
+
+	nla_put_u32(msg, CLD80211_ATTR_CMD,
+			 CLD80211_VENDOR_SUB_CMD_PEER_STATUS_IND);
+	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
+	if (!nest2) {
+		osif_err("nla_nest_start failed");
+		dev_kfree_skb(msg);
+		return;
+	}
+
+	nla_put(msg, CLD80211_SUB_ATTR_PEER_MAC_ADDR,
+			ETH_ALEN, peer_info->peer_mac_addr);
+	nla_put_u8(msg, CLD80211_SUB_ATTR_PEER_STATUS,
+						peer_info->peer_status);
+	nla_put_u8(msg, CLD80211_SUB_ATTR_PEER_VDEV_ID,
+						peer_info->vdev_id);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_PEER_CAPABILITY,
+						peer_info->peer_capability);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_PEER_RESERVED,
+							peer_info->reserved0);
+	nest3 = nla_nest_start(msg, CLD80211_SUB_ATTR_PEER_CHAN_INFO);
+	if (!nest3) {
+		osif_err("nla_nest_start failed");
+		dev_kfree_skb(msg);
+		return;
+	}
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_CHAN_ID,
+			chan_info->chan_id);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_MHZ, chan_info->mhz);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_1,
+			chan_info->band_center_freq1);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_2,
+			chan_info->band_center_freq2);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_INFO, chan_info->info);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_1,
+			chan_info->reg_info_1);
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_2,
+			chan_info->reg_info_2);
+
+	nla_nest_end(msg, nest3);
+	nla_nest_end(msg, nest2);
+
+	osif_debug("sending oem rsp: type: %d to pid (%d)",
+		    CLD80211_VENDOR_SUB_CMD_PEER_STATUS_IND, pid);
+
+	cld80211_oem_send_reply(msg, hdr, nest1, flags);
+}
+
 static void os_if_send_cap_nl_resp(uint32_t pid, uint8_t *buf)
 {
 	void *hdr;
@@ -374,9 +450,95 @@ static void os_if_send_chan_nl_resp(uint32_t pid, uint8_t *buf)
 	} while (resp_frag);
 }
 
+static int
+os_if_create_oemdata_resp(uint32_t pid, uint8_t *buf, bool frag_resp,
+			  uint32_t chnk_len)
+{
+	void *hdr;
+	int flags = GFP_KERNEL;
+	struct sk_buff *msg = NULL;
+	struct nlattr *nest1, *nest2;
+
+	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
+	if (!msg) {
+		osif_err("alloc_skb failed");
+		return -EPERM;
+	}
+
+	nla_put_u32(msg, CLD80211_ATTR_CMD, CLD80211_VENDOR_SUB_CMD_OEM_DATA);
+
+	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
+	if (!nest2)
+		goto fail;
+
+	if (frag_resp)
+		nla_put_flag(msg, CLD80211_SUB_ATTR_OEM_MORE_DATA);
+
+	nla_put(msg, CLD80211_SUB_ATTR_BINARY_DATA, chnk_len, buf);
+
+	nla_nest_end(msg, nest2);
+	osif_debug("sending oem rsp: type: %d to pid (%d)",
+		   CLD80211_VENDOR_SUB_CMD_OEM_DATA, pid);
+	cld80211_oem_send_reply(msg, hdr, nest1, flags);
+	return 0;
+
+fail:
+	osif_err("failed to fill CHAN_RESP attributes");
+	dev_kfree_skb(msg);
+	return -EPERM;
+}
+
+static void
+os_if_send_oem_data_nl_resp(uint32_t pid, uint8_t *buf,
+			    uint32_t buf_len)
+{
+	int err;
+	uint32_t attr_len;
+	uint32_t chnk_len, remain_len;
+	uint8_t *chnk_ptr;
+	bool frag_resp = false;
+
+	struct nlattr vendor_data;
+	struct nlattr attr_cmd;
+	struct nlattr attr_tag_data;
+	struct nlattr cld80211_subattr_bindata;
+	struct nlattr more_data;
+
+	attr_len = WIFIPOS_RESERVE_BYTES;
+	attr_len += NLMSG_ALIGN(sizeof(vendor_data));
+	attr_len += NLMSG_ALIGN(sizeof(attr_cmd));
+	attr_len += NLMSG_ALIGN(sizeof(attr_tag_data));
+	attr_len += NLMSG_ALIGN(sizeof(more_data));
+
+	chnk_ptr = buf;
+	chnk_len = buf_len;
+	remain_len = buf_len;
+	do {
+		if (attr_len + nla_total_size(chnk_len) >
+		    WLAN_CLD80211_MAX_SIZE) {
+			frag_resp = true;
+
+			chnk_len = WLAN_CLD80211_MAX_SIZE - (attr_len +
+					sizeof(cld80211_subattr_bindata));
+		} else {
+			frag_resp = false;
+		}
+
+		remain_len -= chnk_len;
+
+		err = os_if_create_oemdata_resp(pid, chnk_ptr,
+						frag_resp, chnk_len);
+		if (err) {
+			osif_err("failed to alloc memory for oem_nl_resp");
+			return;
+		}
+		chnk_ptr += chnk_len;
+		chnk_len = remain_len;
+	} while (frag_resp);
+}
 
 static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
-			       enum wifi_pos_cmd_ids cmd)
+			       enum wifi_pos_cmd_ids cmd, uint32_t len)
 {
 	switch (cmd) {
 	case WIFI_POS_CMD_GET_CAPS:
@@ -385,13 +547,19 @@ static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
 	case WIFI_POS_CMD_GET_CH_INFO:
 		os_if_send_chan_nl_resp(pid, buf);
 		break;
+	case WIFI_POS_CMD_OEM_DATA:
+		os_if_send_oem_data_nl_resp(pid, buf, len);
+		break;
+	case WIFI_POS_PEER_STATUS_IND:
+		os_if_wifi_pos_send_peer_nl_status(pid, buf);
+		break;
 	default:
 		osif_err("response message is invalid :%d", cmd);
 	}
 }
 #else
 static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
-			       enum wifi_pos_cmd_ids cmd)
+			       enum wifi_pos_cmd_ids cmd, uint32_t len)
 {
 }
 #endif
@@ -418,7 +586,7 @@ static void os_if_wifi_pos_send_rsp(uint32_t pid, enum wifi_pos_cmd_ids cmd,
 	}
 
 	if (ucfg_wifi_pos_is_nl_rsp(psoc)) {
-		os_if_send_nl_resp(pid, buf, cmd);
+		os_if_send_nl_resp(pid, buf, cmd, buf_len);
 	} else {
 		skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len),
 				GFP_ATOMIC);
@@ -447,6 +615,30 @@ static void os_if_wifi_pos_send_rsp(uint32_t pid, enum wifi_pos_cmd_ids cmd,
 }
 
 #ifdef CNSS_GENL
+static int
+wifi_pos_parse_nla_oemdata_req(uint32_t len, uint8_t *buf,
+			       struct wifi_pos_req_msg *req)
+{
+	struct nlattr *tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX + 1];
+
+	if (wlan_cfg80211_nla_parse(tb_oem_data,
+				    CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX,
+				    (struct nlattr *)buf, len, NULL)) {
+		osif_err("invalid data in request");
+		return OEM_ERR_INVALID_MESSAGE_TYPE;
+	}
+
+	if (!tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]) {
+		osif_err("CLD80211_SUB_ATTR_MSG_OEM_DATA_FW not present");
+		return OEM_ERR_INVALID_MESSAGE_TYPE;
+	}
+	req->buf_len = nla_len(
+				tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]);
+	req->buf = nla_data(
+				tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]);
+
+	return 0;
+}
 
 static int  wifi_pos_parse_nla_req(const void *data, int len, int pid,
 		    struct wifi_pos_req_msg *req)
@@ -468,8 +660,16 @@ static int  wifi_pos_parse_nla_req(const void *data, int len, int pid,
 	if (tb[CLD80211_ATTR_CMD_TAG_DATA]) {
 		msg_len = nla_len(tb[CLD80211_ATTR_CMD_TAG_DATA]);
 		msg = nla_data(tb[CLD80211_ATTR_CMD_TAG_DATA]);
-		req->buf_len = msg_len;
-		req->buf = msg;
+
+		if (req->msg_type == WIFI_POS_CMD_OEM_DATA) {
+			if (wifi_pos_parse_nla_oemdata_req(msg_len, msg, req)) {
+				osif_err("parsing oemdata req failed");
+				return OEM_ERR_INVALID_MESSAGE_LENGTH;
+			}
+		} else {
+			req->buf_len = msg_len;
+			req->buf = msg;
+		}
 	}
 	if (tb[CLD80211_ATTR_META_DATA])
 		osif_err("meta data dropped. Apps can use CLD80211_ATTR_CMD_TAG_DATA sub attrs");

+ 61 - 59
umac/wifi_pos/src/wifi_pos_main.c

@@ -88,6 +88,59 @@ struct wlan_lmac_if_wifi_pos_tx_ops *
 	return &psoc->soc_cb.tx_ops.wifi_pos_tx_ops;
 }
 
+#ifdef CNSS_GENL
+static uint8_t *
+wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
+			  struct app_reg_rsp_vdev_info *vdevs_info)
+{
+	uint32_t *nl_sign;
+	uint8_t *resp_buf;
+	struct wifi_app_reg_rsp *app_reg_rsp;
+
+	/*
+	 * allocate ENHNC_FLAGS_LEN i.e. 4bytes extra memory in app_reg_resp
+	 * to indicate NLA type response is supported for OEM request
+	 * commands.
+	 */
+	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
+			+ sizeof(uint8_t) + ENHNC_FLAGS_LEN;
+	resp_buf = qdf_mem_malloc(*rsp_len);
+	if (!resp_buf)
+		return NULL;
+
+	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
+	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);
+
+	nl_sign = (uint32_t *)&app_reg_rsp->vdevs[vdev_idx];
+	*nl_sign |= NL_ENABLE_OEM_REQ_RSP;
+
+	return resp_buf;
+}
+#else
+static uint8_t *
+wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
+			  struct app_reg_rsp_vdev_info *vdevs_info)
+{
+	uint8_t *resp_buf;
+	struct wifi_app_reg_rsp *app_reg_rsp;
+
+	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
+			+ sizeof(uint8_t);
+	resp_buf = qdf_mem_malloc(*rsp_len);
+	if (!resp_buf)
+		return NULL;
+
+	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
+	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);
+
+	return resp_buf;
+}
+#endif
+
 static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
 					struct wifi_pos_req_msg *req)
 {
@@ -182,13 +235,15 @@ static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
 
 		pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id,
 						  WLAN_WIFI_POS_CORE_ID);
-		if (pdev) {
-			data_req.data_len = req->buf_len;
-			data_req.data = req->buf;
-			tx_ops->data_req_tx(pdev, &data_req);
-			wlan_objmgr_pdev_release_ref(pdev,
-						     WLAN_WIFI_POS_CORE_ID);
+		if (!pdev) {
+			wifi_pos_err("pdev null");
+			return QDF_STATUS_E_INVAL;
 		}
+		data_req.data_len = req->buf_len;
+		data_req.data = req->buf;
+		tx_ops->data_req_tx(pdev, &data_req);
+		wlan_objmgr_pdev_release_ref(pdev,
+					     WLAN_WIFI_POS_CORE_ID);
 		break;
 	}
 
@@ -506,59 +561,6 @@ static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc,
 	vdev_idx++;
 }
 
-#ifdef CNSS_GENL
-static uint8_t *
-wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
-			  struct app_reg_rsp_vdev_info *vdevs_info)
-{
-	uint32_t *nl_sign;
-	uint8_t *resp_buf;
-	struct wifi_app_reg_rsp *app_reg_rsp;
-
-	/*
-	 * allocate ENHNC_FLAGS_LEN i.e. 4bytes extra memory in app_reg_resp
-	 * to indicate NLA type resoponse is supported for OEM request
-	 * commands.
-	 */
-	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
-			+ sizeof(uint8_t) + ENHNC_FLAGS_LEN;
-	resp_buf = qdf_mem_malloc(*rsp_len);
-	if (!resp_buf)
-		return NULL;
-
-	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
-	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);
-
-	nl_sign = (uint32_t *)&app_reg_rsp->vdevs[vdev_idx];
-	*nl_sign |= NL_ENABLE_OEM_REQ_RSP;
-
-	return resp_buf;
-}
-#else
-static uint8_t *
-wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
-			  struct app_reg_rsp_vdev_info *vdevs_info)
-{
-	uint8_t *resp_buf;
-	struct wifi_app_reg_rsp *app_reg_rsp;
-
-	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
-			+ sizeof(uint8_t);
-	resp_buf = qdf_mem_malloc(*rsp_len);
-	if (!resp_buf)
-		return NULL;
-
-	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
-	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);
-
-	return resp_buf;
-}
-#endif
-
 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
 					struct wifi_pos_req_msg *req)
 {