diff --git a/Kbuild b/Kbuild index 721b5a5f54a0..641d755c4971 100644 --- a/Kbuild +++ b/Kbuild @@ -89,6 +89,10 @@ ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP), y) HDD_OBJS+= $(HDD_SRC_DIR)/wlan_hdd_green_ap.o endif +ifeq ($(CONFIG_QCACLD_FEATURE_APF), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_apf.o +endif + ifeq ($(CONFIG_WLAN_FEATURE_LPSS), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_lpass.o endif @@ -835,6 +839,10 @@ ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_pmo_api.o endif +ifeq ($(CONFIG_QCACLD_FEATURE_APF), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_apf_tlv.o +endif + ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) ifeq ($(CONFIG_OCB_UT_FRAMEWORK), y) WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_ocb_ut.o @@ -1818,6 +1826,10 @@ cppflags-$(CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY) += -DWLAN_ENABLE_SOCIAL_C #Green AP feature cppflags-$(CONFIG_QCACLD_FEATURE_GREEN_AP) += -DWLAN_SUPPORT_GREEN_AP +ifeq ($(CONFIG_QCACLD_FEATURE_APF), y) +cppflags-$(CONFIG_QCACLD_FEATURE_APF) += -DFEATURE_WLAN_APF +endif + #Stats & Quota Metering feature ifeq ($(CONFIG_IPA_OFFLOAD), y) ifeq ($(CONFIG_QCACLD_FEATURE_METERING), y) diff --git a/configs/default_defconfig b/configs/default_defconfig index e1a7c3b02b40..28497450db41 100644 --- a/configs/default_defconfig +++ b/configs/default_defconfig @@ -80,6 +80,9 @@ endif CONFIG_QCACLD_FEATURE_GREEN_AP := y +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + ifeq ($(CONFIG_ARCH_MSM8998), y) CONFIG_QCACLD_FEATURE_METERING := y endif diff --git a/configs/genoa.snoc.debug_defconfig b/configs/genoa.snoc.debug_defconfig index 7a94a2d998dd..138657aeaffd 100644 --- a/configs/genoa.snoc.debug_defconfig +++ b/configs/genoa.snoc.debug_defconfig @@ -162,6 +162,7 @@ CONFIG_WLAN_FEATURE_SAE := y ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) CONFIG_GTK_OFFLOAD := y endif +CONFIG_QCACLD_FEATURE_APF := y ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) ifneq ($(WLAN_DISABLE_BUILD_TAG), y) diff --git a/core/hdd/inc/wlan_hdd_apf.h b/core/hdd/inc/wlan_hdd_apf.h new file mode 100644 index 000000000000..e5a8fe995ab4 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_apf.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_apf.h + * + * Android Packet Filter related API's and definitions + */ + +#ifndef __WLAN_HDD_APF_H +#define __WLAN_HDD_APF_H + +#include "sir_api.h" +#include "wlan_hdd_main.h" + +/** + * wlan_hdd_cfg80211_bpf_offload() - SSR Wrapper to BPF Offload + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ + +int wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +#endif /* WLAN_HDD_APF_H */ diff --git a/core/hdd/src/wlan_hdd_apf.c b/core/hdd/src/wlan_hdd_apf.c new file mode 100644 index 000000000000..9a1c724654e7 --- /dev/null +++ b/core/hdd/src/wlan_hdd_apf.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_apf.c + * + * Android Packet Filter support and implementation + */ + +#include "wlan_hdd_apf.h" +#include "qca_vendor.h" +#include "wlan_hdd_request_manager.h" + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_bpf_offload() + */ +#define BPF_INVALID \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID +#define BPF_SET_RESET \ + QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER +#define BPF_VERSION \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION +#define BPF_FILTER_ID \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID +#define BPF_PACKET_SIZE \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE +#define BPF_CURRENT_OFFSET \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET +#define BPF_PROGRAM \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM +#define BPF_MAX \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX + +static const struct nla_policy +wlan_hdd_bpf_offload_policy[BPF_MAX + 1] = { + [BPF_SET_RESET] = {.type = NLA_U32}, + [BPF_VERSION] = {.type = NLA_U32}, + [BPF_FILTER_ID] = {.type = NLA_U32}, + [BPF_PACKET_SIZE] = {.type = NLA_U32}, + [BPF_CURRENT_OFFSET] = {.type = NLA_U32}, + [BPF_PROGRAM] = {.type = NLA_U8}, +}; + +struct bpf_offload_priv { + struct sir_bpf_get_offload bpf_get_offload; +}; + +static void hdd_get_bpf_offload_cb(void *context, + struct sir_bpf_get_offload *data) +{ + struct hdd_request *request; + struct bpf_offload_priv *priv; + + hdd_enter(); + + request = hdd_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = hdd_request_priv(request); + priv->bpf_get_offload = *data; + hdd_request_complete(request); + hdd_request_put(request); +} + +/** + * hdd_post_get_bpf_capabilities_rsp() - Callback function to BPF Offload + * @hdd_context: hdd_context + * @bpf_get_offload: struct for get offload + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_post_get_bpf_capabilities_rsp(struct hdd_context *hdd_ctx, + struct sir_bpf_get_offload *bpf_get_offload) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + + hdd_enter(); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += + (sizeof(bpf_get_offload->max_bytes_for_bpf_inst) + NLA_HDRLEN) + + (sizeof(bpf_get_offload->bpf_version) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_debug("BPF Version: %u BPF max bytes: %u", + bpf_get_offload->bpf_version, + bpf_get_offload->max_bytes_for_bpf_inst); + + if (nla_put_u32(skb, BPF_PACKET_SIZE, + bpf_get_offload->max_bytes_for_bpf_inst) || + nla_put_u32(skb, BPF_VERSION, bpf_get_offload->bpf_version)) { + hdd_err("nla put failure"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + hdd_exit(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * hdd_get_bpf_offload - Get BPF offload Capabilities + * @hdd_ctx: Hdd context + * + * Return: 0 on success, errno on failure + */ +static int hdd_get_bpf_offload(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + int ret; + void *cookie; + struct hdd_request *request; + struct bpf_offload_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_BPF, + }; + + hdd_enter(); + + request = hdd_request_alloc(¶ms); + if (!request) { + hdd_err("Unable to allocate request"); + return -EINVAL; + } + cookie = hdd_request_cookie(request); + + status = sme_get_bpf_offload_capabilities(hdd_ctx->hHal, + hdd_get_bpf_offload_cb, + cookie); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to retrieve BPF caps"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + ret = hdd_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out"); + goto cleanup; + } + priv = hdd_request_priv(request); + ret = hdd_post_get_bpf_capabilities_rsp(hdd_ctx, + &priv->bpf_get_offload); + if (ret) + hdd_err("Failed to post get bpf capabilities"); + +cleanup: + /* + * either we never sent a request to SME, we sent a request to + * SME and timed out, or we sent a request to SME, received a + * response from SME, and posted the response to userspace. + * regardless we are done with the request. + */ + hdd_request_put(request); + hdd_exit(); + + return ret; +} + +/** + * hdd_set_reset_bpf_offload - Post set/reset bpf to SME + * @hdd_ctx: Hdd context + * @tb: Length of @data + * @adapter: pointer to adapter struct + * + * Return: 0 on success; errno on failure + */ +static int hdd_set_reset_bpf_offload(struct hdd_context *hdd_ctx, + struct nlattr **tb, + struct hdd_adapter *adapter) +{ + struct sir_bpf_set_offload *bpf_set_offload; + QDF_STATUS status; + int prog_len; + int ret = 0; + + hdd_enter(); + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + if (!hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + } + + bpf_set_offload = qdf_mem_malloc(sizeof(*bpf_set_offload)); + if (bpf_set_offload == NULL) { + hdd_err("qdf_mem_malloc failed for bpf_set_offload"); + return -ENOMEM; + } + + /* Parse and fetch bpf packet size */ + if (!tb[BPF_PACKET_SIZE]) { + hdd_err("attr bpf packet size failed"); + ret = -EINVAL; + goto fail; + } + bpf_set_offload->total_length = nla_get_u32(tb[BPF_PACKET_SIZE]); + + if (!bpf_set_offload->total_length) { + hdd_debug("BPF reset packet filter received"); + goto post_sme; + } + + /* Parse and fetch bpf program */ + if (!tb[BPF_PROGRAM]) { + hdd_err("attr bpf program failed"); + ret = -EINVAL; + goto fail; + } + + prog_len = nla_len(tb[BPF_PROGRAM]); + bpf_set_offload->program = qdf_mem_malloc(sizeof(uint8_t) * prog_len); + + if (bpf_set_offload->program == NULL) { + hdd_err("qdf_mem_malloc failed for bpf offload program"); + ret = -ENOMEM; + goto fail; + } + + bpf_set_offload->current_length = prog_len; + nla_memcpy(bpf_set_offload->program, tb[BPF_PROGRAM], prog_len); + bpf_set_offload->session_id = adapter->session_id; + + hdd_debug("BPF set instructions"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + bpf_set_offload->program, prog_len); + + /* Parse and fetch filter Id */ + if (!tb[BPF_FILTER_ID]) { + hdd_err("attr filter id failed"); + ret = -EINVAL; + goto fail; + } + bpf_set_offload->filter_id = nla_get_u32(tb[BPF_FILTER_ID]); + + /* Parse and fetch current offset */ + if (!tb[BPF_CURRENT_OFFSET]) { + hdd_err("attr current offset failed"); + ret = -EINVAL; + goto fail; + } + bpf_set_offload->current_offset = nla_get_u32(tb[BPF_CURRENT_OFFSET]); + +post_sme: + hdd_debug("Posting BPF SET/RESET to SME, session_id: %d Bpf Version: %d filter ID: %d total_length: %d current_length: %d current offset: %d", + bpf_set_offload->session_id, + bpf_set_offload->version, + bpf_set_offload->filter_id, + bpf_set_offload->total_length, + bpf_set_offload->current_length, + bpf_set_offload->current_offset); + + status = sme_set_bpf_instructions(hdd_ctx->hHal, bpf_set_offload); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_bpf_instructions failed(err=%d)", status); + ret = -EINVAL; + goto fail; + } + hdd_exit(); + +fail: + if (bpf_set_offload->current_length) + qdf_mem_free(bpf_set_offload->program); + qdf_mem_free(bpf_set_offload); + return ret; +} + +/** + * wlan_hdd_cfg80211_bpf_offload() - Set/Reset to BPF Offload + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[BPF_MAX + 1]; + int ret_val, packet_filter_subcmd; + + hdd_enter(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!hdd_ctx->bpf_enabled) { + hdd_err("BPF offload is not supported/enabled"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, BPF_MAX, data, data_len, + wlan_hdd_bpf_offload_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[BPF_SET_RESET]) { + hdd_err("attr bpf set reset failed"); + return -EINVAL; + } + + packet_filter_subcmd = nla_get_u32(tb[BPF_SET_RESET]); + + if (packet_filter_subcmd == QCA_WLAN_GET_PACKET_FILTER) + return hdd_get_bpf_offload(hdd_ctx); + else + return hdd_set_reset_bpf_offload(hdd_ctx, tb, + adapter); +} + +int wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_bpf_offload(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 387f854cb33d..8fafa198f46d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -92,6 +92,7 @@ #include "wlan_hdd_disa.h" #include "wlan_hdd_request_manager.h" #include "wlan_hdd_he.h" +#include "wlan_hdd_apf.h" #include #include @@ -9594,368 +9595,6 @@ static int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, return ret; } -/* - * define short names for the global vendor params - * used by __wlan_hdd_cfg80211_bpf_offload() - */ -#define BPF_INVALID \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID -#define BPF_SET_RESET \ - QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER -#define BPF_VERSION \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION -#define BPF_FILTER_ID \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID -#define BPF_PACKET_SIZE \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE -#define BPF_CURRENT_OFFSET \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET -#define BPF_PROGRAM \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM -#define BPF_MAX \ - QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX - -static const struct nla_policy -wlan_hdd_bpf_offload_policy[BPF_MAX + 1] = { - [BPF_SET_RESET] = {.type = NLA_U32}, - [BPF_VERSION] = {.type = NLA_U32}, - [BPF_FILTER_ID] = {.type = NLA_U32}, - [BPF_PACKET_SIZE] = {.type = NLA_U32}, - [BPF_CURRENT_OFFSET] = {.type = NLA_U32}, - [BPF_PROGRAM] = {.type = NLA_U8}, -}; - -struct bpf_offload_priv { - struct sir_bpf_get_offload bpf_get_offload; -}; - -/** - * hdd_get_bpf_offload_cb() - Callback function to BPF Offload - * @context: opaque context originally passed to SME. HDD always passes - * a cookie for the request context - * @bpf_get_offload: struct for get offload - * - * This function receives the response/data from the lower layer and - * checks to see if the thread is still waiting then post the results to - * upper layer, if the request has timed out then ignore. - * - * Return: None - */ -static void hdd_get_bpf_offload_cb(void *context, - struct sir_bpf_get_offload *data) -{ - struct hdd_request *request; - struct bpf_offload_priv *priv; - - hdd_enter(); - - request = hdd_request_get(context); - if (!request) { - hdd_err("Obsolete request"); - return; - } - - priv = hdd_request_priv(request); - priv->bpf_get_offload = *data; - hdd_request_complete(request); - hdd_request_put(request); -} - -/** - * hdd_post_get_bpf_capabilities_rsp() - Callback function to BPF Offload - * @hdd_context: hdd_context - * @bpf_get_offload: struct for get offload - * - * Return: 0 on success, error number otherwise. - */ -static int hdd_post_get_bpf_capabilities_rsp(struct hdd_context *hdd_ctx, - struct sir_bpf_get_offload *bpf_get_offload) -{ - struct sk_buff *skb; - uint32_t nl_buf_len; - - hdd_enter(); - - nl_buf_len = NLMSG_HDRLEN; - nl_buf_len += - (sizeof(bpf_get_offload->max_bytes_for_bpf_inst) + NLA_HDRLEN) + - (sizeof(bpf_get_offload->bpf_version) + NLA_HDRLEN); - - skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); - if (!skb) { - hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); - return -ENOMEM; - } - - hdd_debug("BPF Version: %u BPF max bytes: %u", - bpf_get_offload->bpf_version, - bpf_get_offload->max_bytes_for_bpf_inst); - - if (nla_put_u32(skb, BPF_PACKET_SIZE, - bpf_get_offload->max_bytes_for_bpf_inst) || - nla_put_u32(skb, BPF_VERSION, bpf_get_offload->bpf_version)) { - hdd_err("nla put failure"); - goto nla_put_failure; - } - - cfg80211_vendor_cmd_reply(skb); - hdd_exit(); - return 0; - -nla_put_failure: - kfree_skb(skb); - return -EINVAL; -} - -/** - * hdd_get_bpf_offload - Get BPF offload Capabilities - * @hdd_ctx: Hdd context - * - * Return: 0 on success, errno on failure - */ -static int hdd_get_bpf_offload(struct hdd_context *hdd_ctx) -{ - QDF_STATUS status; - int ret; - void *cookie; - struct hdd_request *request; - struct bpf_offload_priv *priv; - static const struct hdd_request_params params = { - .priv_size = sizeof(*priv), - .timeout_ms = WLAN_WAIT_TIME_BPF, - }; - - hdd_enter(); - - request = hdd_request_alloc(¶ms); - if (!request) { - hdd_err("Unable to allocate request"); - return -EINVAL; - } - cookie = hdd_request_cookie(request); - - status = sme_get_bpf_offload_capabilities(hdd_ctx->hHal, - hdd_get_bpf_offload_cb, - cookie); - if (!QDF_IS_STATUS_SUCCESS(status)) { - hdd_err("Unable to retrieve BPF caps"); - ret = qdf_status_to_os_return(status); - goto cleanup; - } - ret = hdd_request_wait_for_response(request); - if (ret) { - hdd_err("Target response timed out"); - goto cleanup; - } - priv = hdd_request_priv(request); - ret = hdd_post_get_bpf_capabilities_rsp(hdd_ctx, - &priv->bpf_get_offload); - if (ret) - hdd_err("Failed to post get bpf capabilities"); - -cleanup: - /* - * either we never sent a request to SME, we sent a request to - * SME and timed out, or we sent a request to SME, received a - * response from SME, and posted the response to userspace. - * regardless we are done with the request. - */ - hdd_request_put(request); - hdd_exit(); - - return ret; -} - -/** - * hdd_set_reset_bpf_offload - Post set/reset bpf to SME - * @hdd_ctx: Hdd context - * @tb: Length of @data - * @adapter: pointer to adapter struct - * - * Return: 0 on success; errno on failure - */ -static int hdd_set_reset_bpf_offload(struct hdd_context *hdd_ctx, - struct nlattr **tb, - struct hdd_adapter *adapter) -{ - struct sir_bpf_set_offload *bpf_set_offload; - QDF_STATUS status; - int prog_len; - int ret = 0; - - hdd_enter(); - - if (adapter->device_mode == QDF_STA_MODE || - adapter->device_mode == QDF_P2P_CLIENT_MODE) { - if (!hdd_conn_is_connected( - WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { - hdd_err("Not in Connected state!"); - return -ENOTSUPP; - } - } - - bpf_set_offload = qdf_mem_malloc(sizeof(*bpf_set_offload)); - if (bpf_set_offload == NULL) { - hdd_err("qdf_mem_malloc failed for bpf_set_offload"); - return -ENOMEM; - } - - /* Parse and fetch bpf packet size */ - if (!tb[BPF_PACKET_SIZE]) { - hdd_err("attr bpf packet size failed"); - ret = -EINVAL; - goto fail; - } - bpf_set_offload->total_length = nla_get_u32(tb[BPF_PACKET_SIZE]); - - if (!bpf_set_offload->total_length) { - hdd_debug("BPF reset packet filter received"); - goto post_sme; - } - - /* Parse and fetch bpf program */ - if (!tb[BPF_PROGRAM]) { - hdd_err("attr bpf program failed"); - ret = -EINVAL; - goto fail; - } - - prog_len = nla_len(tb[BPF_PROGRAM]); - bpf_set_offload->program = qdf_mem_malloc(sizeof(uint8_t) * prog_len); - - if (bpf_set_offload->program == NULL) { - hdd_err("qdf_mem_malloc failed for bpf offload program"); - ret = -ENOMEM; - goto fail; - } - - bpf_set_offload->current_length = prog_len; - nla_memcpy(bpf_set_offload->program, tb[BPF_PROGRAM], prog_len); - bpf_set_offload->session_id = adapter->session_id; - - hdd_debug("BPF set instructions"); - QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, - bpf_set_offload->program, prog_len); - - /* Parse and fetch filter Id */ - if (!tb[BPF_FILTER_ID]) { - hdd_err("attr filter id failed"); - ret = -EINVAL; - goto fail; - } - bpf_set_offload->filter_id = nla_get_u32(tb[BPF_FILTER_ID]); - - /* Parse and fetch current offset */ - if (!tb[BPF_CURRENT_OFFSET]) { - hdd_err("attr current offset failed"); - ret = -EINVAL; - goto fail; - } - bpf_set_offload->current_offset = nla_get_u32(tb[BPF_CURRENT_OFFSET]); - -post_sme: - hdd_debug("Posting BPF SET/RESET to SME, session_id: %d Bpf Version: %d filter ID: %d total_length: %d current_length: %d current offset: %d", - bpf_set_offload->session_id, - bpf_set_offload->version, - bpf_set_offload->filter_id, - bpf_set_offload->total_length, - bpf_set_offload->current_length, - bpf_set_offload->current_offset); - - status = sme_set_bpf_instructions(hdd_ctx->hHal, bpf_set_offload); - if (!QDF_IS_STATUS_SUCCESS(status)) { - hdd_err("sme_set_bpf_instructions failed(err=%d)", status); - ret = -EINVAL; - goto fail; - } - hdd_exit(); - -fail: - if (bpf_set_offload->current_length) - qdf_mem_free(bpf_set_offload->program); - qdf_mem_free(bpf_set_offload); - return ret; -} - -/** - * wlan_hdd_cfg80211_bpf_offload() - Set/Reset to BPF Offload - * @wiphy: wiphy structure pointer - * @wdev: Wireless device structure pointer - * @data: Pointer to the data received - * @data_len: Length of @data - * - * Return: 0 on success; errno on failure - */ -static int -__wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) -{ - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct nlattr *tb[BPF_MAX + 1]; - int ret_val, packet_filter_subcmd; - - hdd_enter(); - - ret_val = wlan_hdd_validate_context(hdd_ctx); - if (ret_val) - return ret_val; - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EINVAL; - } - - if (!hdd_ctx->bpf_enabled) { - hdd_err("BPF offload is not supported/enabled"); - return -ENOTSUPP; - } - - if (wlan_cfg80211_nla_parse(tb, BPF_MAX, data, data_len, - wlan_hdd_bpf_offload_policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - if (!tb[BPF_SET_RESET]) { - hdd_err("attr bpf set reset failed"); - return -EINVAL; - } - - packet_filter_subcmd = nla_get_u32(tb[BPF_SET_RESET]); - - if (packet_filter_subcmd == QCA_WLAN_GET_PACKET_FILTER) - return hdd_get_bpf_offload(hdd_ctx); - else - return hdd_set_reset_bpf_offload(hdd_ctx, tb, - adapter); -} - -/** - * wlan_hdd_cfg80211_bpf_offload() - SSR Wrapper to BPF Offload - * @wiphy: wiphy structure pointer - * @wdev: Wireless device structure pointer - * @data: Pointer to the data received - * @data_len: Length of @data - * - * Return: 0 on success; errno on failure - */ - -static int wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_bpf_offload(wiphy, wdev, data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - /** * wlan_hdd_set_pre_cac_status() - Set the pre cac status * @pre_cac_adapter: AP adapter used for pre cac @@ -14772,6 +14411,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_txpower_scale_decr_db }, +#ifdef FEATURE_WLAN_APF { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER, @@ -14780,6 +14420,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_bpf_offload }, +#endif /* FEATURE_WLAN_APF */ { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 76a7086f7262..5397f91f59f8 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -130,6 +130,7 @@ #include "wlan_ipa_ucfg_api.h" #include #include "wlan_hdd_nud_tracking.h" +#include "wlan_hdd_apf.h" #ifdef CNSS_GENL #include