summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNachiket Kukade <nkukade@codeaurora.org>2018-02-19 17:13:11 +0530
committersnandini <snandini@codeaurora.org>2018-02-21 18:23:30 -0800
commit89d4fa175f20d0453dd7bf889519fd418a8b8984 (patch)
treea4ab34520bbb77a39a9775929ffb55af01009218
parentc9b41670dde907313739c5db0d9d96a260d532ed (diff)
qcacld-3.0: Add support for Android Packet Filter v3
Android Packet Filter 3.0 requires the framework to be able to read and write into the APF work memory in the Firmware. It also requires to be able to enable or disable the interpreter. Add support for the new read/write/enable/disable operations. Change-Id: Ic72243b918f4a8385a92b803a1ca3c5305423b52 CRs-Fixed: 2184969
-rw-r--r--Kbuild7
-rw-r--r--core/hdd/inc/wlan_hdd_apf.h75
-rw-r--r--core/hdd/inc/wlan_hdd_main.h14
-rw-r--r--core/hdd/src/wlan_hdd_apf.c436
-rw-r--r--core/hdd/src/wlan_hdd_cfg80211.c3
-rw-r--r--core/hdd/src/wlan_hdd_main.c12
-rw-r--r--core/sme/inc/sme_api.h107
-rw-r--r--core/sme/inc/sme_internal.h2
-rw-r--r--core/sme/src/common/sme_api.c116
-rw-r--r--core/wma/inc/wma.h71
-rw-r--r--core/wma/src/wma_features.c156
-rw-r--r--core/wma/src/wma_main.c5
-rw-r--r--uapi/linux/qca_vendor.h11
13 files changed, 887 insertions, 128 deletions
diff --git a/Kbuild b/Kbuild
index e6eda7af076e..147607295e19 100644
--- a/Kbuild
+++ b/Kbuild
@@ -851,8 +851,11 @@ WMI_OBJS := $(WMI_OBJ_DIR)/wmi_unified.o \
$(WMI_OBJ_DIR)/wmi_tlv_helper.o \
$(WMI_OBJ_DIR)/wmi_unified_tlv.o \
$(WMI_OBJ_DIR)/wmi_unified_api.o \
- $(WMI_OBJ_DIR)/wmi_unified_non_tlv.o \
- $(WMI_OBJ_DIR)/wmi_unified_apf_tlv.o
+ $(WMI_OBJ_DIR)/wmi_unified_non_tlv.o
+
+ifeq ($(CONFIG_WLAN_FEATURE_APF), y)
+WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_apf_tlv.o
+endif
WMI_CLEAN_FILES := $(WMI_OBJ_DIR)/*.o \
$(WMI_OBJ_DIR)/*.o.* \
diff --git a/core/hdd/inc/wlan_hdd_apf.h b/core/hdd/inc/wlan_hdd_apf.h
index 21eef17eba32..fe1e16df81d4 100644
--- a/core/hdd/inc/wlan_hdd_apf.h
+++ b/core/hdd/inc/wlan_hdd_apf.h
@@ -34,29 +34,84 @@
#ifndef __WLAN_HDD_APF_H
#define __WLAN_HDD_APF_H
+#include "qdf_nbuf.h"
+#include "qdf_types.h"
#include "sir_api.h"
#include "wlan_hdd_main.h"
+#include "wmi_unified.h"
+#include "wmi_unified_api.h"
+#include "wmi_unified_param.h"
+
+#define MAX_APF_MEMORY_LEN 4096
+
+/* APF commands wait times in msec */
+#define WLAN_WAIT_TIME_APF_GET_CAPS 1000
+#define WLAN_WAIT_TIME_APF_READ_MEM 10000
/**
- * hdd_get_apf_offload_cb() - Callback function to APF Offload
- * @hdd_context: hdd_context
- * @apf_get_offload: struct for get offload
+ * struct hdd_apf_context - hdd Context for apf
+ * @magic: magic number
+ * @qdf_apf_event: Completion variable for APF get operations
+ * @capability_response: capabilities response received from fw
+ * @apf_enabled: True: APF Interpreter enabled, False: Disabled
+ * @cmd_in_progress: Flag that indicates an APF command is in progress
+ * @buf: Buffer to accumulate read memory chunks
+ * @buf_len: Length of the read memory requested
+ * @offset: APF work memory offset to fetch from
+ * @lock: APF Context lock
+ */
+struct hdd_apf_context {
+ unsigned int magic;
+ qdf_event_t qdf_apf_event;
+ struct sir_apf_get_offload capability_response;
+ bool apf_enabled;
+ bool cmd_in_progress;
+ uint8_t *buf;
+ uint32_t buf_len;
+ uint32_t offset;
+ qdf_spinlock_t lock;
+};
+
+/**
+ * hdd_apf_read_memory_callback - HDD Callback for the APF read memory
+ * operation
+ * @context: Hdd context
+ * @read_mem_evt: APF read memory event response parameters
*
- * 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: 0 on success, errno on failure
+ */
+void
+hdd_apf_read_memory_callback(void *context,
+ struct wmi_apf_read_memory_resp_event_params
+ *read_mem_evt);
+
+/**
+ * hdd_apf_context_init - APF Context initialization operations
+ *
+ * Return: None
+ */
+void hdd_apf_context_init(void);
+
+/**
+ * hdd_apf_context_destroy - APF Context de-init operations
*
* Return: None
*/
-void hdd_get_apf_offload_cb(void *hdd_context,
- struct sir_apf_get_offload *data);
+void hdd_apf_context_destroy(void);
/**
- * hdd_init_apf_completion() - Initialize the completion event for apf
+ * hdd_get_apf_capabilities_cb() - Callback function to get APF capabilities
+ * @hdd_context: hdd_context
+ * @apf_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
*/
-void hdd_init_apf_completion(void);
+void hdd_get_apf_capabilities_cb(void *hdd_context,
+ struct sir_apf_get_offload *data);
/**
* wlan_hdd_cfg80211_apf_offload() - SSR Wrapper to APF Offload
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index f0615cd95ad7..34a5a657c192 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -163,8 +163,6 @@
#define WLAN_WAIT_TIME_ANTENNA_MODE_REQ 3000
#define WLAN_WAIT_TIME_SET_DUAL_MAC_CFG 1500
-#define WLAN_WAIT_TIME_APF 1000
-
/* rcpi request timeout in milli seconds */
#define WLAN_WAIT_TIME_RCPI 500
/* Maximum time(ms) to wait for RSO CMD status event */
@@ -1680,18 +1678,6 @@ struct hdd_offloaded_packets_ctx {
#endif
/**
- * struct hdd_apf_context - hdd Context for apf
- * @magic: magic number
- * @completion: Completion variable for APF Get Capability
- * @capability_response: capabilities response received from fw
- */
-struct hdd_apf_context {
- unsigned int magic;
- struct completion completion;
- struct sir_apf_get_offload capability_response;
-};
-
-/**
* enum driver_status: Driver Modules status
* @DRIVER_MODULES_UNINITIALIZED: Driver CDS modules uninitialized
* @DRIVER_MODULES_OPENED: Driver CDS modules opened
diff --git a/core/hdd/src/wlan_hdd_apf.c b/core/hdd/src/wlan_hdd_apf.c
index 8bb69d247c62..bb177c42735a 100644
--- a/core/hdd/src/wlan_hdd_apf.c
+++ b/core/hdd/src/wlan_hdd_apf.c
@@ -43,7 +43,7 @@ struct hdd_apf_context apf_context;
*/
#define APF_INVALID \
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID
-#define APF_SET_RESET \
+#define APF_SUBCMD \
QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER
#define APF_VERSION \
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION
@@ -55,29 +55,42 @@ struct hdd_apf_context apf_context;
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET
#define APF_PROGRAM \
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM
+#define APF_PROG_LEN \
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH
#define APF_MAX \
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX
static const struct nla_policy
wlan_hdd_apf_offload_policy[APF_MAX + 1] = {
- [APF_SET_RESET] = {.type = NLA_U32},
+ [APF_SUBCMD] = {.type = NLA_U32},
[APF_VERSION] = {.type = NLA_U32},
[APF_FILTER_ID] = {.type = NLA_U32},
[APF_PACKET_SIZE] = {.type = NLA_U32},
[APF_CURRENT_OFFSET] = {.type = NLA_U32},
- [APF_PROGRAM] = {.type = NLA_U8},
+ [APF_PROGRAM] = {.type = NLA_BINARY,
+ .len = MAX_APF_MEMORY_LEN},
+ [APF_PROG_LEN] = {.type = NLA_U32},
};
-void hdd_init_apf_completion(void)
+void hdd_apf_context_init(void)
{
- init_completion(&apf_context.completion);
+ qdf_event_create(&apf_context.qdf_apf_event);
+ qdf_spinlock_create(&apf_context.lock);
+ apf_context.apf_enabled = true;
}
-void hdd_get_apf_offload_cb(void *hdd_context,
- struct sir_apf_get_offload *data)
+void hdd_apf_context_destroy(void)
+{
+ qdf_event_destroy(&apf_context.qdf_apf_event);
+ qdf_spinlock_destroy(&apf_context.lock);
+ qdf_mem_zero(&apf_context, sizeof(apf_context));
+}
+
+void hdd_get_apf_capabilities_cb(void *hdd_context,
+ struct sir_apf_get_offload *data)
{
hdd_context_t *hdd_ctx = hdd_context;
- struct hdd_apf_context *context;
+ struct hdd_apf_context *context = &apf_context;
ENTER();
@@ -87,12 +100,11 @@ void hdd_get_apf_offload_cb(void *hdd_context,
return;
}
- spin_lock(&hdd_context_lock);
+ qdf_spin_lock(&context->lock);
- context = &apf_context;
/* The caller presumably timed out so there is nothing we can do */
if (context->magic != APF_CONTEXT_MAGIC) {
- spin_unlock(&hdd_context_lock);
+ qdf_spin_unlock(&context->lock);
return;
}
@@ -101,9 +113,9 @@ void hdd_get_apf_offload_cb(void *hdd_context,
context->magic = 0;
context->capability_response = *data;
- complete(&context->completion);
+ qdf_event_set(&context->qdf_apf_event);
- spin_unlock(&hdd_context_lock);
+ qdf_spin_unlock(&context->lock);
}
/**
@@ -113,8 +125,9 @@ void hdd_get_apf_offload_cb(void *hdd_context,
*
* Return: 0 on success, error number otherwise.
*/
-static int hdd_post_get_apf_capabilities_rsp(hdd_context_t *hdd_ctx,
- struct sir_apf_get_offload *apf_get_offload)
+static int
+hdd_post_get_apf_capabilities_rsp(hdd_context_t *hdd_ctx,
+ struct sir_apf_get_offload *apf_get_offload)
{
struct sk_buff *skb;
uint32_t nl_buf_len;
@@ -153,39 +166,37 @@ nla_put_failure:
}
/**
- * hdd_get_apf_offload - Get APF offload Capabilities
+ * hdd_get_apf_capabilities - Get APF Capabilities
* @hdd_ctx: Hdd context
*
* Return: 0 on success, errno on failure
*/
-static int hdd_get_apf_offload(hdd_context_t *hdd_ctx)
+static int hdd_get_apf_capabilities(hdd_context_t *hdd_ctx)
{
- unsigned long rc;
- static struct hdd_apf_context *context;
+ static struct hdd_apf_context *context = &apf_context;
QDF_STATUS status;
int ret;
ENTER();
- spin_lock(&hdd_context_lock);
- context = &apf_context;
+ qdf_spin_lock(&context->lock);
context->magic = APF_CONTEXT_MAGIC;
- INIT_COMPLETION(context->completion);
- spin_unlock(&hdd_context_lock);
+ qdf_event_reset(&context->qdf_apf_event);
+ qdf_spin_unlock(&context->lock);
- status = sme_get_apf_offload_capabilities(hdd_ctx->hHal);
- if (!QDF_IS_STATUS_SUCCESS(status)) {
+ status = sme_get_apf_capabilities(hdd_ctx->hHal);
+ if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Unable to retrieve APF caps");
return -EINVAL;
}
/* request was sent -- wait for the response */
- rc = wait_for_completion_timeout(&context->completion,
- msecs_to_jiffies(WLAN_WAIT_TIME_APF));
- if (!rc) {
+ status = qdf_wait_for_event_completion(&context->qdf_apf_event,
+ WLAN_WAIT_TIME_APF_GET_CAPS);
+ if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Target response timed out");
- spin_lock(&hdd_context_lock);
+ qdf_spin_lock(&context->lock);
context->magic = 0;
- spin_unlock(&hdd_context_lock);
+ qdf_spin_unlock(&context->lock);
return -ETIMEDOUT;
}
@@ -217,13 +228,10 @@ static int hdd_set_reset_apf_offload(hdd_context_t *hdd_ctx,
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;
- }
+ if (!hdd_conn_is_connected(
+ WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
+ hdd_err("Not in Connected state!");
+ return -ENOTSUPP;
}
apf_set_offload = qdf_mem_malloc(sizeof(*apf_set_offload));
@@ -286,7 +294,7 @@ static int hdd_set_reset_apf_offload(hdd_context_t *hdd_ctx,
apf_set_offload->current_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]);
post_sme:
- hdd_debug("Posting APF SET/RESET to SME, session_id: %d Bpf Version: %d filter ID: %d total_length: %d current_length: %d current offset: %d",
+ hdd_debug("Posting APF SET/RESET to SME, session_id: %d APF Version: %d filter ID: %d total_length: %d current_length: %d current offset: %d",
apf_set_offload->session_id,
apf_set_offload->version,
apf_set_offload->filter_id,
@@ -310,6 +318,290 @@ fail:
}
/**
+ * hdd_enable_disable_apf - Enable or Disable the APF interpreter
+ * @vdev_id: VDEV id
+ * @hdd_ctx: Hdd context
+ * @apf_enable: true: Enable APF Int., false: disable APF Int.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int
+hdd_enable_disable_apf(hdd_context_t *hdd_ctx, uint8_t vdev_id, bool apf_enable)
+{
+ QDF_STATUS status;
+
+ ENTER();
+
+ status = sme_set_apf_enable_disable(hdd_ctx->hHal, vdev_id, apf_enable);
+ if (!QDF_IS_STATUS_SUCCESS(status)) {
+ hdd_err("Unable to post sme apf enable/disable message (status-%d)",
+ status);
+ return -EINVAL;
+ }
+
+ qdf_spin_lock(&apf_context.lock);
+ apf_context.apf_enabled = apf_enable;
+ qdf_spin_unlock(&apf_context.lock);
+
+ EXIT();
+ return 0;
+}
+
+/**
+ * hdd_apf_write_memory - Write into the apf work memory
+ * @hdd_ctx: Hdd context
+ * @tb: list of attributes
+ * @session_id: Session id
+ *
+ * This function writes code/data into the APF work memory and
+ * provides program length that is passed on to the interpreter.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int
+hdd_apf_write_memory(hdd_context_t *hdd_ctx, struct nlattr **tb,
+ uint8_t session_id)
+{
+ struct wmi_apf_write_memory_params write_mem_params = {0};
+ QDF_STATUS status;
+ int ret = 0;
+ bool apf_enabled;
+
+ ENTER();
+
+ write_mem_params.vdev_id = session_id;
+
+ qdf_spin_lock(&apf_context.lock);
+ apf_enabled = apf_context.apf_enabled;
+ qdf_spin_unlock(&apf_context.lock);
+
+ if (apf_enabled) {
+ hdd_err("Cannot get/set when APF interpreter is enabled");
+ return -EINVAL;
+ }
+
+ /* Read program length */
+ if (!tb[APF_PROG_LEN]) {
+ hdd_err("attr program length failed");
+ return -EINVAL;
+ }
+ write_mem_params.program_len = nla_get_u32(tb[APF_PROG_LEN]);
+
+ /* Read APF work memory offset */
+ if (!tb[APF_CURRENT_OFFSET]) {
+ hdd_err("attr apf packet size failed");
+ return -EINVAL;
+ }
+ write_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]);
+
+ /* Parse and fetch apf program */
+ if (!tb[APF_PROGRAM]) {
+ hdd_err("attr apf program failed");
+ return -EINVAL;
+ }
+
+ write_mem_params.length = nla_len(tb[APF_PROGRAM]);
+ if (!write_mem_params.length) {
+ hdd_err("Program attr with empty data");
+ return -EINVAL;
+ }
+
+ write_mem_params.buf = qdf_mem_malloc(sizeof(uint8_t)
+ * write_mem_params.length);
+ if (write_mem_params.buf == NULL) {
+ hdd_err("failed to alloc mem for apf write mem operation");
+ return -EINVAL;
+ }
+ nla_memcpy(write_mem_params.buf, tb[APF_PROGRAM],
+ write_mem_params.length);
+
+ write_mem_params.apf_version =
+ apf_context.capability_response.apf_version;
+
+ status = sme_apf_write_work_memory(hdd_ctx->hHal, &write_mem_params);
+ if (!QDF_IS_STATUS_SUCCESS(status)) {
+ hdd_err("Unable to retrieve APF caps");
+ ret = -EINVAL;
+ }
+
+ if (write_mem_params.buf)
+ qdf_mem_free(write_mem_params.buf);
+
+ EXIT();
+ return ret;
+}
+
+void
+hdd_apf_read_memory_callback(void *hdd_context,
+ struct wmi_apf_read_memory_resp_event_params
+ *read_mem_evt)
+{
+ hdd_context_t *hdd_ctx = hdd_context;
+ static struct hdd_apf_context *context = &apf_context;
+ uint8_t *buf_ptr;
+ uint32_t pkt_offset;
+ ENTER();
+
+ if (wlan_hdd_validate_context(hdd_ctx) || !read_mem_evt) {
+ hdd_err("HDD context is invalid or event buf(%pK) is null",
+ read_mem_evt);
+ return;
+ }
+
+ qdf_spin_lock(&context->lock);
+ if (context->magic != APF_CONTEXT_MAGIC) {
+ /* The caller presumably timed out, nothing to do */
+ qdf_spin_unlock(&context->lock);
+ hdd_err("Caller timed out or corrupt magic, simply return");
+ return;
+ }
+
+ if (read_mem_evt->offset < context->offset) {
+ qdf_spin_unlock(&context->lock);
+ hdd_err("Offset in read event(%d) smaller than offset in request(%d)!",
+ read_mem_evt->offset, context->offset);
+ return;
+ }
+
+ /*
+ * offset in the event is relative to the APF work memory.
+ * Calculate the packet offset, which gives us the relative
+ * location in the buffer to start copy into.
+ */
+ pkt_offset = read_mem_evt->offset - context->offset;
+
+ if (context->buf_len < pkt_offset + read_mem_evt->length) {
+ qdf_spin_unlock(&context->lock);
+ hdd_err("Read chunk exceeding allocated space");
+ return;
+ }
+ buf_ptr = context->buf + pkt_offset;
+
+ qdf_mem_copy(buf_ptr, read_mem_evt->data, read_mem_evt->length);
+
+ if (!read_mem_evt->more_data) {
+ /* Release the caller after last event, clear magic */
+ context->magic = 0;
+ qdf_event_set(&context->qdf_apf_event);
+ }
+
+ qdf_spin_unlock(&context->lock);
+
+ EXIT();
+}
+
+/**
+ * hdd_apf_read_memory - Read part of the apf work memory
+ * @hdd_ctx: Hdd context
+ * @tb: list of attributes
+ * @session_id: Session id
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int hdd_apf_read_memory(hdd_context_t *hdd_ctx, struct nlattr **tb,
+ uint8_t session_id)
+{
+ struct wmi_apf_read_memory_params read_mem_params = {0};
+ static struct hdd_apf_context *context = &apf_context;
+ QDF_STATUS status;
+ unsigned long nl_buf_len = NLMSG_HDRLEN;
+ int ret = 0;
+ struct sk_buff *skb = NULL;
+ uint8_t *bufptr;
+
+ ENTER();
+
+ read_mem_params.vdev_id = session_id;
+
+ /* Read APF work memory offset */
+ if (!tb[APF_CURRENT_OFFSET]) {
+ hdd_err("attr apf memory offset failed");
+ return -EINVAL;
+ }
+ read_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]);
+
+ /* Read length */
+ if (!tb[APF_PACKET_SIZE]) {
+ hdd_err("attr apf packet size failed");
+ return -EINVAL;
+ }
+ read_mem_params.length = nla_get_u32(tb[APF_PACKET_SIZE]);
+ if (!read_mem_params.length) {
+ hdd_err("apf read length cannot be zero!");
+ return -EINVAL;
+ }
+ bufptr = qdf_mem_malloc(read_mem_params.length);
+ if (bufptr == NULL) {
+ hdd_err("alloc failed for cumulative event buffer");
+ return -ENOMEM;
+ }
+
+ qdf_spin_lock(&context->lock);
+ if (context->apf_enabled) {
+ qdf_spin_unlock(&context->lock);
+ hdd_err("Cannot get/set while interpreter is enabled");
+ return -EINVAL;
+ }
+
+ qdf_event_reset(&context->qdf_apf_event);
+ context->offset = read_mem_params.addr_offset;
+
+ context->buf = bufptr;
+ context->buf_len = read_mem_params.length;
+ context->magic = APF_CONTEXT_MAGIC;
+ qdf_spin_unlock(&context->lock);
+
+ status = sme_apf_read_work_memory(hdd_ctx->hHal, &read_mem_params);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ hdd_err("Unable to post sme APF read memory message (status-%d)",
+ status);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* request was sent -- wait for the response */
+ status = qdf_wait_for_event_completion(&context->qdf_apf_event,
+ WLAN_WAIT_TIME_APF_READ_MEM);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ hdd_err("Target response timed out");
+ qdf_spin_lock(&context->lock);
+ context->magic = 0;
+ qdf_spin_unlock(&context->lock);
+ ret = -ETIMEDOUT;
+ goto fail;
+ }
+
+ nl_buf_len += sizeof(uint32_t) + NLA_HDRLEN;
+ nl_buf_len += context->buf_len + 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");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (nla_put_u32(skb, APF_SUBCMD, QCA_WLAN_READ_PACKET_FILTER) ||
+ nla_put(skb, APF_PROGRAM, read_mem_params.length, context->buf)) {
+ hdd_err("put fail");
+ kfree_skb(skb);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ cfg80211_vendor_cmd_reply(skb);
+fail:
+ if (context->buf) {
+ qdf_mem_free(context->buf);
+ context->buf = NULL;
+ }
+
+ EXIT();
+ return ret;
+}
+
+
+/**
* wlan_hdd_cfg80211_apf_offload() - Set/Reset to APF Offload
* @wiphy: wiphy structure pointer
* @wdev: Wireless device structure pointer
@@ -325,9 +617,11 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
{
hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
struct net_device *dev = wdev->netdev;
- hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
struct nlattr *tb[APF_MAX + 1];
- int ret_val, packet_filter_subcmd;
+ int ret_val = 0, apf_subcmd;
+ uint8_t session_id = adapter->sessionId;
+ static struct hdd_apf_context *context = &apf_context;
ENTER();
@@ -351,18 +645,64 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
return -EINVAL;
}
- if (!tb[APF_SET_RESET]) {
- hdd_err("attr apf set reset failed");
+ if (!(adapter->device_mode == QDF_STA_MODE ||
+ adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
+ hdd_err("APF only supported in STA or P2P CLI modes!");
+ return -ENOTSUPP;
+ }
+
+ if (!tb[APF_SUBCMD]) {
+ hdd_err("attr apf sub-command failed");
return -EINVAL;
}
+ apf_subcmd = nla_get_u32(tb[APF_SUBCMD]);
+
+ qdf_spin_lock(&context->lock);
+ if (context->cmd_in_progress) {
+ qdf_spin_unlock(&context->lock);
+ hdd_err("Another APF cmd in progress, try again later!");
+ return -EAGAIN;
+ }
+ context->cmd_in_progress = true;
+ qdf_spin_unlock(&context->lock);
+
+ switch (apf_subcmd) {
+ /* Legacy APF sub-commands */
+ case QCA_WLAN_SET_PACKET_FILTER:
+ ret_val = hdd_set_reset_apf_offload(hdd_ctx, tb,
+ adapter);
+ break;
+ case QCA_WLAN_GET_PACKET_FILTER:
+ ret_val = hdd_get_apf_capabilities(hdd_ctx);
+ break;
+
+ /* APF 3.0 sub-commands */
+ case QCA_WLAN_WRITE_PACKET_FILTER:
+ ret_val = hdd_apf_write_memory(hdd_ctx, tb, session_id);
+ break;
+ case QCA_WLAN_READ_PACKET_FILTER:
+ ret_val = hdd_apf_read_memory(hdd_ctx, tb, session_id);
+ break;
+ case QCA_WLAN_ENABLE_PACKET_FILTER:
+ ret_val = hdd_enable_disable_apf(hdd_ctx,
+ session_id,
+ true);
+ break;
+ case QCA_WLAN_DISABLE_PACKET_FILTER:
+ ret_val = hdd_enable_disable_apf(hdd_ctx,
+ session_id,
+ false);
+ break;
+ default:
+ hdd_err("Unknown APF Sub-command: %d", apf_subcmd);
+ ret_val = -ENOTSUPP;
+ }
- packet_filter_subcmd = nla_get_u32(tb[APF_SET_RESET]);
+ qdf_spin_lock(&context->lock);
+ context->cmd_in_progress = false;
+ qdf_spin_unlock(&context->lock);
- if (packet_filter_subcmd == QCA_WLAN_GET_PACKET_FILTER)
- return hdd_get_apf_offload(hdd_ctx);
- else
- return hdd_set_reset_apf_offload(hdd_ctx, tb,
- pAdapter);
+ return ret_val;
}
/**
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index db86c887615e..9f4da525501e 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -96,7 +96,10 @@
#include "wlan_hdd_nan_datapath.h"
#include "wlan_hdd_disa.h"
#include "wlan_hdd_spectralscan.h"
+
+#ifdef WLAN_FEATURE_APF
#include "wlan_hdd_apf.h"
+#endif
#include "wmi_unified.h"
#include "wmi_unified_param.h"
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 58a3531b35ef..584d1c19287b 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -113,7 +113,9 @@
#include "wlan_hdd_spectralscan.h"
#include "sme_power_save_api.h"
#include "wlan_hdd_sysfs.h"
+#ifdef WLAN_FEATURE_APF
#include "wlan_hdd_apf.h"
+#endif
#ifdef CNSS_GENL
#include <net/cnss_nl.h>
@@ -6154,6 +6156,8 @@ static int hdd_context_deinit(hdd_context_t *hdd_ctx)
qdf_list_destroy(&hdd_ctx->hddAdapters);
+ hdd_apf_context_destroy();
+
return 0;
}
@@ -8284,7 +8288,7 @@ static int hdd_context_init(hdd_context_t *hdd_ctx)
init_completion(&hdd_ctx->mc_sus_event_var);
init_completion(&hdd_ctx->ready_to_suspend);
- hdd_init_apf_completion();
+ hdd_apf_context_init();
qdf_spinlock_create(&hdd_ctx->connection_status_lock);
qdf_spinlock_create(&hdd_ctx->sta_update_info_lock);
@@ -10906,7 +10910,7 @@ int hdd_register_cb(hdd_context_t *hdd_ctx)
hdd_get_nud_stats_cb);
status = sme_apf_offload_register_callback(hdd_ctx->hHal,
- hdd_get_apf_offload_cb);
+ hdd_get_apf_capabilities_cb);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("set apf offload callback failed");
ret = -EINVAL;
@@ -10948,6 +10952,9 @@ int hdd_register_cb(hdd_context_t *hdd_ctx)
if (!QDF_IS_STATUS_SUCCESS(status))
hdd_err("set congestion callback failed");
+ sme_apf_read_memory_register_callback(hdd_ctx->hHal,
+ hdd_apf_read_memory_callback);
+
EXIT();
return ret;
@@ -11000,6 +11007,7 @@ void hdd_deregister_cb(hdd_context_t *hdd_ctx)
sme_deregister_oem_data_rsp_callback(hdd_ctx->hHal);
sme_deregister11d_scan_done_callback(hdd_ctx->hHal);
+ sme_apf_read_memory_deregister_callback(hdd_ctx->hHal);
EXIT();
}
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index 96804b17c37f..82d8eee99fae 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -1370,14 +1370,118 @@ bool sme_is_sta_smps_allowed(tHalHandle hHal, uint8_t session_id);
QDF_STATUS sme_add_beacon_filter(tHalHandle hal,
uint32_t session_id, uint32_t *ie_map);
QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id);
+
+/**
+ * sme_apf_offload_register_callback() - Register get apf offload callback
+ *
+ * @hal - MAC global handle
+ * @callback_routine - callback routine from HDD
+ *
+ * API used by HDD to register its APF get caps callback in SME.
+ *
+ * Return: QDF_STATUS
+ */
QDF_STATUS sme_apf_offload_register_callback(tHalHandle hal,
void (*papf_get_offload_cb)(void *,
struct sir_apf_get_offload *));
+
+/**
+ * sme_apf_offload_deregister_callback() - De-register get apf offload callback
+ *
+ * @hal - MAC global handle
+ *
+ * API used by HDD to de-register its APF get caps callback in SME.
+ *
+ * Return: QDF_STATUS
+ */
QDF_STATUS sme_apf_offload_deregister_callback(tHalHandle hal);
-QDF_STATUS sme_get_apf_offload_capabilities(tHalHandle hal);
+/**
+ * sme_get_apf_capabilities() - Get length for APF offload
+ * @hal: Global HAL handle
+ *
+ * API to get APF version and max filter size.
+ *
+ * Return: QDF_STATUS enumeration
+ */
+QDF_STATUS sme_get_apf_capabilities(tHalHandle hal);
+
+/**
+ * sme_set_apf_instructions() - Set APF apf filter instructions.
+ * @hal: HAL handle
+ * @apf_set_offload: struct to set apf filter instructions.
+ *
+ * APFv2 (Legacy APF) API to set the APF packet filter.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
QDF_STATUS sme_set_apf_instructions(tHalHandle hal,
struct sir_apf_set_offload *);
+
+/**
+ * sme_set_apf_enable_disable - Send apf enable/disable cmd
+ * @hal: global hal handle
+ * @vdev_id: vdev id
+ * @apf_enable: true: Enable APF Int., false: Disable APF Int.
+ *
+ * API to either enable or disable the APF interpreter.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS sme_set_apf_enable_disable(tHalHandle hal, uint8_t vdev_id,
+ bool apf_enable);
+
+/**
+ * sme_apf_write_work_memory - Write into the apf work memory
+ * @hal: global hal handle
+ * @write_params: APF parameters for the write operation
+ *
+ * API for writing into the APF work memory.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS sme_apf_write_work_memory(tHalHandle hal,
+ struct wmi_apf_write_memory_params
+ *write_params);
+
+/**
+ * sme_apf_read_work_memory - Read part of apf work memory
+ * @hal: global hal handle
+ * @read_params: APF parameters for the get operation
+ *
+ * API for issuing a APF read memory request.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS
+sme_apf_read_work_memory(tHalHandle hal,
+ struct wmi_apf_read_memory_params *read_params);
+
+/**
+ * sme_apf_read_memory_register_callback() - Register apf mem callback
+ *
+ * @hal - MAC global handle
+ * @callback_routine - callback routine from HDD
+ *
+ * API used by HDD to register its APF read memory callback in SME.
+ *
+ * Return: QDF_STATUS Enumeration
+ */
+QDF_STATUS sme_apf_read_memory_register_callback(tHalHandle hal,
+ void (*apf_read_mem_cb)(void *context,
+ struct wmi_apf_read_memory_resp_event_params *));
+
+/**
+ * sme_apf_read_memory_deregister_callback() - De-register apf mem callback
+ *
+ * @h_hal - MAC global handle
+ *
+ * API used by HDD to de-register its APF read memory callback in SME.
+ *
+ * Return: QDF_STATUS Enumeration
+ */
+QDF_STATUS sme_apf_read_memory_deregister_callback(tHalHandle h_hal);
+
uint32_t sme_get_wni_dot11_mode(tHalHandle hal);
QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid);
QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal,
@@ -2058,5 +2162,4 @@ void sme_enable_roaming_on_connected_sta(tHalHandle hal);
* false - if not in progress
*/
bool sme_is_sta_key_exchange_in_progress(tHalHandle hal, uint8_t session_id);
-
#endif /* #if !defined( __SME_API_H ) */
diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h
index 86eab8284a67..66f58c7eba18 100644
--- a/core/sme/inc/sme_internal.h
+++ b/core/sme/inc/sme_internal.h
@@ -283,6 +283,8 @@ typedef struct tagSmeStruct {
struct spectral_samp_msg *samp_msg);
void (*stats_ext2_cb)(void *, struct stats_ext2_event *);
void (*congestion_cb)(void *, uint32_t congestion, uint32_t vdev_id);
+ void (*apf_read_mem_cb)(void *context,
+ struct wmi_apf_read_memory_resp_event_params *params);
} tSmeStruct, *tpSmeStruct;
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index 2e4ee5285ebc..b6886ef92bfd 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -16714,14 +16714,7 @@ void sme_send_disassoc_req_frame(tHalHandle hal, uint8_t session_id,
FL("cds_send_mb_message Failed"));
}
-/**
- * sme_get_apf_offload_capabilities() - Get length for APF offload
- * @hal: Global HAL handle
- * This function constructs the cds message and fill in message type,
- * post the same to WDA.
- * Return: QDF_STATUS enumeration
- */
-QDF_STATUS sme_get_apf_offload_capabilities(tHalHandle hal)
+QDF_STATUS sme_get_apf_capabilities(tHalHandle hal)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
@@ -16750,14 +16743,6 @@ QDF_STATUS sme_get_apf_offload_capabilities(tHalHandle hal)
return status;
}
-
-/**
- * sme_set_apf_instructions() - Set APF apf filter instructions.
- * @hal: HAL handle
- * @apf_set_offload: struct to set apf filter instructions.
- *
- * Return: QDF_STATUS enumeration.
- */
QDF_STATUS sme_set_apf_instructions(tHalHandle hal,
struct sir_apf_set_offload *req)
{
@@ -16808,16 +16793,95 @@ QDF_STATUS sme_set_apf_instructions(tHalHandle hal,
return status;
}
-/**
- * sme_apf_offload_register_callback() - Register get apf offload callbacK
- *
- * @hal - MAC global handle
- * @callback_routine - callback routine from HDD
- *
- * This API is invoked by HDD to register its callback in SME
- *
- * Return: QDF_STATUS
- */
+QDF_STATUS sme_set_apf_enable_disable(tHalHandle hal, uint8_t vdev_id,
+ bool apf_enable)
+{
+ void *wma_handle;
+
+ wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+ if (!wma_handle) {
+ QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+ "wma handle is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return wma_send_apf_enable_cmd(wma_handle, vdev_id, apf_enable);
+}
+
+QDF_STATUS
+sme_apf_write_work_memory(tHalHandle hal,
+ struct wmi_apf_write_memory_params *write_params)
+{
+ void *wma_handle;
+
+ wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+ if (!wma_handle) {
+ QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+ "wma handle is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return wma_send_apf_write_work_memory_cmd(wma_handle, write_params);
+}
+
+QDF_STATUS
+sme_apf_read_work_memory(tHalHandle hal,
+ struct wmi_apf_read_memory_params *read_params)
+{
+ void *wma_handle;
+
+ wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+ if (!wma_handle) {
+ QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+ "wma handle is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return wma_send_apf_read_work_memory_cmd(wma_handle, read_params);
+}
+
+QDF_STATUS sme_apf_read_memory_register_callback(tHalHandle hal,
+ void (*apf_read_mem_cb)(void *context,
+ struct wmi_apf_read_memory_resp_event_params *))
+{
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ tpAniSirGlobal mac = PMAC_STRUCT(hal);
+
+ status = sme_acquire_global_lock(&mac->sme);
+ if (QDF_IS_STATUS_SUCCESS(status)) {
+ mac->sme.apf_read_mem_cb = apf_read_mem_cb;
+ sme_release_global_lock(&mac->sme);
+ } else {
+ QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+ FL("sme_acquire_global_lock failed"));
+ }
+ return status;
+}
+
+QDF_STATUS sme_apf_read_memory_deregister_callback(tHalHandle h_hal)
+{
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ tpAniSirGlobal mac;
+
+ if (!h_hal) {
+ QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+ FL("hHal is not valid"));
+ return QDF_STATUS_E_INVAL;
+ }
+
+ mac = PMAC_STRUCT(h_hal);
+
+ status = sme_acquire_global_lock(&mac->sme);
+ if (QDF_IS_STATUS_SUCCESS(status)) {
+ mac->sme.apf_read_mem_cb = NULL;
+ sme_release_global_lock(&mac->sme);
+ } else {
+ QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+ FL("sme_acquire_global_lock failed"));
+ }
+ return status;
+}
+
QDF_STATUS sme_apf_offload_register_callback(tHalHandle hal,
void (*papf_get_offload_cb)(void *context,
struct sir_apf_get_offload *))
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index c1c2b35aa57e..d5376815c779 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -2456,13 +2456,82 @@ void wma_process_fw_test_cmd(WMA_HANDLE handle,
QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma,
struct obss_ht40_scanind *req);
+uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask);
+
+/**
+ * wma_get_apf_caps_event_handler() - Event handler for get apf capability
+ * @handle: WMA global handle
+ * @cmd_param_info: command event data
+ * @len: Length of @cmd_param_info
+ *
+ * Return: 0 on Success or Errno on failure
+ */
int wma_get_apf_caps_event_handler(void *handle,
u_int8_t *cmd_param_info,
u_int32_t len);
-uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask);
+
+/**
+ * wma_get_apf_capabilities - Send get apf capability to firmware
+ * @wma_handle: wma handle
+ *
+ * Return: QDF_STATUS enumeration.
+ */
QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma);
+
+/**
+ * wma_set_apf_instructions - Set apf instructions to firmware
+ * @wma: wma handle
+ * @apf_set_offload: APF offload information to set to firmware
+ *
+ * Return: QDF_STATUS enumeration
+ */
QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma,
struct sir_apf_set_offload *apf_set_offload);
+
+/**
+ * wma_send_apf_enable_cmd - Send apf enable/disable cmd
+ * @wma_handle: wma handle
+ * @vdev_id: vdev id
+ * @apf_enable: true: Enable APF Int., false: Disable APF Int.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS wma_send_apf_enable_cmd(WMA_HANDLE handle, uint8_t vdev_id,
+ bool apf_enable);
+
+/**
+ * wma_send_apf_write_work_memory_cmd - Command to write into the apf work memory
+ * @wma_handle: wma handle
+ * @write_params: APF parameters for the write operation
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS wma_send_apf_write_work_memory_cmd(WMA_HANDLE handle,
+ struct wmi_apf_write_memory_params *write_params);
+
+/**
+ * wma_send_apf_read_work_memory_cmd - Command to get part of apf work memory
+ * @wma_handle: wma handle
+ * @callback: HDD callback to receive apf get mem event
+ * @context: Context for the HDD callback
+ * @read_params: APF parameters for the get operation
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS wma_send_apf_read_work_memory_cmd(WMA_HANDLE handle,
+ struct wmi_apf_read_memory_params *read_params);
+
+/**
+ * wma_apf_read_work_memory_event_handler - Event handler for get apf mem operation
+ * @handle: wma handle
+ * @evt_buf: Buffer pointer to the event
+ * @len: Length of the event buffer
+ *
+ * Return: status.
+ */
+int wma_apf_read_work_memory_event_handler(void *handle, uint8_t *evt_buf,
+ uint32_t len);
+
void wma_process_set_pdev_ie_req(tp_wma_handle wma,
struct set_ie_param *ie_params);
void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma,
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index bc8663faf0a9..487e453b3ad1 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -3744,7 +3744,7 @@ static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason)
case WOW_REASON_ACTION_FRAME_RECV:
return "ACTION_FRAME_RECV";
case WOW_REASON_BPF_ALLOW:
- return "APF_ALLOW";
+ return "BPF_ALLOW";
case WOW_REASON_NAN_DATA:
return "NAN_DATA";
case WOW_REASON_OEM_RESPONSE_EVENT:
@@ -9783,14 +9783,6 @@ QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma,
return ret;
}
-/**
- * wma_get_apf_caps_event_handler() - Event handler for get apf capability
- * @handle: WMA global handle
- * @cmd_param_info: command event data
- * @len: Length of @cmd_param_info
- *
- * Return: 0 on Success or Errno on failure
- */
int wma_get_apf_caps_event_handler(void *handle,
u_int8_t *cmd_param_info,
u_int32_t len)
@@ -9833,12 +9825,6 @@ int wma_get_apf_caps_event_handler(void *handle,
return 0;
}
-/**
- * wma_get_apf_capabilities - Send get apf capability to firmware
- * @wma_handle: wma handle
- *
- * Return: QDF_STATUS enumeration.
- */
QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -9881,13 +9867,6 @@ QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma)
return status;
}
-/**
- * wma_set_apf_instructions - Set apf instructions to firmware
- * @wma: wma handle
- * @apf_set_offload: Bpf offload information to set to firmware
- *
- * Return: QDF_STATUS enumeration
- */
QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma,
struct sir_apf_set_offload *apf_set_offload)
{
@@ -9971,6 +9950,139 @@ QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma,
return QDF_STATUS_SUCCESS;
}
+QDF_STATUS wma_send_apf_enable_cmd(WMA_HANDLE handle, uint8_t vdev_id,
+ bool apf_enable)
+{
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ tp_wma_handle wma = (tp_wma_handle) handle;
+
+ if (!wma || !wma->wmi_handle) {
+ WMA_LOGE(FL("WMA is closed, can not issue get APF capab"));
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+ WMI_SERVICE_BPF_OFFLOAD)) {
+ WMA_LOGE(FL("APF cababilities feature bit not enabled"));
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ status = wmi_unified_send_apf_enable_cmd(wma->wmi_handle, vdev_id,
+ apf_enable);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ WMA_LOGE("Failed to send apf enable/disable cmd");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ if (apf_enable)
+ WMA_LOGD("Sent APF Enable on vdevid: %d", vdev_id);
+ else
+ WMA_LOGD("Sent APF Disable on vdevid: %d", vdev_id);
+
+ return status;
+}
+
+QDF_STATUS
+wma_send_apf_write_work_memory_cmd(WMA_HANDLE handle,
+ struct wmi_apf_write_memory_params *write_params)
+{
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ tp_wma_handle wma = (tp_wma_handle) handle;
+
+ if (!wma || !wma->wmi_handle) {
+ WMA_LOGE(FL("WMA is closed, can not issue write APF mem"));
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+ WMI_SERVICE_BPF_OFFLOAD)) {
+ WMA_LOGE(FL("APF cababilities feature bit not enabled"));
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ if (wmi_unified_send_apf_write_work_memory_cmd(wma->wmi_handle,
+ write_params)) {
+ WMA_LOGE(FL("Failed to send APF write mem command"));
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ WMA_LOGD("Sent APF wite mem on vdevid: %d", write_params->vdev_id);
+ return status;
+}
+
+int wma_apf_read_work_memory_event_handler(void *handle, uint8_t *evt_buf,
+ uint32_t len)
+{
+ tp_wma_handle wma_handle;
+ wmi_unified_t wmi_handle;
+ struct wmi_apf_read_memory_resp_event_params evt_params = {0};
+ QDF_STATUS status;
+ tpAniSirGlobal pmac = cds_get_context(QDF_MODULE_ID_PE);
+
+ WMA_LOGI(FL("handle:%pK event:%pK len:%u"), handle, evt_buf, len);
+
+ wma_handle = handle;
+ if (!wma_handle) {
+ WMA_LOGE(FL("NULL wma_handle"));
+ return -EINVAL;
+ }
+
+ wmi_handle = wma_handle->wmi_handle;
+ if (!wmi_handle) {
+ WMA_LOGE(FL("NULL wmi_handle"));
+ return -EINVAL;
+ }
+
+ if (!pmac) {
+ WMA_LOGE(FL("Invalid pmac"));
+ return -EINVAL;
+ }
+
+ if (!pmac->sme.apf_read_mem_cb) {
+ WMA_LOGE(FL("Callback not registered"));
+ return -EINVAL;
+ }
+
+ status = wmi_extract_apf_read_memory_resp_event(wmi_handle,
+ evt_buf, &evt_params);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ WMA_LOGE(FL("Event extract failure: %d"), status);
+ return -EINVAL;
+ }
+
+ pmac->sme.apf_read_mem_cb(pmac->hHdd, &evt_params);
+
+ return 0;
+}
+
+QDF_STATUS wma_send_apf_read_work_memory_cmd(WMA_HANDLE handle,
+ struct wmi_apf_read_memory_params
+ *read_params)
+{
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ tp_wma_handle wma = (tp_wma_handle) handle;
+
+ if (!wma || !wma->wmi_handle) {
+ WMA_LOGE(FL("WMA is closed, can not issue read APF memory"));
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+ WMI_SERVICE_BPF_OFFLOAD)) {
+ WMA_LOGE(FL("APF cababilities feature bit not enabled"));
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ if (wmi_unified_send_apf_read_work_memory_cmd(wma->wmi_handle,
+ read_params)) {
+ WMA_LOGE(FL("Failed to send APF read memory command"));
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ WMA_LOGD("Sent APF read memory on vdevid: %d", read_params->vdev_id);
+ return status;
+}
+
/**
* wma_set_tx_rx_aggregation_size() - sets tx rx aggregation sizes
* @tx_rx_aggregation_size: aggregation size parameters
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 2035b8e8cc35..f6c0bd249372 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -2813,6 +2813,10 @@ QDF_STATUS wma_open(void *cds_context,
wma_get_apf_caps_event_handler,
WMA_RX_SERIALIZER_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
+ WMI_BPF_GET_VDEV_WORK_MEMORY_RESP_EVENTID,
+ wma_apf_read_work_memory_event_handler,
+ WMA_RX_SERIALIZER_CTX);
+ wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_CHAN_INFO_EVENTID,
wma_chan_info_event_handler,
WMA_RX_SERIALIZER_CTX);
@@ -2854,7 +2858,6 @@ QDF_STATUS wma_open(void *cds_context,
WMI_REPORT_RX_AGGR_FAILURE_EVENTID,
wma_rx_aggr_failure_event_handler,
WMA_RX_SERIALIZER_CTX);
-
wma_register_debug_callback();
wma_handle->peer_dbg = qdf_mem_malloc(sizeof(*wma_handle->peer_dbg));
diff --git a/uapi/linux/qca_vendor.h b/uapi/linux/qca_vendor.h
index 2bca01642a9d..83f7419388f4 100644
--- a/uapi/linux/qca_vendor.h
+++ b/uapi/linux/qca_vendor.h
@@ -3613,10 +3613,18 @@ enum qca_set_band {
* enum set_reset_packet_filter - set packet filter control commands
* @QCA_WLAN_SET_PACKET_FILTER: Set Packet Filter
* @QCA_WLAN_GET_PACKET_FILTER: Get Packet filter
+ * @QCA_WLAN_WRITE_PACKET_FILTER: Write packet filter program/data
+ * @QCA_WLAN_READ_PACKET_FILTER: Read packet filter program/data
+ * @QCA_WLAN_ENABLE_PACKET_FILTER: Enable APF interpreter
+ * @QCA_WLAN_DISABLE_PACKET_FILTER: Disable APF interpreter
*/
enum set_reset_packet_filter {
QCA_WLAN_SET_PACKET_FILTER = 1,
QCA_WLAN_GET_PACKET_FILTER = 2,
+ QCA_WLAN_WRITE_PACKET_FILTER = 3,
+ QCA_WLAN_READ_PACKET_FILTER = 4,
+ QCA_WLAN_ENABLE_PACKET_FILTER = 5,
+ QCA_WLAN_DISABLE_PACKET_FILTER = 6,
};
/**
@@ -3627,6 +3635,8 @@ enum set_reset_packet_filter {
* @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE: Total Length
* @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET: Current offset
* @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM: length of APF instructions
+ * @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH: length of the program
+ * section in packet filter buffer
*/
enum qca_wlan_vendor_attr_packet_filter {
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID = 0,
@@ -3636,6 +3646,7 @@ enum qca_wlan_vendor_attr_packet_filter {
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH,
/* keep last */
QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST,