Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4c43ae3 authored by Vinay Gannevaram's avatar Vinay Gannevaram Committed by nshrivas
Browse files

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
parent a3d02798
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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,9 +660,17 @@ 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]);

		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
Original line number Diff line number Diff line
@@ -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) {
		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)
{