From d83b9685df68a6da6768e2815afb973bdae71410 Mon Sep 17 00:00:00 2001 From: Abhishek Ambure Date: Wed, 5 May 2021 13:53:22 +0530 Subject: [PATCH] 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 --- core/hdd/src/wlan_hdd_cfg80211.c | 56 ++++++++++++++++++++++++++++++++ core/hdd/src/wlan_hdd_cfg80211.h | 22 +++++++++++++ core/hdd/src/wlan_hdd_cfr.c | 56 ++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 5c1aef598b5c..7ece5048fa24 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -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, diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 3725b46c7393..0b785ead3750 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -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 diff --git a/core/hdd/src/wlan_hdd_cfr.c b/core/hdd/src/wlan_hdd_cfr.c index 24dccf20bb8d..0027d9de360a 100644 --- a/core/hdd/src/wlan_hdd_cfr.c +++ b/core/hdd/src/wlan_hdd_cfr.c @@ -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; }