qcacld-3.0: Add support to send cfr data via nl events

User configures CFR data transport mode using vendor command
QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG and attr
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE. Host sends
CFR data to userspace via relayfs if transport mode set is
QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS else if transport mode is set
to QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS, host sends CFR data
via NL events. By default transport mode is relayfs.
To get CFR data as unicast NL events, user configures PID of a
process using vendor attr
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID. By default CFR
data NL events are broadcast.

Change-Id: Ifc2694fa3b21dc01f25da2219deb367375a48475
CRs-Fixed: 2953290
This commit is contained in:
Abhishek Ambure 2021-05-05 13:53:22 +05:30 • committed by Madan Koyyalamudi
commit d83b9685df
3 changed files with 134 additions and 0 deletions

View file

@ -1683,6 +1683,7 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
#ifdef WLAN_SUPPORT_TWT
FEATURE_TWT_VENDOR_EVENTS
#endif
FEATURE_CFR_DATA_VENDOR_EVENTS
};
/**
@ -6701,6 +6702,61 @@ wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb,
}
#endif
#ifdef WLAN_CFR_ENABLE
void hdd_cfr_data_send_nl_event(uint8_t vdev_id, uint32_t pid,
const void *data, uint32_t data_len)
{
uint32_t len, ret;
struct sk_buff *vendor_event;
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
struct hdd_adapter *adapter;
struct nlmsghdr *nlhdr = NULL;
if (!hdd_ctx) {
hdd_err("HDD context is NULL");
return;
}
adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
if (!adapter) {
hdd_err("adapter NULL for vdev id %d", vdev_id);
return;
}
len = nla_total_size(data_len) + NLMSG_HDRLEN;
vendor_event = cfg80211_vendor_event_alloc(
hdd_ctx->wiphy, &adapter->wdev, len,
QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG_INDEX,
GFP_KERNEL);
if (!vendor_event) {
hdd_err("cfg80211_vendor_event_alloc failed vdev id %d, data len %d",
vdev_id, data_len);
return;
}
ret = nla_put(vendor_event,
QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA,
data_len, data);
if (ret) {
hdd_err("CFR event put fails status %d", ret);
kfree_skb(vendor_event);
return;
}
if (pid) {
nlhdr = nlmsg_hdr(vendor_event);
if (nlhdr)
nlhdr->nlmsg_pid = pid;
else
hdd_err_rl("nlhdr is null");
}
hdd_debug("vdev id %d pid %d", vdev_id, pid);
cfg80211_vendor_event(vendor_event, GFP_KERNEL);
}
#endif
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx,
uint8_t vdev_id, uint16_t buf_len,

View file

@ -514,6 +514,28 @@ void wlan_hdd_cfg80211_unlink_bss(struct hdd_adapter *adapter,
void wlan_hdd_cfg80211_acs_ch_select_evt(struct hdd_adapter *adapter);
#ifdef WLAN_CFR_ENABLE
/*
* hdd_cfr_data_send_nl_event() - send cfr data through nl event
* @vdev_id: vdev id
* @pid: process pid to which send data event unicast way
* @data: pointer to the cfr data
* @data_len: length of data
*
* Return: void
*/
void hdd_cfr_data_send_nl_event(uint8_t vdev_id, uint32_t pid,
const void *data, uint32_t data_len);
#define FEATURE_CFR_DATA_VENDOR_EVENTS \
[QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG_INDEX] = { \
.vendor_id = QCA_NL80211_VENDOR_ID, \
.subcmd = QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG, \
},
#else
#define FEATURE_CFR_DATA_VENDOR_EVENTS
#endif
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/**
* hdd_send_roam_scan_ch_list_event() - roam scan ch list event to user space

View file

@ -70,8 +70,38 @@ const struct nla_policy cfr_config_policy[
.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER] = {
.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE] = {
.type = NLA_U8},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID] = {
.type = NLA_U32},
};
static void
wlan_hdd_transport_mode_cfg(struct wlan_objmgr_pdev *pdev,
uint8_t vdev_id, uint32_t pid,
enum qca_wlan_vendor_cfr_data_transport_modes tx_mode)
{
struct pdev_cfr *pa;
if (!pdev) {
hdd_err("failed to %s transport mode cb for cfr, pdev is NULL for vdev id %d",
tx_mode ? "register" : "deregister", vdev_id);
return;
}
pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
if (!pa) {
hdd_err("cfr private obj is NULL for vdev id %d", vdev_id);
return;
}
pa->nl_cb.vdev_id = vdev_id;
pa->nl_cb.pid = pid;
if (tx_mode == QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS)
pa->nl_cb.cfr_nl_cb = hdd_cfr_data_send_nl_event;
else
pa->nl_cb.cfr_nl_cb = NULL;
}
#ifdef WLAN_ENH_CFR_ENABLE
#define DEFAULT_CFR_NSS 0xff
@ -175,6 +205,7 @@ wlan_cfg80211_cfr_set_group_config(struct wlan_objmgr_vdev *vdev,
params.expected_data_subtype,
params.expected_data_subtype);
}
if (!params.expected_mgmt_subtype ||
!params.expected_ctrl_subtype ||
!params.expected_data_subtype) {
@ -289,6 +320,31 @@ wlan_cfg80211_cfr_set_config(struct wlan_objmgr_vdev *vdev,
}
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE]) {
uint8_t transport_mode = 0xff;
uint32_t pid = 0;
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID])
pid = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID]);
else
hdd_debug("No PID received");
transport_mode = nla_get_u8(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE]);
hdd_debug("tx mode attr %d, pid %d", transport_mode, pid);
if (transport_mode == QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS ||
transport_mode == QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS) {
wlan_hdd_transport_mode_cfg(vdev->vdev_objmgr.wlan_pdev,
vdev->vdev_objmgr.vdev_id,
pid, transport_mode);
} else {
hdd_debug("invalid transport mode %d for vdev id %d",
transport_mode, vdev->vdev_objmgr.vdev_id);
}
}
return 0;
}