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
Cette révision appartient à :
Vinay Gannevaram
2019-12-27 12:48:10 +05:30
révisé par nshrivas
Parent 8fd2d1abbf
révision 7ccc84acb3
3 fichiers modifiés avec 337 ajouts et 64 suppressions

Voir le fichier

@@ -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_ */

Voir le fichier

@@ -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");

Voir le fichier

@@ -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)
{