Files
android_kernel_samsung_sm86…/wmi/src/wmi_unified_pmo_tlv.c
sheenam monga 0c6cd801dc qcacmn: Fix OOB in send_gtk_offload_cmd_tlv
In current design, Host driver copies kck and kek from pmo_gtk_req
to kck and kek of WMI_GTK_OFFLOAD_CMD_fixed_param. Host tries
to copy PMO_KCK_LEN i.e 32 bytes to an array of length 16 bytes
which can lead to OOB.

Fix is to copy only 16 bytes of kck and kek. Copy the bytes
from pmo_gtk_req same as the size of cmd->kck and cmd->kek i.e
destination array size to avoid OOB.

Change-Id: I999add18e18bedc9cfa1a0cfa5c0dad781e8e13f
CRs-Fixed: 2470368
2019-06-25 13:06:48 -07:00

1955 lines
58 KiB
C

/*
* Copyright (c) 2018-2019 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.
*/
#include <osdep.h>
#include "wmi.h"
#include "wmi_unified_priv.h"
#include "wmi_unified_pmo_api.h"
#ifdef FEATURE_WLAN_D0WOW
/**
* send_d0wow_enable_cmd_tlv() - WMI d0 wow enable function
* @param wmi_handle: handle to WMI.
* @mac_id: radio context
*
* Return: 0 on success and error code on failure.
*/
static QDF_STATUS send_d0wow_enable_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t mac_id)
{
wmi_d0_wow_enable_disable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
QDF_STATUS status;
len = sizeof(wmi_d0_wow_enable_disable_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_d0_wow_enable_disable_cmd_fixed_param));
cmd->enable = true;
wmi_mtrace(WMI_D0_WOW_ENABLE_DISABLE_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_D0_WOW_ENABLE_DISABLE_CMDID);
if (QDF_IS_STATUS_ERROR(status))
wmi_buf_free(buf);
return status;
}
/**
* send_d0wow_disable_cmd_tlv() - WMI d0 wow disable function
* @param wmi_handle: handle to WMI.
* @mac_id: radio context
*
* Return: 0 on success and error code on failure.
*/
static QDF_STATUS send_d0wow_disable_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t mac_id)
{
wmi_d0_wow_enable_disable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
QDF_STATUS status;
len = sizeof(wmi_d0_wow_enable_disable_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_d0_wow_enable_disable_cmd_fixed_param));
cmd->enable = false;
wmi_mtrace(WMI_D0_WOW_ENABLE_DISABLE_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_D0_WOW_ENABLE_DISABLE_CMDID);
if (QDF_IS_STATUS_ERROR(status))
wmi_buf_free(buf);
return status;
}
void wmi_d0wow_attach_tlv(struct wmi_unified *wmi_handle)
{
struct wmi_ops *ops = wmi_handle->ops;
ops->send_d0wow_enable_cmd = send_d0wow_enable_cmd_tlv;
ops->send_d0wow_disable_cmd = send_d0wow_disable_cmd_tlv;
}
#endif /* FEATURE_WLAN_D0WOW */
/**
* send_add_wow_wakeup_event_cmd_tlv() - Configures wow wakeup events.
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @bitmap: Event bitmap
* @enable: enable/disable
*
* Return: CDF status
*/
static QDF_STATUS send_add_wow_wakeup_event_cmd_tlv(wmi_unified_t wmi_handle,
uint32_t vdev_id,
uint32_t *bitmap,
bool enable)
{
WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *cmd;
uint16_t len;
wmi_buf_t buf;
int ret;
len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->is_add = enable;
qdf_mem_copy(&(cmd->event_bitmaps[0]), bitmap, sizeof(uint32_t) *
WMI_WOW_MAX_EVENT_BM_LEN);
WMI_LOGD("Wakeup pattern 0x%x%x%x%x %s in fw", cmd->event_bitmaps[0],
cmd->event_bitmaps[1], cmd->event_bitmaps[2],
cmd->event_bitmaps[3], enable ? "enabled" : "disabled");
wmi_mtrace(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID);
if (ret) {
WMI_LOGE("Failed to config wow wakeup event");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* send_wow_patterns_to_fw_cmd_tlv() - Sends WOW patterns to FW.
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @ptrn_id: pattern id
* @ptrn: pattern
* @ptrn_len: pattern length
* @ptrn_offset: pattern offset
* @mask: mask
* @mask_len: mask length
* @user: true for user configured pattern and false for default pattern
* @default_patterns: default patterns
*
* Return: CDF status
*/
static QDF_STATUS send_wow_patterns_to_fw_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t vdev_id, uint8_t ptrn_id,
const uint8_t *ptrn, uint8_t ptrn_len,
uint8_t ptrn_offset, const uint8_t *mask,
uint8_t mask_len, bool user,
uint8_t default_patterns)
{
WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
WOW_BITMAP_PATTERN_T *bitmap_pattern;
wmi_buf_t buf;
uint8_t *buf_ptr;
int32_t len;
int ret;
len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
WMI_TLV_HDR_SIZE +
1 * sizeof(WOW_BITMAP_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
WMI_TLV_HDR_SIZE +
0 * sizeof(uint32_t) + WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_WOW_ADD_PATTERN_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->pattern_id = ptrn_id;
cmd->pattern_type = WOW_BITMAP_PATTERN;
buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(WOW_BITMAP_PATTERN_T));
buf_ptr += WMI_TLV_HDR_SIZE;
bitmap_pattern = (WOW_BITMAP_PATTERN_T *) buf_ptr;
WMITLV_SET_HDR(&bitmap_pattern->tlv_header,
WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T,
WMITLV_GET_STRUCT_TLVLEN(WOW_BITMAP_PATTERN_T));
qdf_mem_copy(&bitmap_pattern->patternbuf[0], ptrn, ptrn_len);
qdf_mem_copy(&bitmap_pattern->bitmaskbuf[0], mask, mask_len);
bitmap_pattern->pattern_offset = ptrn_offset;
bitmap_pattern->pattern_len = ptrn_len;
if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMAP_PATTERN_SIZE)
bitmap_pattern->pattern_len = WOW_DEFAULT_BITMAP_PATTERN_SIZE;
if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMASK_SIZE)
bitmap_pattern->pattern_len = WOW_DEFAULT_BITMASK_SIZE;
bitmap_pattern->bitmask_len = bitmap_pattern->pattern_len;
bitmap_pattern->pattern_id = ptrn_id;
WMI_LOGD("vdev: %d, ptrn id: %d, ptrn len: %d, ptrn offset: %d user %d",
cmd->vdev_id, cmd->pattern_id, bitmap_pattern->pattern_len,
bitmap_pattern->pattern_offset, user);
WMI_LOGD("Pattern : ");
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
&bitmap_pattern->patternbuf[0],
bitmap_pattern->pattern_len);
WMI_LOGD("Mask : ");
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
&bitmap_pattern->bitmaskbuf[0],
bitmap_pattern->pattern_len);
buf_ptr += sizeof(WOW_BITMAP_PATTERN_T);
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for pattern_info_timeout but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for ratelimit_interval with dummy data as this fix elem */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1 * sizeof(uint32_t));
buf_ptr += WMI_TLV_HDR_SIZE;
*(uint32_t *) buf_ptr = 0;
wmi_mtrace(WMI_WOW_ADD_WAKE_PATTERN_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_WOW_ADD_WAKE_PATTERN_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to send wow ptrn to fw", __func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* fill_arp_offload_params_tlv() - Fill ARP offload data
* @wmi_handle: wmi handle
* @offload_req: offload request
* @buf_ptr: buffer pointer
*
* To fill ARP offload data to firmware
* when target goes to wow mode.
*
* Return: None
*/
static void fill_arp_offload_params_tlv(wmi_unified_t wmi_handle,
struct pmo_arp_offload_params *offload_req, uint8_t **buf_ptr)
{
int i;
WMI_ARP_OFFLOAD_TUPLE *arp_tuple;
bool enable_or_disable = offload_req->enable;
WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE)));
*buf_ptr += WMI_TLV_HDR_SIZE;
for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) {
arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *)*buf_ptr;
WMITLV_SET_HDR(&arp_tuple->tlv_header,
WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE,
WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE));
/* Fill data for ARP and NS in the first tupple for LA */
if ((enable_or_disable & PMO_OFFLOAD_ENABLE) && (i == 0)) {
/* Copy the target ip addr and flags */
arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID;
qdf_mem_copy(&arp_tuple->target_ipaddr,
offload_req->host_ipv4_addr,
WMI_IPV4_ADDR_LEN);
WMI_LOGD("ARPOffload IP4 address: %pI4",
offload_req->host_ipv4_addr);
}
*buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE);
}
}
#ifdef WLAN_NS_OFFLOAD
/**
* fill_ns_offload_params_tlv() - Fill NS offload data
* @wmi|_handle: wmi handle
* @offload_req: offload request
* @buf_ptr: buffer pointer
*
* To fill NS offload data to firmware
* when target goes to wow mode.
*
* Return: None
*/
static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle,
struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr)
{
int i;
WMI_NS_OFFLOAD_TUPLE *ns_tuple;
WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE)));
*buf_ptr += WMI_TLV_HDR_SIZE;
for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) {
ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr;
WMITLV_SET_HDR(&ns_tuple->tlv_header,
WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE,
(sizeof(WMI_NS_OFFLOAD_TUPLE) - WMI_TLV_HDR_SIZE));
/*
* Fill data only for NS offload in the first ARP tuple for LA
*/
if ((ns_req->enable & PMO_OFFLOAD_ENABLE)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID;
/* Copy the target/solicitation/remote ip addr */
if (ns_req->target_ipv6_addr_valid[i])
qdf_mem_copy(&ns_tuple->target_ipaddr[0],
&ns_req->target_ipv6_addr[i],
sizeof(WMI_IPV6_ADDR));
qdf_mem_copy(&ns_tuple->solicitation_ipaddr,
&ns_req->self_ipv6_addr[i],
sizeof(WMI_IPV6_ADDR));
if (ns_req->target_ipv6_addr_ac_type[i]) {
ns_tuple->flags |=
WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST;
}
WMI_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6",
i, &ns_req->self_ipv6_addr[i],
&ns_req->target_ipv6_addr[i]);
/* target MAC is optional, check if it is valid,
* if this is not valid, the target will use the known
* local MAC address rather than the tuple
*/
WMI_CHAR_ARRAY_TO_MAC_ADDR(
ns_req->self_macaddr.bytes,
&ns_tuple->target_mac);
if ((ns_tuple->target_mac.mac_addr31to0 != 0) ||
(ns_tuple->target_mac.mac_addr47to32 != 0)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID;
}
}
*buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE);
}
}
/**
* fill_nsoffload_ext_tlv() - Fill NS offload ext data
* @wmi: wmi handle
* @offload_req: offload request
* @buf_ptr: buffer pointer
*
* To fill extended NS offload extended data to firmware
* when target goes to wow mode.
*
* Return: None
*/
static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle,
struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr)
{
int i;
WMI_NS_OFFLOAD_TUPLE *ns_tuple;
uint32_t count, num_ns_ext_tuples;
count = ns_req->num_ns_offload_count;
num_ns_ext_tuples = ns_req->num_ns_offload_count -
WMI_MAX_NS_OFFLOADS;
/* Populate extended NS offload tuples */
WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(num_ns_ext_tuples * sizeof(WMI_NS_OFFLOAD_TUPLE)));
*buf_ptr += WMI_TLV_HDR_SIZE;
for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) {
ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr;
WMITLV_SET_HDR(&ns_tuple->tlv_header,
WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE,
(sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE));
/*
* Fill data only for NS offload in the first ARP tuple for LA
*/
if ((ns_req->enable & PMO_OFFLOAD_ENABLE)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID;
/* Copy the target/solicitation/remote ip addr */
if (ns_req->target_ipv6_addr_valid[i])
qdf_mem_copy(&ns_tuple->target_ipaddr[0],
&ns_req->target_ipv6_addr[i],
sizeof(WMI_IPV6_ADDR));
qdf_mem_copy(&ns_tuple->solicitation_ipaddr,
&ns_req->self_ipv6_addr[i],
sizeof(WMI_IPV6_ADDR));
if (ns_req->target_ipv6_addr_ac_type[i]) {
ns_tuple->flags |=
WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST;
}
WMI_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6",
i, &ns_req->self_ipv6_addr[i],
&ns_req->target_ipv6_addr[i]);
/* target MAC is optional, check if it is valid,
* if this is not valid, the target will use the
* known local MAC address rather than the tuple
*/
WMI_CHAR_ARRAY_TO_MAC_ADDR(
ns_req->self_macaddr.bytes,
&ns_tuple->target_mac);
if ((ns_tuple->target_mac.mac_addr31to0 != 0) ||
(ns_tuple->target_mac.mac_addr47to32 != 0)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID;
}
}
*buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE);
}
}
#else
static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle,
struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr)
{
}
static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle,
struct pmo_ns_offload_params *ns_req, uint8_t **buf_ptr)
{
}
#endif
/**
* send_enable_arp_ns_offload_cmd_tlv() - enable ARP NS offload
* @wma: wmi handle
* @arp_offload_req: arp offload request
* @ns_offload_req: ns offload request
* @arp_only: flag
*
* To configure ARP NS off load data to firmware
* when target goes to wow mode.
*
* Return: QDF Status
*/
static QDF_STATUS send_enable_arp_ns_offload_cmd_tlv(wmi_unified_t wmi_handle,
struct pmo_arp_offload_params *arp_offload_req,
struct pmo_ns_offload_params *ns_offload_req,
uint8_t vdev_id)
{
int32_t res;
WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd;
uint8_t *buf_ptr;
wmi_buf_t buf;
int32_t len;
uint32_t count = 0, num_ns_ext_tuples = 0;
count = ns_offload_req->num_ns_offload_count;
/*
* TLV place holder size for array of NS tuples
* TLV place holder size for array of ARP tuples
*/
len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) +
WMI_TLV_HDR_SIZE +
WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE) +
WMI_TLV_HDR_SIZE +
WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE);
/*
* If there are more than WMI_MAX_NS_OFFLOADS addresses then allocate
* extra length for extended NS offload tuples which follows ARP offload
* tuples. Host needs to fill this structure in following format:
* 2 NS ofload tuples
* 2 ARP offload tuples
* N numbers of extended NS offload tuples if HDD has given more than
* 2 NS offload addresses
*/
if (count > WMI_MAX_NS_OFFLOADS) {
num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS;
len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples
* sizeof(WMI_NS_OFFLOAD_TUPLE);
}
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param));
cmd->flags = 0;
cmd->vdev_id = vdev_id;
cmd->num_ns_ext_tuples = num_ns_ext_tuples;
WMI_LOGD("ARP NS Offload vdev_id: %d", cmd->vdev_id);
buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param);
fill_ns_offload_params_tlv(wmi_handle, ns_offload_req, &buf_ptr);
fill_arp_offload_params_tlv(wmi_handle, arp_offload_req, &buf_ptr);
if (num_ns_ext_tuples)
fill_nsoffload_ext_tlv(wmi_handle, ns_offload_req, &buf_ptr);
wmi_mtrace(WMI_SET_ARP_NS_OFFLOAD_CMDID, cmd->vdev_id, 0);
res = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_SET_ARP_NS_OFFLOAD_CMDID);
if (res) {
WMI_LOGE("Failed to enable ARP NDP/NSffload");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* send_add_clear_mcbc_filter_cmd_tlv() - set mcast filter command to fw
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @multicastAddr: mcast address
* @clearList: clear list flag
*
* Return: QDF_STATUS_SUCCESS for success or error code
*/
static QDF_STATUS send_add_clear_mcbc_filter_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t vdev_id,
struct qdf_mac_addr multicast_addr,
bool clearList)
{
WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd));
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf);
qdf_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param));
cmd->action =
(clearList ? WMI_MCAST_FILTER_DELETE : WMI_MCAST_FILTER_SET);
cmd->vdev_id = vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(multicast_addr.bytes, &cmd->mcastbdcastaddr);
WMI_LOGD("Action:%d; vdev_id:%d; clearList:%d; MCBC MAC Addr: %pM",
cmd->action, vdev_id, clearList, multicast_addr.bytes);
wmi_mtrace(WMI_SET_MCASTBCAST_FILTER_CMDID, cmd->vdev_id, 0);
err = wmi_unified_cmd_send(wmi_handle, buf,
sizeof(*cmd),
WMI_SET_MCASTBCAST_FILTER_CMDID);
if (err) {
WMI_LOGE("Failed to send set_param cmd");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* send_multiple_add_clear_mcbc_filter_cmd_tlv() - send multiple mcast filter
* command to fw
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @mcast_filter_params: mcast filter params
*
* Return: QDF_STATUS_SUCCESS for success or error code
*/
static QDF_STATUS send_multiple_add_clear_mcbc_filter_cmd_tlv(
wmi_unified_t wmi_handle,
uint8_t vdev_id,
struct pmo_mcast_filter_params *filter_param)
{
WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param *cmd;
uint8_t *buf_ptr;
wmi_buf_t buf;
int err;
int i;
uint8_t *mac_addr_src_ptr = NULL;
wmi_mac_addr *mac_addr_dst_ptr;
uint32_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
sizeof(wmi_mac_addr) * filter_param->multicast_addr_cnt;
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
cmd = (WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param *)
wmi_buf_data(buf);
qdf_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_set_multiple_mcast_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param));
cmd->operation =
((filter_param->action == 0) ? WMI_MULTIPLE_MCAST_FILTER_DELETE
: WMI_MULTIPLE_MCAST_FILTER_ADD);
cmd->vdev_id = vdev_id;
cmd->num_mcastaddrs = filter_param->multicast_addr_cnt;
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC,
sizeof(wmi_mac_addr) *
filter_param->multicast_addr_cnt);
if (filter_param->multicast_addr_cnt == 0)
goto send_cmd;
mac_addr_src_ptr = (uint8_t *)&filter_param->multicast_addr;
mac_addr_dst_ptr = (wmi_mac_addr *)
(buf_ptr + WMI_TLV_HDR_SIZE);
for (i = 0; i < filter_param->multicast_addr_cnt; i++) {
WMI_CHAR_ARRAY_TO_MAC_ADDR(mac_addr_src_ptr, mac_addr_dst_ptr);
mac_addr_src_ptr += ATH_MAC_LEN;
mac_addr_dst_ptr++;
}
send_cmd:
wmi_mtrace(WMI_SET_MULTIPLE_MCAST_FILTER_CMDID, cmd->vdev_id, 0);
err = wmi_unified_cmd_send(wmi_handle, buf,
len,
WMI_SET_MULTIPLE_MCAST_FILTER_CMDID);
if (err) {
WMI_LOGE("Failed to send set_param cmd");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS send_conf_hw_filter_cmd_tlv(wmi_unified_t wmi,
struct pmo_hw_filter_params *req)
{
QDF_STATUS status;
wmi_hw_data_filter_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
if (!req) {
WMI_LOGE("req is null");
return QDF_STATUS_E_INVAL;
}
wmi_buf = wmi_buf_alloc(wmi, sizeof(*cmd));
if (!wmi_buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_hw_data_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_hw_data_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_hw_data_filter_cmd_fixed_param));
cmd->vdev_id = req->vdev_id;
cmd->enable = req->enable;
/* Set all modes in case of disable */
if (!cmd->enable)
cmd->hw_filter_bitmap = ((uint32_t)~0U);
else
cmd->hw_filter_bitmap = req->mode_bitmap;
WMI_LOGD("Send %s hw filter mode: 0x%X for vdev id %d",
req->enable ? "enable" : "disable", req->mode_bitmap,
req->vdev_id);
wmi_mtrace(WMI_HW_DATA_FILTER_CMDID, cmd->vdev_id, 0);
status = wmi_unified_cmd_send(wmi, wmi_buf, sizeof(*cmd),
WMI_HW_DATA_FILTER_CMDID);
if (QDF_IS_STATUS_ERROR(status)) {
WMI_LOGE("Failed to configure hw filter");
wmi_buf_free(wmi_buf);
}
return status;
}
static void
fill_fils_tlv_params(WMI_GTK_OFFLOAD_CMD_fixed_param *cmd,
uint8_t vdev_id,
struct pmo_gtk_req *params)
{
uint8_t *buf_ptr;
wmi_gtk_offload_fils_tlv_param *ext_param;
buf_ptr = (uint8_t *) cmd + sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(*ext_param));
buf_ptr += WMI_TLV_HDR_SIZE;
ext_param = (wmi_gtk_offload_fils_tlv_param *)buf_ptr;
WMITLV_SET_HDR(&ext_param->tlv_header,
WMITLV_TAG_STRUC_wmi_gtk_offload_extended_tlv_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_gtk_offload_fils_tlv_param));
ext_param->vdev_id = vdev_id;
ext_param->flags = cmd->flags;
ext_param->kek_len = params->kek_len;
qdf_mem_copy(ext_param->KEK, params->kek, params->kek_len);
qdf_mem_copy(ext_param->KCK, params->kck,
WMI_GTK_OFFLOAD_KCK_BYTES);
qdf_mem_copy(ext_param->replay_counter, &params->replay_counter,
GTK_REPLAY_COUNTER_BYTES);
}
/**
* send_gtk_offload_cmd_tlv() - send GTK offload command to fw
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @params: GTK offload parameters
*
* Return: CDF status
*/
static
QDF_STATUS send_gtk_offload_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id,
struct pmo_gtk_req *params,
bool enable_offload,
uint32_t gtk_offload_opcode)
{
int len;
wmi_buf_t buf;
WMI_GTK_OFFLOAD_CMD_fixed_param *cmd;
QDF_STATUS status = QDF_STATUS_SUCCESS;
WMI_LOGD("%s Enter", __func__);
len = sizeof(*cmd);
if (params->is_fils_connection)
len += WMI_TLV_HDR_SIZE +
sizeof(wmi_gtk_offload_fils_tlv_param);
/* alloc wmi buffer */
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
status = QDF_STATUS_E_NOMEM;
goto out;
}
cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_GTK_OFFLOAD_CMD_fixed_param));
cmd->vdev_id = vdev_id;
/* Request target to enable GTK offload */
if (enable_offload == PMO_GTK_OFFLOAD_ENABLE) {
cmd->flags = gtk_offload_opcode;
/* Copy the keys and replay counter */
qdf_mem_copy(cmd->KCK, params->kck, sizeof(cmd->KCK));
qdf_mem_copy(cmd->KEK, params->kek, sizeof(cmd->KEK));
qdf_mem_copy(cmd->replay_counter, &params->replay_counter,
GTK_REPLAY_COUNTER_BYTES);
} else {
cmd->flags = gtk_offload_opcode;
}
if (params->is_fils_connection)
fill_fils_tlv_params(cmd, vdev_id, params);
WMI_LOGD("VDEVID: %d, GTK_FLAGS: x%x kek len %d", vdev_id, cmd->flags, params->kek_len);
/* send the wmi command */
wmi_mtrace(WMI_GTK_OFFLOAD_CMDID, cmd->vdev_id, 0);
if (wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_GTK_OFFLOAD_CMDID)) {
WMI_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID");
wmi_buf_free(buf);
status = QDF_STATUS_E_FAILURE;
}
out:
WMI_LOGD("%s Exit", __func__);
return status;
}
/**
* send_process_gtk_offload_getinfo_cmd_tlv() - send GTK offload cmd to fw
* @wmi_handle: wmi handle
* @params: GTK offload params
*
* Return: CDF status
*/
static QDF_STATUS send_process_gtk_offload_getinfo_cmd_tlv(
wmi_unified_t wmi_handle,
uint8_t vdev_id,
uint64_t offload_req_opcode)
{
int len;
wmi_buf_t buf;
WMI_GTK_OFFLOAD_CMD_fixed_param *cmd;
QDF_STATUS status = QDF_STATUS_SUCCESS;
len = sizeof(*cmd);
/* alloc wmi buffer */
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
status = QDF_STATUS_E_NOMEM;
goto out;
}
cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_GTK_OFFLOAD_CMD_fixed_param));
/* Request for GTK offload status */
cmd->flags = offload_req_opcode;
cmd->vdev_id = vdev_id;
/* send the wmi command */
wmi_mtrace(WMI_GTK_OFFLOAD_CMDID, cmd->vdev_id, 0);
if (wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_GTK_OFFLOAD_CMDID)) {
WMI_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID for req info");
wmi_buf_free(buf);
status = QDF_STATUS_E_FAILURE;
}
out:
return status;
}
/**
* send_enable_enhance_multicast_offload_tlv() - send enhance multicast offload
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @action: true for enable else false
*
* To enable enhance multicast offload to firmware
* when target goes to wow mode.
*
* Return: QDF Status
*/
static
QDF_STATUS send_enable_enhance_multicast_offload_tlv(
wmi_unified_t wmi_handle,
uint8_t vdev_id, bool action)
{
QDF_STATUS status;
wmi_buf_t buf;
wmi_config_enhanced_mcast_filter_cmd_fixed_param *cmd;
buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd));
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_config_enhanced_mcast_filter_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_config_enhanced_mcast_filter_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_config_enhanced_mcast_filter_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->enable = ((action == 0) ? ENHANCED_MCAST_FILTER_DISABLED :
ENHANCED_MCAST_FILTER_ENABLED);
WMI_LOGD("%s: config enhance multicast offload action %d for vdev %d",
__func__, action, vdev_id);
wmi_mtrace(WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID, cmd->vdev_id, 0);
status = wmi_unified_cmd_send(wmi_handle, buf,
sizeof(*cmd), WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID);
if (status != QDF_STATUS_SUCCESS) {
wmi_buf_free(buf);
WMI_LOGE("%s:Failed to send ENHANCED_MCAST_FILTER_CMDID",
__func__);
}
return status;
}
/**
* extract_gtk_rsp_event_tlv() - extract gtk rsp params from event
* @wmi_handle: wmi handle
* @param evt_buf: pointer to event buffer
* @param hdr: Pointer to hold header
* @param bufp: Pointer to hold pointer to rx param buffer
*
* Return: QDF_STATUS_SUCCESS for success or error code
*/
static QDF_STATUS extract_gtk_rsp_event_tlv(wmi_unified_t wmi_handle,
void *evt_buf, struct pmo_gtk_rsp_params *gtk_rsp_param, uint32_t len)
{
WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *fixed_param;
WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *param_buf;
param_buf = (WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *)evt_buf;
if (!param_buf) {
WMI_LOGE("gtk param_buf is NULL");
return QDF_STATUS_E_INVAL;
}
if (len < sizeof(WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param)) {
WMI_LOGE("Invalid length for GTK status");
return QDF_STATUS_E_INVAL;
}
fixed_param = (WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *)
param_buf->fixed_param;
if (fixed_param->vdev_id >= WLAN_UMAC_PSOC_MAX_VDEVS) {
wmi_err_rl("Invalid vdev_id %u", fixed_param->vdev_id);
return QDF_STATUS_E_INVAL;
}
gtk_rsp_param->vdev_id = fixed_param->vdev_id;
gtk_rsp_param->status_flag = QDF_STATUS_SUCCESS;
gtk_rsp_param->refresh_cnt = fixed_param->refresh_cnt;
qdf_mem_copy(&gtk_rsp_param->replay_counter,
&fixed_param->replay_counter,
GTK_REPLAY_COUNTER_BYTES);
return QDF_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_RA_FILTERING
/**
* send_wow_sta_ra_filter_cmd_tlv() - set RA filter pattern in fw
* @wmi_handle: wmi handle
* @vdev_id: vdev id
*
* Return: CDF status
*/
static QDF_STATUS send_wow_sta_ra_filter_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t vdev_id,
uint8_t default_pattern,
uint16_t rate_limit_interval)
{
WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
wmi_buf_t buf;
uint8_t *buf_ptr;
int32_t len;
int ret;
len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_BITMAP_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
WMI_TLV_HDR_SIZE +
0 * sizeof(uint32_t) + WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_WOW_ADD_PATTERN_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->pattern_id = default_pattern,
cmd->pattern_type = WOW_IPV6_RA_PATTERN;
buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
/* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for pattern_info_timeout but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for ra_ratelimit_interval. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(uint32_t));
buf_ptr += WMI_TLV_HDR_SIZE;
*((uint32_t *) buf_ptr) = rate_limit_interval;
WMI_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__,
rate_limit_interval, vdev_id);
wmi_mtrace(WMI_WOW_ADD_WAKE_PATTERN_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_WOW_ADD_WAKE_PATTERN_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to send RA rate limit to fw", __func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
void wmi_ra_filtering_attach_tlv(struct wmi_unified *wmi_handle)
{
struct wmi_ops *ops = wmi_handle->ops;
ops->send_wow_sta_ra_filter_cmd = send_wow_sta_ra_filter_cmd_tlv;
}
#endif /* FEATURE_WLAN_RA_FILTERING */
/**
* send_action_frame_patterns_cmd_tlv() - send wmi cmd of action filter params
* @wmi_handle: wmi handler
* @action_params: pointer to action_params
*
* Return: 0 for success, otherwise appropriate error code
*/
static QDF_STATUS send_action_frame_patterns_cmd_tlv(wmi_unified_t wmi_handle,
struct pmo_action_wakeup_set_params *action_params)
{
WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *cmd;
wmi_buf_t buf;
int i;
int32_t err;
uint32_t len = 0, *cmd_args;
uint8_t *buf_ptr;
len = (PMO_SUPPORTED_ACTION_CATE * sizeof(uint32_t))
+ WMI_TLV_HDR_SIZE + sizeof(*cmd);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *)cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param));
cmd->vdev_id = action_params->vdev_id;
cmd->operation = action_params->operation;
for (i = 0; i < MAX_SUPPORTED_ACTION_CATEGORY_ELE_LIST; i++)
cmd->action_category_map[i] =
action_params->action_category_map[i];
buf_ptr += sizeof(WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(PMO_SUPPORTED_ACTION_CATE * sizeof(uint32_t)));
buf_ptr += WMI_TLV_HDR_SIZE;
cmd_args = (uint32_t *) buf_ptr;
for (i = 0; i < PMO_SUPPORTED_ACTION_CATE; i++)
cmd_args[i] = action_params->action_per_category[i];
wmi_mtrace(WMI_WOW_SET_ACTION_WAKE_UP_CMDID, cmd->vdev_id, 0);
err = wmi_unified_cmd_send(wmi_handle, buf,
len, WMI_WOW_SET_ACTION_WAKE_UP_CMDID);
if (err) {
WMI_LOGE("Failed to send ap_ps_egap cmd");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_LPHB
/**
* send_lphb_config_hbenable_cmd_tlv() - enable command of LPHB configuration
* @wmi_handle: wmi handle
* @lphb_conf_req: configuration info
*
* Return: CDF status
*/
static QDF_STATUS send_lphb_config_hbenable_cmd_tlv(wmi_unified_t wmi_handle,
wmi_hb_set_enable_cmd_fixed_param *params)
{
QDF_STATUS status;
wmi_buf_t buf = NULL;
uint8_t *buf_ptr;
wmi_hb_set_enable_cmd_fixed_param *hb_enable_fp;
int len = sizeof(wmi_hb_set_enable_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
hb_enable_fp = (wmi_hb_set_enable_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_enable_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_hb_set_enable_cmd_fixed_param));
/* fill in values */
hb_enable_fp->vdev_id = params->session;
hb_enable_fp->enable = params->enable;
hb_enable_fp->item = params->item;
hb_enable_fp->session = params->session;
wmi_mtrace(WMI_HB_SET_ENABLE_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf,
len, WMI_HB_SET_ENABLE_CMDID);
if (QDF_IS_STATUS_ERROR(status)) {
WMI_LOGE("cmd_send WMI_HB_SET_ENABLE returned Error %d",
status);
wmi_buf_free(buf);
}
return status;
}
/**
* send_lphb_config_tcp_params_cmd_tlv() - set tcp params of LPHB configuration
* @wmi_handle: wmi handle
* @lphb_conf_req: lphb config request
*
* Return: CDF status
*/
static QDF_STATUS send_lphb_config_tcp_params_cmd_tlv(wmi_unified_t wmi_handle,
wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req)
{
QDF_STATUS status;
wmi_buf_t buf = NULL;
uint8_t *buf_ptr;
wmi_hb_set_tcp_params_cmd_fixed_param *hb_tcp_params_fp;
int len = sizeof(wmi_hb_set_tcp_params_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
hb_tcp_params_fp = (wmi_hb_set_tcp_params_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_tcp_params_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_hb_set_tcp_params_cmd_fixed_param));
/* fill in values */
hb_tcp_params_fp->vdev_id = lphb_conf_req->vdev_id;
hb_tcp_params_fp->srv_ip = lphb_conf_req->srv_ip;
hb_tcp_params_fp->dev_ip = lphb_conf_req->dev_ip;
hb_tcp_params_fp->seq = lphb_conf_req->seq;
hb_tcp_params_fp->src_port = lphb_conf_req->src_port;
hb_tcp_params_fp->dst_port = lphb_conf_req->dst_port;
hb_tcp_params_fp->interval = lphb_conf_req->interval;
hb_tcp_params_fp->timeout = lphb_conf_req->timeout;
hb_tcp_params_fp->session = lphb_conf_req->session;
qdf_mem_copy(&hb_tcp_params_fp->gateway_mac,
&lphb_conf_req->gateway_mac,
sizeof(hb_tcp_params_fp->gateway_mac));
wmi_mtrace(WMI_HB_SET_TCP_PARAMS_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf,
len, WMI_HB_SET_TCP_PARAMS_CMDID);
if (QDF_IS_STATUS_ERROR(status)) {
WMI_LOGE("cmd_send WMI_HB_SET_TCP_PARAMS returned Error %d",
status);
wmi_buf_free(buf);
}
return status;
}
/**
* send_lphb_config_tcp_pkt_filter_cmd_tlv() - configure tcp packet filter cmd
* @wmi_handle: wmi handle
* @lphb_conf_req: lphb config request
*
* Return: CDF status
*/
static
QDF_STATUS send_lphb_config_tcp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle,
wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp)
{
QDF_STATUS status;
wmi_buf_t buf = NULL;
uint8_t *buf_ptr;
wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *hb_tcp_filter_fp;
int len = sizeof(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
hb_tcp_filter_fp =
(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_tcp_filter_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param));
/* fill in values */
hb_tcp_filter_fp->vdev_id = g_hb_tcp_filter_fp->vdev_id;
hb_tcp_filter_fp->length = g_hb_tcp_filter_fp->length;
hb_tcp_filter_fp->offset = g_hb_tcp_filter_fp->offset;
hb_tcp_filter_fp->session = g_hb_tcp_filter_fp->session;
memcpy((void *)&hb_tcp_filter_fp->filter,
(void *)&g_hb_tcp_filter_fp->filter,
WMI_WLAN_HB_MAX_FILTER_SIZE);
wmi_mtrace(WMI_HB_SET_TCP_PKT_FILTER_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf,
len, WMI_HB_SET_TCP_PKT_FILTER_CMDID);
if (QDF_IS_STATUS_ERROR(status)) {
WMI_LOGE("cmd_send WMI_HB_SET_TCP_PKT_FILTER returned Error %d",
status);
wmi_buf_free(buf);
}
return status;
}
/**
* send_lphb_config_udp_params_cmd_tlv() - configure udp param command of LPHB
* @wmi_handle: wmi handle
* @lphb_conf_req: lphb config request
*
* Return: CDF status
*/
static QDF_STATUS send_lphb_config_udp_params_cmd_tlv(wmi_unified_t wmi_handle,
wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req)
{
QDF_STATUS status;
wmi_buf_t buf = NULL;
uint8_t *buf_ptr;
wmi_hb_set_udp_params_cmd_fixed_param *hb_udp_params_fp;
int len = sizeof(wmi_hb_set_udp_params_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
hb_udp_params_fp = (wmi_hb_set_udp_params_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_udp_params_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_hb_set_udp_params_cmd_fixed_param));
/* fill in values */
hb_udp_params_fp->vdev_id = lphb_conf_req->vdev_id;
hb_udp_params_fp->srv_ip = lphb_conf_req->srv_ip;
hb_udp_params_fp->dev_ip = lphb_conf_req->dev_ip;
hb_udp_params_fp->src_port = lphb_conf_req->src_port;
hb_udp_params_fp->dst_port = lphb_conf_req->dst_port;
hb_udp_params_fp->interval = lphb_conf_req->interval;
hb_udp_params_fp->timeout = lphb_conf_req->timeout;
hb_udp_params_fp->session = lphb_conf_req->session;
qdf_mem_copy(&hb_udp_params_fp->gateway_mac,
&lphb_conf_req->gateway_mac,
sizeof(lphb_conf_req->gateway_mac));
wmi_mtrace(WMI_HB_SET_UDP_PARAMS_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf,
len, WMI_HB_SET_UDP_PARAMS_CMDID);
if (QDF_IS_STATUS_ERROR(status)) {
WMI_LOGE("cmd_send WMI_HB_SET_UDP_PARAMS returned Error %d",
status);
wmi_buf_free(buf);
}
return status;
}
/**
* send_lphb_config_udp_pkt_filter_cmd_tlv() - configure udp pkt filter command
* @wmi_handle: wmi handle
* @lphb_conf_req: lphb config request
*
* Return: CDF status
*/
static
QDF_STATUS send_lphb_config_udp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle,
wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req)
{
QDF_STATUS status;
wmi_buf_t buf = NULL;
uint8_t *buf_ptr;
wmi_hb_set_udp_pkt_filter_cmd_fixed_param *hb_udp_filter_fp;
int len = sizeof(wmi_hb_set_udp_pkt_filter_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *) wmi_buf_data(buf);
hb_udp_filter_fp =
(wmi_hb_set_udp_pkt_filter_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_udp_filter_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_hb_set_udp_pkt_filter_cmd_fixed_param));
/* fill in values */
hb_udp_filter_fp->vdev_id = lphb_conf_req->vdev_id;
hb_udp_filter_fp->length = lphb_conf_req->length;
hb_udp_filter_fp->offset = lphb_conf_req->offset;
hb_udp_filter_fp->session = lphb_conf_req->session;
memcpy((void *)&hb_udp_filter_fp->filter,
(void *)&lphb_conf_req->filter,
WMI_WLAN_HB_MAX_FILTER_SIZE);
wmi_mtrace(WMI_HB_SET_UDP_PKT_FILTER_CMDID, NO_SESSION, 0);
status = wmi_unified_cmd_send(wmi_handle, buf,
len, WMI_HB_SET_UDP_PKT_FILTER_CMDID);
if (QDF_IS_STATUS_ERROR(status)) {
WMI_LOGE("cmd_send WMI_HB_SET_UDP_PKT_FILTER returned Error %d",
status);
wmi_buf_free(buf);
}
return status;
}
void wmi_lphb_attach_tlv(struct wmi_unified *wmi_handle)
{
struct wmi_ops *ops = wmi_handle->ops;
ops->send_lphb_config_hbenable_cmd =
send_lphb_config_hbenable_cmd_tlv;
ops->send_lphb_config_tcp_params_cmd =
send_lphb_config_tcp_params_cmd_tlv;
ops->send_lphb_config_tcp_pkt_filter_cmd =
send_lphb_config_tcp_pkt_filter_cmd_tlv;
ops->send_lphb_config_udp_params_cmd =
send_lphb_config_udp_params_cmd_tlv;
ops->send_lphb_config_udp_pkt_filter_cmd =
send_lphb_config_udp_pkt_filter_cmd_tlv;
}
#endif /* FEATURE_WLAN_LPHB */
#ifdef WLAN_FEATURE_PACKET_FILTERING
/**
* send_enable_disable_packet_filter_cmd_tlv() - enable/disable packet filter
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @enable: Flag to enable/disable packet filter
*
* Return: QDF_STATUS_SUCCESS for success or error code
*/
static QDF_STATUS send_enable_disable_packet_filter_cmd_tlv(
wmi_unified_t wmi_handle, uint8_t vdev_id, bool enable)
{
int32_t len;
int ret = 0;
wmi_buf_t buf;
WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *cmd;
len = sizeof(WMI_PACKET_FILTER_ENABLE_CMD_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_PACKET_FILTER_ENABLE_CMD_fixed_param));
cmd->vdev_id = vdev_id;
if (enable)
cmd->enable = PACKET_FILTER_SET_ENABLE;
else
cmd->enable = PACKET_FILTER_SET_DISABLE;
WMI_LOGE("%s: Packet filter enable %d for vdev_id %d",
__func__, cmd->enable, vdev_id);
wmi_mtrace(WMI_PACKET_FILTER_ENABLE_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_PACKET_FILTER_ENABLE_CMDID);
if (ret) {
WMI_LOGE("Failed to send packet filter wmi cmd to fw");
wmi_buf_free(buf);
}
return ret;
}
/**
* send_config_packet_filter_cmd_tlv() - configure packet filter in target
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @rcv_filter_param: Packet filter parameters
* @filter_id: Filter id
* @enable: Flag to add/delete packet filter configuration
*
* Return: QDF_STATUS_SUCCESS for success or error code
*/
static QDF_STATUS send_config_packet_filter_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t vdev_id, struct pmo_rcv_pkt_fltr_cfg *rcv_filter_param,
uint8_t filter_id, bool enable)
{
int len, i;
int err = 0;
wmi_buf_t buf;
WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *cmd;
/* allocate the memory */
len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_PACKET_FILTER_CONFIG_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->filter_id = filter_id;
if (enable)
cmd->filter_action = PACKET_FILTER_SET_ACTIVE;
else
cmd->filter_action = PACKET_FILTER_SET_INACTIVE;
if (enable) {
cmd->num_params = QDF_MIN(
WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER,
rcv_filter_param->num_params);
cmd->filter_type = rcv_filter_param->filter_type;
cmd->coalesce_time = rcv_filter_param->coalesce_time;
for (i = 0; i < cmd->num_params; i++) {
cmd->paramsData[i].proto_type =
rcv_filter_param->params_data[i].protocol_layer;
cmd->paramsData[i].cmp_type =
rcv_filter_param->params_data[i].compare_flag;
cmd->paramsData[i].data_length =
rcv_filter_param->params_data[i].data_length;
cmd->paramsData[i].data_offset =
rcv_filter_param->params_data[i].data_offset;
memcpy(&cmd->paramsData[i].compareData,
rcv_filter_param->params_data[i].compare_data,
sizeof(cmd->paramsData[i].compareData));
memcpy(&cmd->paramsData[i].dataMask,
rcv_filter_param->params_data[i].data_mask,
sizeof(cmd->paramsData[i].dataMask));
}
}
WMI_LOGE("Packet filter action %d filter with id: %d, num_params=%d",
cmd->filter_action, cmd->filter_id, cmd->num_params);
/* send the command along with data */
wmi_mtrace(WMI_PACKET_FILTER_CONFIG_CMDID, cmd->vdev_id, 0);
err = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_PACKET_FILTER_CONFIG_CMDID);
if (err) {
WMI_LOGE("Failed to send pkt_filter cmd");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
void wmi_packet_filtering_attach_tlv(struct wmi_unified *wmi_handle)
{
struct wmi_ops *ops = wmi_handle->ops;
ops->send_enable_disable_packet_filter_cmd =
send_enable_disable_packet_filter_cmd_tlv;
ops->send_config_packet_filter_cmd =
send_config_packet_filter_cmd_tlv;
}
#endif /* WLAN_FEATURE_PACKET_FILTERING */
/**
* send_wow_delete_pattern_cmd_tlv() - delete wow pattern in target
* @wmi_handle: wmi handle
* @ptrn_id: pattern id
* @vdev_id: vdev id
*
* Return: CDF status
*/
static QDF_STATUS send_wow_delete_pattern_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t ptrn_id,
uint8_t vdev_id)
{
WMI_WOW_DEL_PATTERN_CMD_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(WMI_WOW_DEL_PATTERN_CMD_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_DEL_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_DEL_PATTERN_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->pattern_id = ptrn_id;
cmd->pattern_type = WOW_BITMAP_PATTERN;
wmi_mtrace(WMI_WOW_DEL_WAKE_PATTERN_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_WOW_DEL_WAKE_PATTERN_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to delete wow ptrn from fw", __func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* send_host_wakeup_ind_to_fw_cmd_tlv() - send wakeup ind to fw
* @wmi_handle: wmi handle
*
* Sends host wakeup indication to FW. On receiving this indication,
* FW will come out of WOW.
*
* Return: CDF status
*/
static QDF_STATUS send_host_wakeup_ind_to_fw_cmd_tlv(wmi_unified_t wmi_handle)
{
wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *cmd;
wmi_buf_t buf;
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
int32_t len;
int ret;
len = sizeof(wmi_wow_hostwakeup_from_sleep_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_wow_hostwakeup_from_sleep_cmd_fixed_param));
wmi_mtrace(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, NO_SESSION, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
if (ret) {
WMI_LOGE("Failed to send host wakeup indication to fw");
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return qdf_status;
}
/**
* send_wow_timer_pattern_cmd_tlv() - set timer pattern tlv, so that firmware
* will wake up host after specified time is elapsed
* @wmi_handle: wmi handle
* @vdev_id: vdev id
* @cookie: value to identify reason why host set up wake call.
* @time: time in ms
*
* Return: QDF status
*/
static QDF_STATUS send_wow_timer_pattern_cmd_tlv(wmi_unified_t wmi_handle,
uint8_t vdev_id, uint32_t cookie, uint32_t time)
{
WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
wmi_buf_t buf;
uint8_t *buf_ptr;
int32_t len;
int ret;
len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_BITMAP_PATTERN_T) +
WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE + 0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t) +
WMI_TLV_HDR_SIZE + 1 * sizeof(uint32_t);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(WMI_WOW_ADD_PATTERN_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->pattern_id = cookie,
cmd->pattern_type = WOW_TIMER_PATTERN;
buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
/* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for pattern_info_timeout, and time value */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(uint32_t));
buf_ptr += WMI_TLV_HDR_SIZE;
*((uint32_t *) buf_ptr) = time;
buf_ptr += sizeof(uint32_t);
/* Fill TLV for ra_ratelimit_interval. with dummy 0 value */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(uint32_t));
buf_ptr += WMI_TLV_HDR_SIZE;
*((uint32_t *) buf_ptr) = 0;
WMI_LOGD("%s: send wake timer pattern with time[%d] to fw vdev = %d",
__func__, time, vdev_id);
wmi_mtrace(WMI_WOW_ADD_WAKE_PATTERN_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_WOW_ADD_WAKE_PATTERN_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to send wake timer pattern to fw",
__func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
/**
* send_enable_ext_wow_cmd_tlv() - enable ext wow in fw
* @wmi_handle: wmi handle
* @params: ext wow params
*
* Return:0 for success or error code
*/
static QDF_STATUS send_enable_ext_wow_cmd_tlv(wmi_unified_t wmi_handle,
struct ext_wow_params *params)
{
wmi_extwow_enable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(wmi_extwow_enable_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_extwow_enable_cmd_fixed_param));
cmd->vdev_id = params->vdev_id;
cmd->type = params->type;
cmd->wakeup_pin_num = params->wakeup_pin_num;
WMI_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x",
__func__, cmd->vdev_id, cmd->type, cmd->wakeup_pin_num);
wmi_mtrace(WMI_EXTWOW_ENABLE_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_EXTWOW_ENABLE_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to set EXTWOW Enable", __func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* send_set_app_type2_params_in_fw_cmd_tlv() - set app type2 params in fw
* @wmi_handle: wmi handle
* @appType2Params: app type2 params
*
* Return: CDF status
*/
static QDF_STATUS send_set_app_type2_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle,
struct app_type2_params *appType2Params)
{
wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_extwow_set_app_type2_params_cmd_fixed_param));
cmd->vdev_id = appType2Params->vdev_id;
qdf_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16);
cmd->rc4_key_len = appType2Params->rc4_key_len;
cmd->ip_id = appType2Params->ip_id;
cmd->ip_device_ip = appType2Params->ip_device_ip;
cmd->ip_server_ip = appType2Params->ip_server_ip;
cmd->tcp_src_port = appType2Params->tcp_src_port;
cmd->tcp_dst_port = appType2Params->tcp_dst_port;
cmd->tcp_seq = appType2Params->tcp_seq;
cmd->tcp_ack_seq = appType2Params->tcp_ack_seq;
cmd->keepalive_init = appType2Params->keepalive_init;
cmd->keepalive_min = appType2Params->keepalive_min;
cmd->keepalive_max = appType2Params->keepalive_max;
cmd->keepalive_inc = appType2Params->keepalive_inc;
WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac.bytes,
&cmd->gateway_mac);
cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val;
cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val;
WMI_LOGD("%s: vdev_id %d gateway_mac %pM "
"rc4_key %.16s rc4_key_len %u "
"ip_id %x ip_device_ip %x ip_server_ip %x "
"tcp_src_port %u tcp_dst_port %u tcp_seq %u "
"tcp_ack_seq %u keepalive_init %u keepalive_min %u "
"keepalive_max %u keepalive_inc %u "
"tcp_tx_timeout_val %u tcp_rx_timeout_val %u",
__func__, cmd->vdev_id, appType2Params->gateway_mac.bytes,
cmd->rc4_key, cmd->rc4_key_len,
cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip,
cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq,
cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min,
cmd->keepalive_max, cmd->keepalive_inc,
cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val);
wmi_mtrace(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* send_app_type1_params_in_fw_cmd_tlv() - set app type1 params in fw
* @wmi_handle: wmi handle
* @app_type1_params: app type1 params
*
* Return: CDF status
*/
static QDF_STATUS send_app_type1_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle,
struct app_type1_params *app_type1_params)
{
wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
return QDF_STATUS_E_NOMEM;
}
cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_extwow_set_app_type1_params_cmd_fixed_param));
cmd->vdev_id = app_type1_params->vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(app_type1_params->wakee_mac_addr.bytes,
&cmd->wakee_mac);
qdf_mem_copy(cmd->ident, app_type1_params->identification_id, 8);
cmd->ident_len = app_type1_params->id_length;
qdf_mem_copy(cmd->passwd, app_type1_params->password, 16);
cmd->passwd_len = app_type1_params->pass_length;
WMI_LOGD("%s: vdev_id %d wakee_mac_addr %pM "
"identification_id %.8s id_length %u "
"password %.16s pass_length %u",
__func__, cmd->vdev_id, app_type1_params->wakee_mac_addr.bytes,
cmd->ident, cmd->ident_len, cmd->passwd, cmd->passwd_len);
wmi_mtrace(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, cmd->vdev_id, 0);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID);
if (ret) {
WMI_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__);
wmi_buf_free(buf);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
void wmi_extwow_attach_tlv(struct wmi_unified *wmi_handle)
{
struct wmi_ops *ops = wmi_handle->ops;
ops->send_enable_ext_wow_cmd = send_enable_ext_wow_cmd_tlv;
ops->send_set_app_type2_params_in_fw_cmd =
send_set_app_type2_params_in_fw_cmd_tlv;
ops->send_app_type1_params_in_fw_cmd =
send_app_type1_params_in_fw_cmd_tlv;
}
#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
void wmi_pmo_attach_tlv(wmi_unified_t wmi_handle)
{
struct wmi_ops *ops = wmi_handle->ops;
ops->send_add_wow_wakeup_event_cmd =
send_add_wow_wakeup_event_cmd_tlv;
ops->send_wow_patterns_to_fw_cmd = send_wow_patterns_to_fw_cmd_tlv;
ops->send_enable_arp_ns_offload_cmd =
send_enable_arp_ns_offload_cmd_tlv;
ops->send_add_clear_mcbc_filter_cmd =
send_add_clear_mcbc_filter_cmd_tlv;
ops->send_multiple_add_clear_mcbc_filter_cmd =
send_multiple_add_clear_mcbc_filter_cmd_tlv;
ops->send_conf_hw_filter_cmd = send_conf_hw_filter_cmd_tlv;
ops->send_gtk_offload_cmd = send_gtk_offload_cmd_tlv;
ops->send_process_gtk_offload_getinfo_cmd =
send_process_gtk_offload_getinfo_cmd_tlv;
ops->send_enable_enhance_multicast_offload_cmd =
send_enable_enhance_multicast_offload_tlv;
ops->extract_gtk_rsp_event = extract_gtk_rsp_event_tlv;
ops->send_action_frame_patterns_cmd =
send_action_frame_patterns_cmd_tlv;
ops->send_wow_delete_pattern_cmd = send_wow_delete_pattern_cmd_tlv;
ops->send_host_wakeup_ind_to_fw_cmd =
send_host_wakeup_ind_to_fw_cmd_tlv;
ops->send_wow_timer_pattern_cmd = send_wow_timer_pattern_cmd_tlv;
wmi_d0wow_attach_tlv(wmi_handle);
wmi_ra_filtering_attach_tlv(wmi_handle);
wmi_lphb_attach_tlv(wmi_handle);
wmi_packet_filtering_attach_tlv(wmi_handle);
wmi_extwow_attach_tlv(wmi_handle);
}