diff --git a/components/coap/dispatcher/inc/wlan_coap_public_structs.h b/components/coap/dispatcher/inc/wlan_coap_public_structs.h new file mode 100644 index 0000000000..55e6f55b5a --- /dev/null +++ b/components/coap/dispatcher/inc/wlan_coap_public_structs.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains CoAP structure definitions + */ + +#ifndef _WLAN_COAP_PUBLIC_STRUCTS_H_ +#define _WLAN_COAP_PUBLIC_STRUCTS_H_ +#include + +/** + * struct coap_offload_reply_param - parameters to enable CoAP offload reply + * @vdev_id: vdev id + * @pattern_id: pattern id + * @cache_timeout: the cached packet expire timeout in ms + * @src_ip_v4: source IPv4 address for sending reply message + * @src_udp_port: source udp port for sending reply message + * @dest_ip_v4: destination IPv4 address to match recived CoAP message + * @dest_ip_v4_is_bc: indicate whether the destination address is broadcast + * address or not + * @dest_udp_port: destination UDP port to match recived CoAP message + * @verify_offset: UDP payload offset to match recived CoAP message + * @verify_len: UDP payload length to match recived CoAP message + * @verify: pointer to binary data to match recived CoAP message + * @coapmsg_len: CoAP reply message length + * @coapmsg: pointer to CoAP reply message + */ +struct coap_offload_reply_param { + uint32_t vdev_id; + uint32_t pattern_id; + uint32_t cache_timeout; + uint32_t src_ip_v4; + uint16_t src_udp_port; + uint32_t dest_ip_v4; + bool dest_ip_v4_is_bc; + uint16_t dest_udp_port; + uint32_t verify_offset; + uint32_t verify_len; + uint8_t *verify; + uint32_t coapmsg_len; + uint8_t *coapmsg; +}; + +/** + * struct coap_offload_periodic_tx_param - parameters to enable CoAP offload + * periodic tranmitting + * @vdev_id: vdev id + * @pattern_id: pattern id + * @src_ip_v4: IPv4 address for sending CoAP message + * @src_udp_port: source udp port for sending CoAP message + * @dest_ip_v4: destination IPv4 address for sending CoAP message + * @dest_ip_v4_is_bc: indicate whether the destination address is broadcast + * address or not + * @dest_udp_port: destination UDP port for sending CoAP message + * @timeout: the periorid to send keepalive message in ms + * @coapmsg_len: keeplive CoAP message length + * @coapmsg: pointer to keeplive CoAP message + */ +struct coap_offload_periodic_tx_param { + uint32_t vdev_id; + uint32_t pattern_id; + uint32_t src_ip_v4; + uint16_t src_udp_port; + uint32_t dest_ip_v4; + bool dest_ip_v4_is_bc; + uint16_t dest_udp_port; + uint32_t timeout; + uint32_t coapmsg_len; + uint8_t *coapmsg; +}; + +/** + * struct coap_buf_node - CoAP message info entry + * @node: List entry element + * @tsf: TSF of the CoAP meesage + * @src_ip: source IPv4 address of the CoAP message + * @len: length of the payload + * @payload: pointer to buffer holding UDP payload of the CoAP message + */ +struct coap_buf_node { + qdf_list_node_t node; + uint64_t tsf; + uint32_t src_ip; + uint32_t len; + uint8_t *payload; +}; + +/** + * struct coap_buf_info - info of the cached CoAP messages + * @vdev_id: vdev id + * @req_id: request id + * @more_info: flag to indicate whether there are more cached messages + * @info_list: list to hold cached CoAP messages + */ +struct coap_buf_info { + uint8_t vdev_id; + uint32_t req_id; + bool more_info; + qdf_list_t info_list; +}; + +/** + * typedef coap_cache_get_callback() - callback for getting cached CoAP messages + * @context: context for getting cached CoAP messages + * @info: pointer to info of the cached CoAP messages + */ +typedef void (*coap_cache_get_callback)(void *context, + struct coap_buf_info *info); +#endif diff --git a/components/wmi/inc/wmi_unified_coap_api.h b/components/wmi/inc/wmi_unified_coap_api.h new file mode 100644 index 0000000000..2112efaa89 --- /dev/null +++ b/components/wmi/inc/wmi_unified_coap_api.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to CoAP component. + */ + +#ifndef _WMI_UNIFIED_COAP_API_H_ +#define _WMI_UNIFIED_COAP_API_H_ + +#include + +#ifdef WLAN_FEATURE_COAP +/** + * wmi_unified_coap_add_pattern_cmd() - Add pattern for CoAP offload reply + * @wmi_handle: wmi handle + * @param: parameters for CoAP offload reply + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_add_pattern_cmd(wmi_unified_t wmi_handle, + struct coap_offload_reply_param *param) +{ + if (wmi_handle->ops->send_coap_add_pattern_cmd) + return wmi_handle->ops->send_coap_add_pattern_cmd(wmi_handle, + param); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_del_pattern_cmd() - Delete pattern for CoAP offload reply + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_del_pattern_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + if (wmi_handle->ops->send_coap_del_pattern_cmd) + return wmi_handle->ops->send_coap_del_pattern_cmd(wmi_handle, + vdev_id, pattern_id); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_add_keepalive_pattern_cmd() - Add pattern for CoAP offload + * periodic transmitting + * @wmi_handle: wmi handle + * @param: parameters for CoAP offload periodic transmitting + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_add_keepalive_pattern_cmd(wmi_unified_t wmi_handle, + struct coap_offload_periodic_tx_param *param) +{ + if (wmi_handle->ops->send_coap_add_keepalive_pattern_cmd) + return wmi_handle->ops->send_coap_add_keepalive_pattern_cmd( + wmi_handle, param); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_del_pattern_cmd() - Delete pattern for CoAP offload + * periodic transmitting + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_del_keepalive_pattern_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint32_t pattern_id) +{ + if (wmi_handle->ops->send_coap_del_keepalive_pattern_cmd) + return wmi_handle->ops->send_coap_del_keepalive_pattern_cmd( + wmi_handle, vdev_id, pattern_id); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_del_pattern_cmd() - Get cached CoAP messages + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_cache_get(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + if (wmi_handle->ops->send_coap_cache_get_cmd) + return wmi_handle->ops->send_coap_cache_get_cmd(wmi_handle, + vdev_id, pattern_id); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_extract_buf_info() - extract CoAP buf info from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @info: Pointer to hold CoAP buf info + * + * The caller needs to free any possible nodes in info->info_list + * regardless of failure or success. + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_extract_buf_info(wmi_unified_t wmi_handle, void *evt_buf, + struct coap_buf_info *info) +{ + if (wmi_handle->ops->extract_coap_buf_info) { + return wmi_handle->ops->extract_coap_buf_info(wmi_handle, + evt_buf, + info); + } + + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif /* _WMI_UNIFIED_ROAM_API_H_ */ diff --git a/components/wmi/src/wmi_unified_coap_tlv.c b/components/wmi/src/wmi_unified_coap_tlv.c new file mode 100644 index 0000000000..1c21232dd1 --- /dev/null +++ b/components/wmi/src/wmi_unified_coap_tlv.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to CoAP component. + */ + +#include +#include "wmi.h" +#include "ol_defines.h" + +/* + * send_coap_add_pattern_cmd_tlv() - Send wmi cmd for adding CoAP pattern + * @wmi_handle: wmi handle + * @param: parameter for CoAP add pattern + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_add_pattern_cmd_tlv(wmi_unified_t wmi_handle, + struct coap_offload_reply_param *param) +{ + WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len, coapmsg_len_align, verify_len_align; + + wmi_debug("vdev id %d pattern id %d timeout %d src ip 0x%x:%d coap msg len %d", + param->vdev_id, param->pattern_id, param->cache_timeout, + param->src_ip_v4, param->src_udp_port, + param->coapmsg_len); + + wmi_debug("filter: dest ip 0x%x:%d is bc %d verify offset %d len %d", + param->dest_ip_v4, param->dest_udp_port, + param->dest_ip_v4_is_bc, param->verify_offset, + param->verify_len); + + if (!param->verify || !param->verify_len || + !param->coapmsg || !param->coapmsg_len) { + wmi_err("invalid param"); + return QDF_STATUS_E_INVAL; + } + + coapmsg_len_align = qdf_align(param->coapmsg_len, 4); + verify_len_align = qdf_align(param->verify_len, 4); + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + coapmsg_len_align + + WMI_TLV_HDR_SIZE + verify_len_align; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = wmi_buf_data(buf); + cmd = (WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = param->vdev_id; + cmd->pattern_id = param->pattern_id; + cmd->timeout = param->cache_timeout; + WMI_COAP_IPV6_SET(cmd->pattern_type, 0); + WMI_COAP_ADDR_TYPE_SET(cmd->pattern_type, + param->dest_ip_v4_is_bc ? 1 : 0); + qdf_mem_copy(cmd->match_udp_ip.ipv4_addr, ¶m->dest_ip_v4, + sizeof(param->dest_ip_v4)); + cmd->match_udp_port = param->dest_udp_port; + qdf_mem_copy(cmd->udp_local_ip.ipv4_addr, ¶m->src_ip_v4, + sizeof(param->src_ip_v4)); + cmd->udp_local_port = param->src_udp_port; + cmd->verify_offset = param->verify_offset; + cmd->verify_len = param->verify_len; + cmd->coapmsg_len = param->coapmsg_len; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, verify_len_align); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->verify, param->verify_len); + + buf_ptr += verify_len_align; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, coapmsg_len_align); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->coapmsg, param->coapmsg_len); + buf_ptr += coapmsg_len_align; + + wmi_mtrace(WMI_WOW_COAP_ADD_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_ADD_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap add pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_del_pattern_cmd_tlv() - Send wmi cmd for deleting CoAP pattern + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_del_pattern_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint32_t len = sizeof(*cmd); + + wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + wmi_mtrace(WMI_WOW_COAP_DEL_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_DEL_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap del pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_add_pattern_cmd_tlv() - Send wmi cmd for adding CoAP keepalive + * pattern + * @wmi_handle: wmi handle + * @param: parameter for CoAP add pattern + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_add_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle, + struct coap_offload_periodic_tx_param *param) +{ + WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len, coapmsg_len_align; + + wmi_debug("vdev id %d pattern id %d ip src 0x%x:%d dest 0x%x:%d bc %d timeout %d", + param->vdev_id, param->pattern_id, param->src_ip_v4, + param->src_udp_port, param->dest_ip_v4, + param->dest_udp_port, param->dest_ip_v4_is_bc, + param->timeout); + + if (!param->coapmsg || !param->coapmsg_len) { + wmi_err("invalid CoAP message"); + return QDF_STATUS_E_INVAL; + } + + coapmsg_len_align = qdf_align(param->coapmsg_len, 4); + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + coapmsg_len_align; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = wmi_buf_data(buf); + cmd = (WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = param->vdev_id; + cmd->pattern_id = param->pattern_id; + + /* only support IPv4 in current stage */ + WMI_COAP_IPV6_SET(cmd->pattern_type, 0); + WMI_COAP_ADDR_TYPE_SET(cmd->pattern_type, + param->dest_ip_v4_is_bc ? 1 : 0); + qdf_mem_copy(cmd->udp_remote_ip.ipv4_addr, ¶m->dest_ip_v4, + sizeof(param->dest_ip_v4)); + cmd->udp_remote_port = param->dest_udp_port; + qdf_mem_copy(cmd->udp_local_ip.ipv4_addr, ¶m->src_ip_v4, + sizeof(param->src_ip_v4)); + cmd->udp_local_port = param->src_udp_port; + cmd->coapmsg_len = param->coapmsg_len; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, coapmsg_len_align); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->coapmsg, param->coapmsg_len); + buf_ptr += coapmsg_len_align; + + wmi_mtrace(WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap add keepalive pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_del_pattern_cmd_tlv() - Send wmi cmd for deleting CoAP + * keepalive pattern + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_del_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len = sizeof(*cmd); + + wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = wmi_buf_data(buf); + cmd = (WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + wmi_mtrace(WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap del keepalive pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_cache_get_cmd_tlv() - Send wmi cmd for getting cached CoAP + * messages + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_cache_get_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint32_t len = sizeof(*cmd); + + wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + wmi_mtrace(WMI_WOW_COAP_GET_BUF_INFO_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_GET_BUF_INFO_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap get buf info command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * coap_extract_buf_info_tlv() - Extract CoAP buf info event + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @info: pointer to CoAP buf info + * + * The caller needs to free any possible nodes in info->info_list + * regardless of failure or success. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +coap_extract_buf_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct coap_buf_info *info) +{ + WMI_WOW_COAP_BUF_INFO_EVENT_fixed_param *buf_info_ev; + WMI_WOW_COAP_BUF_INFO_EVENTID_param_tlvs *param_buf = evt_buf; + wmi_coap_tuple *tuple; + uint8_t *payload; + uint32_t num_tuple, num_payload; + struct coap_buf_node *buf_node; + int i, j; + + buf_info_ev = param_buf->fixed_param; + if (!buf_info_ev) { + wmi_debug("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + if (buf_info_ev->vdev_id > WLAN_MAX_VDEVS) { + wmi_debug("received invalid vdev_id %d", + buf_info_ev->vdev_id); + return QDF_STATUS_E_INVAL; + } + + info->vdev_id = buf_info_ev->vdev_id; + info->req_id = buf_info_ev->pattern_id; + info->more_info = buf_info_ev->more_tuples; + + num_tuple = param_buf->num_coap_tuple; + num_payload = param_buf->num_payloads; + for (i = 0, j = 0; i < num_tuple && j < num_payload; i++) { + tuple = ¶m_buf->coap_tuple[i]; + if (!tuple->payload_len) { + wmi_err("idx %d: invalid payload len 0", i); + continue; + } + + payload = ¶m_buf->payloads[j]; + j += qdf_align(tuple->payload_len, 4); + if (j > num_payload) { + wmi_err("idx %d: payload len overflow, pos %d - total %d", + i, j, num_payload); + return QDF_STATUS_E_INVAL; + } + + buf_node = qdf_mem_malloc(sizeof(*buf_node)); + if (!buf_node) + return QDF_STATUS_E_NOMEM; + + buf_node->payload = qdf_mem_malloc(tuple->payload_len); + if (!buf_node->payload) { + qdf_mem_free(buf_node); + return QDF_STATUS_E_NOMEM; + } + + buf_node->tsf = tuple->tsf; + qdf_mem_copy(&buf_node->src_ip, tuple->src_ip.ipv4_addr, + sizeof(buf_node->src_ip)); + buf_node->len = tuple->payload_len; + qdf_mem_copy(buf_node->payload, payload, buf_node->len); + qdf_list_insert_back(&info->info_list, &buf_node->node); + + wmi_debug("idx %d: src ip 0x%x tsf 0x%llx payload len %d", + i, buf_node->src_ip, buf_node->tsf, buf_node->len); + } + + wmi_debug("vdev_id %d req_id %d num_tuple %d payload len %d more info %d", + info->vdev_id, info->req_id, num_tuple, + num_payload, info->more_info); + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_coap_attach_tlv() - attach CoAP tlv handlers + * @wmi_handle: wmi handle + * + * Return: void + */ +void wmi_coap_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_coap_add_pattern_cmd = send_coap_add_pattern_cmd_tlv; + ops->send_coap_del_pattern_cmd = send_coap_del_pattern_cmd_tlv; + ops->send_coap_add_keepalive_pattern_cmd = + send_coap_add_keepalive_pattern_cmd_tlv; + ops->send_coap_del_keepalive_pattern_cmd = + send_coap_del_keepalive_pattern_cmd_tlv; + ops->send_coap_cache_get_cmd = send_coap_cache_get_cmd_tlv; + ops->extract_coap_buf_info = coap_extract_buf_info_tlv; +}