diff options
Diffstat (limited to 'synadhd/wifi_hal/wifi_logger.cpp')
-rwxr-xr-x | synadhd/wifi_hal/wifi_logger.cpp | 2831 |
1 files changed, 2831 insertions, 0 deletions
diff --git a/synadhd/wifi_hal/wifi_logger.cpp b/synadhd/wifi_hal/wifi_logger.cpp new file mode 100755 index 0000000..0338270 --- /dev/null +++ b/synadhd/wifi_hal/wifi_logger.cpp @@ -0,0 +1,2831 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Portions copyright (C) 2017 Broadcom Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <linux/rtnetlink.h> +#include <netpacket/packet.h> +#include <linux/filter.h> +#include <linux/errqueue.h> +#include <errno.h> + +#include <linux/pkt_sched.h> +#include <netlink/object-api.h> +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink-private/object-api.h> +#include <netlink-private/types.h> +#include <unistd.h> +#include <cutils/properties.h> + + +#include "nl80211_copy.h" +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include <log/log.h> + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" +#include <sys/stat.h> +#include "syna_version.h" +#define WIFI_HAL_EVENT_SOCK_PORT 645 + +#define ARRAYSIZE(a) (u8)(sizeof(a) / sizeof(a[0])) +typedef enum { + LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START, + LOGGER_TRIGGER_MEM_DUMP, + LOGGER_GET_MEM_DUMP, + LOGGER_GET_VER, + LOGGER_GET_RING_STATUS, + LOGGER_GET_RING_DATA, + LOGGER_GET_FEATURE, + LOGGER_RESET_LOGGING, + LOGGER_TRIGGER_DRIVER_MEM_DUMP, + LOGGER_GET_DRIVER_MEM_DUMP, + LOGGER_START_PKT_FATE_MONITORING, + LOGGER_GET_TX_PKT_FATES, + LOGGER_GET_RX_PKT_FATES, + LOGGER_GET_WAKE_REASON_STATS, + LOGGER_DEBUG_GET_DUMP, + LOGGER_FILE_DUMP_DONE_IND, + LOGGER_SET_HAL_START, + LOGGER_HAL_STOP, + LOGGER_SET_HAL_PID, + LOGGER_SET_TPUT_DEBUG_DUMP_CMD, + LOGGER_GET_BUF_RING_MAP +} DEBUG_SUB_COMMAND; + +#define MAX_NV_FILE 4 +#define MAX_SKU_NAME_LEN 5 +#define OTA_PATH "/data/vendor/firmware/wifi/" +#define OTA_CLM_FILE "bcmdhd_clm.blob" +#define OTA_NVRAM_FILE "bcmdhd.cal" +#define HW_DEV_PROP "ro.revision" +#define HW_SKU_PROP "ro.boot.hardware.sku" + +typedef enum { + NVRAM, + CLM_BLOB +} OTA_TYPE; + +char ota_nvram_ext[10]; +typedef struct ota_info_buf { + u32 ota_clm_len; + const void *ota_clm_buf[1]; + u32 ota_nvram_len; + const void *ota_nvram_buf[1]; +} ota_info_buf_t; +u32 applied_ota_version = 0; + +typedef enum { + LOGGER_ATTRIBUTE_INVALID = 0, + LOGGER_ATTRIBUTE_DRIVER_VER = 1, + LOGGER_ATTRIBUTE_FW_VER = 2, + LOGGER_ATTRIBUTE_RING_ID = 3, + LOGGER_ATTRIBUTE_RING_NAME = 4, + LOGGER_ATTRIBUTE_RING_FLAGS = 5, + LOGGER_ATTRIBUTE_LOG_LEVEL = 6, + LOGGER_ATTRIBUTE_LOG_TIME_INTVAL = 7, + LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE = 8, + LOGGER_ATTRIBUTE_FW_DUMP_LEN = 9, + LOGGER_ATTRIBUTE_FW_DUMP_DATA = 10, + LOGGER_ATTRIBUTE_FW_ERR_CODE = 11, + LOGGER_ATTRIBUTE_RING_DATA = 12, + LOGGER_ATTRIBUTE_RING_STATUS = 13, + LOGGER_ATTRIBUTE_RING_NUM = 14, + LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN = 15, + LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA = 16, + LOGGER_ATTRIBUTE_PKT_FATE_NUM = 17, + LOGGER_ATTRIBUTE_PKT_FATE_DATA = 18, + LOGGER_ATTRIBUTE_HANG_REASON = 19, + LOGGER_ATTRIBUTE_BUF_RING_NUM = 20, + LOGGER_ATTRIBUTE_BUF_RING_MAP = 21, + /* Add new attributes just above this */ + LOGGER_ATTRIBUTE_MAX +} LOGGER_ATTRIBUTE; + +typedef enum { + DEBUG_OFF = 0, + DEBUG_NORMAL, + DEBUG_VERBOSE, + DEBUG_VERY, + DEBUG_VERY_VERY, +} LOGGER_LEVEL; + +typedef enum { + GET_FW_VER, + GET_DRV_VER, + GET_RING_DATA, + GET_RING_STATUS, + GET_FEATURE, + START_RING_LOG, + GET_BUF_RING_MAP, +} GetCmdType; + +typedef enum { + PACKET_MONITOR_START, + TX_PACKET_FATE, + RX_PACKET_FATE, +} PktFateReqType; + +enum wake_stat_attributes { + WAKE_STAT_ATTRIBUTE_INVALID, + WAKE_STAT_ATTRIBUTE_TOTAL, + WAKE_STAT_ATTRIBUTE_WAKE, + WAKE_STAT_ATTRIBUTE_COUNT, + WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED, + WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW, + WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE, + WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT, + WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED, + WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE, + WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT, + WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT, + WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT, + WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, + WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT, + WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA, + WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA, + WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, + WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT, + WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT, + WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT, + WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO, + WAKE_STAT_ATTRIBUTE_MAX +}; + +typedef enum { + SET_HAL_START_ATTRIBUTE_DEINIT = 0x0001, + SET_HAL_START_ATTRIBUTE_PRE_INIT = 0x0002, + SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003 +} SET_HAL_START_ATTRIBUTE; + +typedef enum { + OTA_DOWNLOAD_CLM_LENGTH_ATTR = 0x0001, + OTA_DOWNLOAD_CLM_ATTR = 0x0002, + OTA_DOWNLOAD_NVRAM_LENGTH_ATTR = 0x0003, + OTA_DOWNLOAD_NVRAM_ATTR = 0x0004, + OTA_SET_FORCE_REG_ON = 0x0005, + OTA_CUR_NVRAM_EXT_ATTR = 0x0006, +} OTA_DOWNLOAD_ATTRIBUTE; + +#define HAL_START_REQUEST_ID 2 +#define HAL_RESTART_ID 3 +#define FILE_NAME_LEN 256 +#define RING_NAME_LEN 32 +#if defined(RING_DUMP) +/* Loglevel */ +#define DUMP_DEBUG(x) +#define DUMP_INFO(x) ALOGI x +#define FILE_DUMP_REQUEST_ID 2 +#define C2S(x) case x: return #x; +static const char *EWP_EventAttrToString(int len_attr); +static const char *EWP_CmdAttrToString(int data_attr); + +typedef struct buf_data { + u32 ver; /* version of struct */ + u32 len; /* Total len */ + /* size of each buffer in case of split buffers (0 - single buffer). */ + u32 buf_threshold; + const void *data_buf[1]; /* array of user space buffer pointers.*/ +} buf_data_t; + +/* Attributes associated with GOOGLE_FILE_DUMP_EVENT */ +typedef enum { + DUMP_LEN_ATTR_INVALID = 0, + DUMP_LEN_ATTR_MEMDUMP = 1, + DUMP_LEN_ATTR_SSSR_C0_BEFORE = 2, + DUMP_LEN_ATTR_SSSR_C0_AFTER = 3, + DUMP_LEN_ATTR_SSSR_C1_BEFORE = 4, + DUMP_LEN_ATTR_SSSR_C1_AFTER = 5, + DUMP_LEN_ATTR_SSSR_C2_BEFORE = 6, + DUMP_LEN_ATTR_SSSR_C2_AFTER = 7, + DUMP_LEN_ATTR_SSSR_DIG_BEFORE = 8, + DUMP_LEN_ATTR_SSSR_DIG_AFTER = 9, + DUMP_LEN_ATTR_TIMESTAMP = 10, + DUMP_LEN_ATTR_GENERAL_LOG = 11, + DUMP_LEN_ATTR_ECNTRS = 12, + DUMP_LEN_ATTR_SPECIAL_LOG = 13, + DUMP_LEN_ATTR_DHD_DUMP = 14, + DUMP_LEN_ATTR_EXT_TRAP = 15, + DUMP_LEN_ATTR_HEALTH_CHK = 16, + DUMP_LEN_ATTR_PRESERVE_LOG = 17, + DUMP_LEN_ATTR_COOKIE = 18, + DUMP_LEN_ATTR_FLOWRING_DUMP = 19, + DUMP_LEN_ATTR_PKTLOG = 20, + DUMP_LEN_ATTR_PKTLOG_DEBUG = 21, + DUMP_FILENAME_ATTR_DEBUG_DUMP = 22, + DUMP_FILENAME_ATTR_MEM_DUMP = 23, + DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP = 24, + DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP = 25, + DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP = 26, + DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP = 27, + DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP = 28, + DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP = 29, + DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP = 30, + DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP = 31, + DUMP_FILENAME_ATTR_PKTLOG_DUMP = 32, + DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP = 33, + DUMP_LEN_ATTR_STATUS_LOG = 34, + DUMP_LEN_ATTR_AXI_ERROR = 35, + DUMP_FILENAME_ATTR_AXI_ERROR_DUMP = 36, + DUMP_LEN_ATTR_RTT_LOG = 37, + DUMP_LEN_ATTR_SDTC_ETB_DUMP = 38, + DUMP_FILENAME_ATTR_SDTC_ETB_DUMP = 39, + DUMP_LEN_ATTR_PKTID_MAP_LOG = 40, + DUMP_LEN_ATTR_PKTID_UNMAP_LOG = 41, + DUMP_LEN_ATTR_EWP_HW_INIT_LOG = 42, + DUMP_LEN_ATTR_EWP_HW_MOD_DUMP = 43, + DUMP_LEN_ATTR_EWP_HW_REG_DUMP = 44, + /* Please add new attributes from here to sync up old DHD */ + DUMP_EVENT_ATTR_MAX = 45, +} EWP_DUMP_EVENT_ATTRIBUTE; + +/* Attributes associated with DEBUG_GET_DUMP_BUF */ +typedef enum { + DUMP_BUF_ATTR_INVALID = 0, + DUMP_BUF_ATTR_MEMDUMP = 1, + DUMP_BUF_ATTR_SSSR_C0_BEFORE = 2, + DUMP_BUF_ATTR_SSSR_C0_AFTER = 3, + DUMP_BUF_ATTR_SSSR_C1_BEFORE = 4, + DUMP_BUF_ATTR_SSSR_C1_AFTER = 5, + DUMP_BUF_ATTR_SSSR_C2_BEFORE = 6, + DUMP_BUF_ATTR_SSSR_C2_AFTER = 7, + DUMP_BUF_ATTR_SSSR_DIG_BEFORE = 8, + DUMP_BUF_ATTR_SSSR_DIG_AFTER = 9, + DUMP_BUF_ATTR_TIMESTAMP = 10, + DUMP_BUF_ATTR_GENERAL_LOG = 11, + DUMP_BUF_ATTR_ECNTRS = 12, + DUMP_BUF_ATTR_SPECIAL_LOG = 13, + DUMP_BUF_ATTR_DHD_DUMP = 14, + DUMP_BUF_ATTR_EXT_TRAP = 15, + DUMP_BUF_ATTR_HEALTH_CHK = 16, + DUMP_BUF_ATTR_PRESERVE_LOG = 17, + DUMP_BUF_ATTR_COOKIE = 18, + DUMP_BUF_ATTR_FLOWRING_DUMP = 19, + DUMP_BUF_ATTR_PKTLOG = 20, + DUMP_BUF_ATTR_PKTLOG_DEBUG = 21, + DUMP_BUF_ATTR_STATUS_LOG = 22, + DUMP_BUF_ATTR_AXI_ERROR = 23, + DUMP_BUF_ATTR_RTT_LOG = 24, + DUMP_BUF_ATTR_SDTC_ETB_DUMP = 25, + DUMP_BUF_ATTR_PKTID_MAP_LOG = 26, + DUMP_BUF_ATTR_PKTID_UNMAP_LOG = 27, + DUMP_BUF_ATTR_EWP_HW_INIT_LOG = 28, + DUMP_BUF_ATTR_EWP_HW_MOD_DUMP = 29, + DUMP_BUF_ATTR_EWP_HW_REG_DUMP = 30, + /* Please add new attributes from here to sync up old DHD */ + DUMP_BUF_ATTR_MAX = 31, +} EWP_DUMP_CMD_ATTRIBUTE; + +typedef enum { + DUMP_TYPE_MEM_DUMP = 0, + DUMP_TYPE_DEBUG_DUMP = 1, + DUMP_TYPE_SSSR_CORE0_BEF_DUMP = 2, + DUMP_TYPE_SSSR_CORE0_AFT_DUMP = 3, + DUMP_TYPE_SSSR_CORE1_BEF_DUMP = 4, + DUMP_TYPE_SSSR_CORE1_AFT_DUMP = 5, + DUMP_TYPE_SSSR_CORE2_BEF_DUMP = 6, + DUMP_TYPE_SSSR_CORE2_AFT_DUMP = 7, + DUMP_TYPE_SSSR_DIG_BEF_DUMP = 8, + DUMP_TYPE_SSSR_DIG_AFT_DUMP = 9, + DUMP_TYPE_PKTLOG_DUMP = 10, + DUMP_TYPE_PKTLOG_DEBUG_DUMP = 11, + DUMP_TYPE_AXI_ERROR_DUMP = 12, + DUMP_TYPE_D2H_MINI_DUMP = 13, + DUMP_TYPE_SDTC_ETB_DUMP = 14, + /* Please add new attributes from here to sync up old DHD */ + DUMP_TYPE_MAX = 15, +} EWP_DUMP_TYPE; + +/* Struct for table which has len_attr, data_attr and dump file type attr */ +typedef struct logger_attr_entry { + u8 attr_type; /* Type of attribute */ + u8 buf_attr; /* Buffer associated with the attribute */ + u8 dump_type; /* Each attribute will be linked to a dump type */ +} logger_attr_entry_t; + +logger_attr_entry_t attr_lookup_tbl[] = { + /* Mem Dump Block */ + {DUMP_FILENAME_ATTR_MEM_DUMP, 0, DUMP_TYPE_MEM_DUMP}, + {DUMP_LEN_ATTR_MEMDUMP, DUMP_BUF_ATTR_MEMDUMP, DUMP_TYPE_MEM_DUMP}, + /* SSSR Dump Block */ + {DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE0_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_C0_BEFORE, DUMP_BUF_ATTR_SSSR_C0_BEFORE, DUMP_TYPE_SSSR_CORE0_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE0_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_C0_AFTER, DUMP_BUF_ATTR_SSSR_C0_AFTER, DUMP_TYPE_SSSR_CORE0_AFT_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE1_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_C1_BEFORE, DUMP_BUF_ATTR_SSSR_C1_BEFORE, DUMP_TYPE_SSSR_CORE1_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE1_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_C1_AFTER, DUMP_BUF_ATTR_SSSR_C1_AFTER, DUMP_TYPE_SSSR_CORE1_AFT_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE2_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_C2_BEFORE, DUMP_BUF_ATTR_SSSR_C2_BEFORE, DUMP_TYPE_SSSR_CORE2_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE2_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_C2_AFTER, DUMP_BUF_ATTR_SSSR_C2_AFTER, DUMP_TYPE_SSSR_CORE2_AFT_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_DIG_BEF_DUMP}, + {DUMP_LEN_ATTR_SSSR_DIG_BEFORE, DUMP_BUF_ATTR_SSSR_DIG_BEFORE, DUMP_TYPE_SSSR_DIG_BEF_DUMP}, + + {DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, 0, DUMP_TYPE_SSSR_DIG_AFT_DUMP}, + {DUMP_LEN_ATTR_SSSR_DIG_AFTER, DUMP_BUF_ATTR_SSSR_DIG_AFTER, DUMP_TYPE_SSSR_DIG_AFT_DUMP}, + + /* Debug Dump Block */ + {DUMP_FILENAME_ATTR_DEBUG_DUMP, 0, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_TIMESTAMP, DUMP_BUF_ATTR_TIMESTAMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_GENERAL_LOG, DUMP_BUF_ATTR_GENERAL_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_ECNTRS, DUMP_BUF_ATTR_ECNTRS, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_SPECIAL_LOG, DUMP_BUF_ATTR_SPECIAL_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_DHD_DUMP, DUMP_BUF_ATTR_DHD_DUMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EXT_TRAP, DUMP_BUF_ATTR_EXT_TRAP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_HEALTH_CHK, DUMP_BUF_ATTR_HEALTH_CHK, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PRESERVE_LOG, DUMP_BUF_ATTR_PRESERVE_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_COOKIE, DUMP_BUF_ATTR_COOKIE, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_FLOWRING_DUMP, DUMP_BUF_ATTR_FLOWRING_DUMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_STATUS_LOG, DUMP_BUF_ATTR_STATUS_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_RTT_LOG, DUMP_BUF_ATTR_RTT_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PKTID_MAP_LOG, DUMP_BUF_ATTR_PKTID_MAP_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PKTID_UNMAP_LOG, DUMP_BUF_ATTR_PKTID_UNMAP_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EWP_HW_INIT_LOG, DUMP_BUF_ATTR_EWP_HW_INIT_LOG, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EWP_HW_MOD_DUMP, DUMP_BUF_ATTR_EWP_HW_MOD_DUMP, DUMP_TYPE_DEBUG_DUMP}, + {DUMP_LEN_ATTR_EWP_HW_REG_DUMP, DUMP_BUF_ATTR_EWP_HW_REG_DUMP, DUMP_TYPE_DEBUG_DUMP}, + + /* PKT log dump block */ + {DUMP_FILENAME_ATTR_PKTLOG_DUMP, 0, DUMP_TYPE_PKTLOG_DUMP}, + {DUMP_LEN_ATTR_PKTLOG, DUMP_BUF_ATTR_PKTLOG, DUMP_TYPE_PKTLOG_DUMP}, + {DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP, 0, DUMP_TYPE_PKTLOG_DEBUG_DUMP}, + {DUMP_LEN_ATTR_PKTLOG_DEBUG, DUMP_BUF_ATTR_PKTLOG_DEBUG, DUMP_TYPE_PKTLOG_DEBUG_DUMP}, + /* AXI error log dump block */ + {DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, 0, DUMP_TYPE_AXI_ERROR_DUMP}, + {DUMP_LEN_ATTR_AXI_ERROR, DUMP_BUF_ATTR_AXI_ERROR, DUMP_TYPE_AXI_ERROR_DUMP}, + /* SDTC etb log dump block */ + {DUMP_FILENAME_ATTR_SDTC_ETB_DUMP, 0, DUMP_TYPE_SDTC_ETB_DUMP}, + {DUMP_LEN_ATTR_SDTC_ETB_DUMP, DUMP_BUF_ATTR_SDTC_ETB_DUMP, DUMP_TYPE_SDTC_ETB_DUMP}, + {DUMP_EVENT_ATTR_MAX, 0, 0}, +}; + +static const char *EWP_EventAttrToString(int len_attr) +{ + switch (len_attr) { + C2S(DUMP_LEN_ATTR_MEMDUMP) + C2S(DUMP_LEN_ATTR_SSSR_C0_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_C0_AFTER) + C2S(DUMP_LEN_ATTR_SSSR_C1_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_C1_AFTER) + C2S(DUMP_LEN_ATTR_SSSR_C2_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_C2_AFTER) + C2S(DUMP_LEN_ATTR_SSSR_DIG_BEFORE) + C2S(DUMP_LEN_ATTR_SSSR_DIG_AFTER) + C2S(DUMP_LEN_ATTR_TIMESTAMP) + C2S(DUMP_LEN_ATTR_GENERAL_LOG) + C2S(DUMP_LEN_ATTR_ECNTRS) + C2S(DUMP_LEN_ATTR_SPECIAL_LOG) + C2S(DUMP_LEN_ATTR_DHD_DUMP) + C2S(DUMP_LEN_ATTR_EXT_TRAP) + C2S(DUMP_LEN_ATTR_HEALTH_CHK) + C2S(DUMP_LEN_ATTR_PRESERVE_LOG) + C2S(DUMP_LEN_ATTR_COOKIE) + C2S(DUMP_LEN_ATTR_FLOWRING_DUMP) + C2S(DUMP_LEN_ATTR_PKTLOG) + C2S(DUMP_LEN_ATTR_PKTLOG_DEBUG) + C2S(DUMP_LEN_ATTR_STATUS_LOG) + C2S(DUMP_FILENAME_ATTR_DEBUG_DUMP) + C2S(DUMP_FILENAME_ATTR_MEM_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP) + C2S(DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP) + C2S(DUMP_FILENAME_ATTR_PKTLOG_DUMP) + C2S(DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP) + C2S(DUMP_LEN_ATTR_AXI_ERROR) + C2S(DUMP_FILENAME_ATTR_AXI_ERROR_DUMP) + C2S(DUMP_LEN_ATTR_RTT_LOG) + C2S(DUMP_FILENAME_ATTR_SDTC_ETB_DUMP) + C2S(DUMP_LEN_ATTR_SDTC_ETB_DUMP) + C2S(DUMP_LEN_ATTR_PKTID_MAP_LOG) + C2S(DUMP_LEN_ATTR_PKTID_UNMAP_LOG) + C2S(DUMP_LEN_ATTR_EWP_HW_INIT_LOG) + C2S(DUMP_LEN_ATTR_EWP_HW_MOD_DUMP) + C2S(DUMP_LEN_ATTR_EWP_HW_REG_DUMP) + default: + return "DUMP_LEN_ATTR_INVALID"; + } +} + +static const char *EWP_CmdAttrToString(int attr) +{ + switch (attr) { + C2S(DUMP_BUF_ATTR_MEMDUMP) + C2S(DUMP_BUF_ATTR_SSSR_C0_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_C0_AFTER) + C2S(DUMP_BUF_ATTR_SSSR_C1_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_C1_AFTER) + C2S(DUMP_BUF_ATTR_SSSR_C2_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_C2_AFTER) + C2S(DUMP_BUF_ATTR_SSSR_DIG_BEFORE) + C2S(DUMP_BUF_ATTR_SSSR_DIG_AFTER) + C2S(DUMP_BUF_ATTR_TIMESTAMP) + C2S(DUMP_BUF_ATTR_GENERAL_LOG) + C2S(DUMP_BUF_ATTR_ECNTRS) + C2S(DUMP_BUF_ATTR_SPECIAL_LOG) + C2S(DUMP_BUF_ATTR_DHD_DUMP) + C2S(DUMP_BUF_ATTR_EXT_TRAP) + C2S(DUMP_BUF_ATTR_HEALTH_CHK) + C2S(DUMP_BUF_ATTR_PRESERVE_LOG) + C2S(DUMP_BUF_ATTR_COOKIE) + C2S(DUMP_BUF_ATTR_FLOWRING_DUMP) + C2S(DUMP_BUF_ATTR_PKTLOG) + C2S(DUMP_BUF_ATTR_PKTLOG_DEBUG) + C2S(DUMP_BUF_ATTR_STATUS_LOG) + C2S(DUMP_BUF_ATTR_AXI_ERROR) + C2S(DUMP_BUF_ATTR_RTT_LOG) + C2S(DUMP_BUF_ATTR_SDTC_ETB_DUMP) + C2S(DUMP_BUF_ATTR_PKTID_MAP_LOG) + C2S(DUMP_BUF_ATTR_PKTID_UNMAP_LOG) + C2S(DUMP_BUF_ATTR_EWP_HW_INIT_LOG) + C2S(DUMP_BUF_ATTR_EWP_HW_MOD_DUMP) + C2S(DUMP_BUF_ATTR_EWP_HW_REG_DUMP) + default: + return "DUMP_BUF_ATTR_INVALID"; + } +} + +/* Return index for matching buffer attribute */ +static int logger_attr_buffer_lookup(u8 attr) { + for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) { + if (attr == attr_lookup_tbl[i].buf_attr) { + return i; + } + } + ALOGE("Lookup for buf attr = %s failed\n", + EWP_CmdAttrToString(attr)); + return -1; +} + +/* Return index matching the length attribute */ +static int logger_attr_lookup(u8 attr) { + for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) { + if (attr == attr_lookup_tbl[i].attr_type) { + return i; + } + } + ALOGE("Lookup for len attr = %s failed\n", + EWP_EventAttrToString(attr)); + return -1; +} +#endif /* RING_DUMP */ + +#define DBGRING_NAME_MAX 32 //Copy from legacy hal +typedef struct wifi_buf_ring_map_entry { + uint32_t type; + uint32_t ring_id; + char ring_name[DBGRING_NAME_MAX]; +} wifi_buf_ring_map_entry_t; + +typedef struct { + char hw_id[PROPERTY_VALUE_MAX]; + char sku[MAX_SKU_NAME_LEN]; +} sku_info_t; + +sku_info_t sku_table[] = { + { {"G9S9B"}, {"MMW"} }, + { {"G8V0U"}, {"MMW"} }, + { {"GFQM1"}, {"MMW"} }, + { {"GB62Z"}, {"MMW"} }, + { {"GB7N6"}, {"ROW"} }, + { {"GLU0G"}, {"ROW"} }, + { {"GNA8F"}, {"ROW"} }, + { {"GX7AS"}, {"ROW"} }, + { {"GR1YH"}, {"JPN"} }, + { {"GF5KQ"}, {"JPN"} }, + { {"GPQ72"}, {"JPN"} }, + { {"GB17L"}, {"JPN"} }, + { {"G1AZG"}, {"EU"} } +}; +/////////////////////////////////////////////////////////////////////////////// +class DebugCommand : public WifiCommand +{ + char *mBuff; + int *mBuffSize; + u32 *mNumRings; + wifi_ring_buffer_status *mStatus; + u32 *mNumMaps; + wifi_buf_ring_map_entry_t *mMaps; + unsigned int *mSupport; + u32 mVerboseLevel; + u32 mFlags; + u32 mMaxIntervalSec; + u32 mMinDataSize; + char *mRingName; + GetCmdType mType; + +public: + + // constructor for get version + DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size, + GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType + (cmdType) + { + mNumRings = NULL; + mStatus = NULL; + mSupport = NULL; + mVerboseLevel = 0; + mFlags = 0; + mMaxIntervalSec = 0; + mMinDataSize = 0; + mRingName = NULL; + memset(mBuff, 0, *mBuffSize); + } + + // constructor for ring data + DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mRingName(ring_name), mType(cmdType) + { + mBuff = NULL; + mBuffSize = NULL; + mNumRings = NULL; + mStatus = NULL; + mSupport = NULL; + mVerboseLevel = 0; + mFlags = 0; + mMaxIntervalSec = 0; + mMinDataSize = 0; + } + + // constructor for ring status + DebugCommand(wifi_interface_handle iface, u32 *num_rings, + wifi_ring_buffer_status *status, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType) + { + mBuff = NULL; + mBuffSize = NULL; + mSupport = NULL; + mVerboseLevel = 0; + mFlags = 0; + mMaxIntervalSec = 0; + mMinDataSize = 0; + mRingName = NULL; + memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings)); + } + + // constructor for feature set + DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mSupport(support), mType(cmdType) + { + mBuff = NULL; + mBuffSize = NULL; + mNumRings = NULL; + mStatus = NULL; + mVerboseLevel = 0; + mFlags = 0; + mMaxIntervalSec = 0; + mMinDataSize = 0; + mRingName = NULL; + } + + // constructor for buf ring map + DebugCommand(wifi_interface_handle iface, u32 *num_maps, + wifi_buf_ring_map_entry_t *map, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mNumMaps(num_maps), mMaps(map), mType(cmdType) + { + memset(mMaps, 0, sizeof(wifi_buf_ring_map_entry_t) * (*mNumMaps)); + } + + // constructor for ring params + DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags, + u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType) + : WifiCommand("DebugCommand", iface, 0), mVerboseLevel(verbose_level), mFlags(flags), + mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size), + mRingName(ring_name), mType(cmdType) + { + mBuff = NULL; + mBuffSize = NULL; + mNumRings = NULL; + mStatus = NULL; + mSupport = NULL; + } + + int createRingRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_START_LOGGING); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create start ring logger request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u32(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put log level; result = %d", result); + return result; + } + result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ring flags; result = %d", result); + return result; + } + result = request.put_u32(LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put log time interval; result = %d", result); + return result; + } + result = request.put_u32(LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put min data size; result = %d", result); + return result; + } + result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ringbuffer name; result = %d", result); + return result; + } + request.attr_end(data); + + return WIFI_SUCCESS; + } + + int createRequest(WifiRequest &request) { + int result; + + switch (mType) { + case GET_FW_VER: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_VER); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get fw version request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + // Driver expecting only attribute type, passing mbuff as data with + // length 0 to avoid undefined state + result = request.put(LOGGER_ATTRIBUTE_FW_VER, mBuff, 0); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get fw version request; result = %d", result); + return result; + } + request.attr_end(data); + break; + } + + case GET_DRV_VER: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_VER); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get drv version request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + // Driver expecting only attribute type, passing mbuff as data with + // length 0 to avoid undefined state + result = request.put(LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0); + + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get drv version request; result = %d", result); + return result; + } + request.attr_end(data); + break; + } + + case GET_RING_DATA: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_RING_DATA); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get ring data request; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put ring data request; result = %d", result); + return result; + } + request.attr_end(data); + break; + } + + case GET_RING_STATUS: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_RING_STATUS); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get ring status request; result = %d", result); + return result; + } + break; + } + + case GET_FEATURE: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_FEATURE); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get feature request; result = %d", result); + return result; + } + break; + } + + case GET_BUF_RING_MAP: + { + result = request.create(GOOGLE_OUI, LOGGER_GET_BUF_RING_MAP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get ring status request; result = %d", result); + return result; + } + break; + } + + case START_RING_LOG: + result = createRingRequest(request); + break; + + default: + ALOGE("Unknown Debug command"); + result = WIFI_ERROR_UNKNOWN; + } + return result; + } + + int start() { + ALOGD("Start debug command"); + WifiRequest request(familyId(), ifaceId()); + int result = createRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create debug request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register debug response; result = %d", result); + } + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In DebugCommand::handleResponse, mType:%d\n", mType); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + switch (mType) { + case GET_DRV_VER: + case GET_FW_VER: + { + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d, expected len = %d", len, *mBuffSize); + memcpy(mBuff, data, min(len, *mBuffSize)); + if (*mBuffSize < len) + return NL_SKIP; + *mBuffSize = len; + break; + } + + case START_RING_LOG: + case GET_RING_DATA: + break; + + case GET_RING_STATUS: + { + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + wifi_ring_buffer_status *status(mStatus); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + nl_iterator it(vendor_data); + if (it.get_type() == LOGGER_ATTRIBUTE_RING_NUM) { + unsigned int num_rings = it.get_u32(); + if (*mNumRings < num_rings) { + ALOGE("Not enough status buffers provided, available: %d required: %d", + *mNumRings, num_rings); + } else { + *mNumRings = num_rings; + } + } else { + ALOGE("Unknown attribute: %d expecting %d", + it.get_type(), LOGGER_ATTRIBUTE_RING_NUM); + return NL_SKIP; + } + + it.next(); + for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { + if (it.get_len() > sizeof(wifi_ring_buffer_status)) { + ALOGE("ring status unexpected len = %d, dest len = %lu", + it.get_len(), sizeof(wifi_ring_buffer_status)); + return NL_SKIP; + } else { + memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status)); + i++; + status++; + } + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + break; + } + + case GET_FEATURE: + { + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d, expected len = %lu", len, sizeof(unsigned int)); + memcpy(mSupport, data, sizeof(unsigned int)); + break; + } + + case GET_BUF_RING_MAP: + { + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + wifi_buf_ring_map_entry_t *map(mMaps); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + nl_iterator it(vendor_data); + if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_NUM) { + unsigned int num_maps = it.get_u32(); + if (*mNumMaps < num_maps) { + ALOGE("Not enough status buffers provided, available: %d required: %d", + *mNumMaps, num_maps); + } else { + *mNumMaps = num_maps; + } + } else { + ALOGE("Unknown attribute: %d expecting %d", + it.get_type(), LOGGER_ATTRIBUTE_BUF_RING_NUM); + return NL_SKIP; + } + + it.next(); + for (unsigned int i = 0; it.has_next() && i < *mNumMaps; it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_MAP) { + if (it.get_len() > sizeof(wifi_buf_ring_map_entry_t)) { + ALOGE("GET_BUF_RING_MAP: unexpected len = %d, dest len = %lu", + it.get_len(), sizeof(wifi_buf_ring_map_entry_t)); + return NL_SKIP; + } else { + memcpy(map, it.get_data(), sizeof(wifi_buf_ring_map_entry_t)); + } + i++; + map++; + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + break; + } + + default: + ALOGW("Unknown Debug command"); + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +/* API to collect a firmware version string */ +wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, + int buffer_size) +{ + if (buffer && (buffer_size > 0)) { + DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("FW version buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to collect a driver version string */ +wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size) +{ + if (buffer && (buffer_size > 0)) { + DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Driver version buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to collect driver records */ +wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name) +{ + DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +/* API to get the status of all ring buffers supported by driver */ +wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, + u32 *num_rings, wifi_ring_buffer_status *status) +{ + if (status && num_rings) { + DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Ring status buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +/* API to get supportable feature */ +wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface, + unsigned int *support) +{ + if (support) { + DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Get support buffer NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + +wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, + u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name) +{ + if (ring_name) { + ALOGE("Ring name: level:%d sec:%d ring_name:%s", + verbose_level, max_interval_sec, ring_name); + DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec, + min_data_size, ring_name, START_RING_LOG); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; + } else { + ALOGE("Ring name NULL"); + return WIFI_ERROR_INVALID_ARGS; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +class SetLogHandler : public WifiCommand +{ + wifi_ring_buffer_data_handler mHandler; + +public: + SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler) + : WifiCommand("SetLogHandler", iface, id), mHandler(handler) + { } + + int start() { + ALOGV("Register loghandler"); + int result; + uint32_t event_sock_pid = getpid() + (WIFI_HAL_EVENT_SOCK_PORT << 22); + + WifiRequest request(familyId(), ifaceId()); + + /* set hal event socket port to driver */ + result = request.create(GOOGLE_OUI, LOGGER_SET_HAL_PID); + if (result != WIFI_SUCCESS) { + ALOGV("Failed to set Hal preInit; result = %d", result); + return result; + } + registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID, event_sock_pid); + if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + ALOGV("Hal preInit Failed to put pic = %d", result); + return result; + } + + if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + ALOGV("Hal preInit Failed to put pid= %d", result); + return result; + } + + request.attr_end(data); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + ALOGE("Failed to register set Hal preInit; result = %d", result); + return result; + } + return result; + } + + virtual int cancel() { + /* Send a command to driver to stop generating logging events */ + ALOGV("Clear loghandler"); + + /* unregister event handler */ + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); + wifi_unregister_cmd(wifiHandle(), id()); + + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create reset request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to request reset; result = %d", result); + return result; + } + + ALOGD("Success to clear loghandler"); + return WIFI_SUCCESS; + } + + virtual int handleEvent(WifiEvent& event) { + char *buffer = NULL; + int buffer_size = 0; + + // ALOGD("In SetLogHandler::handleEvent"); + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + // ALOGI("Got Logger event: %d", event_id); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + if (event_id == GOOGLE_DEBUG_RING_EVENT) { + wifi_ring_buffer_status status; + memset(&status, 0, sizeof(status)); + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { + if (it.get_len() > sizeof(wifi_ring_buffer_status)) { + ALOGE("SetLogHandler: ring status unexpected len = %d, dest len = %lu", + it.get_len(), sizeof(wifi_ring_buffer_status)); + return NL_SKIP; + } else { + memcpy(&status, it.get_data(), sizeof(wifi_ring_buffer_status)); + } + } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { + buffer_size = it.get_len(); + buffer = (char *)it.get_data(); + ALOGV("SetLogHandler: ring data size = %d", buffer_size); + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + // ALOGI("Retrieved Debug data"); + if (mHandler.on_ring_buffer_data) { + /* Skip msg header. Retrieved log */ + char *pBuff; + wifi_ring_buffer_entry *buffer_entry = + (wifi_ring_buffer_entry *) buffer; + pBuff = (char *) (buffer_entry + 1); + (*mHandler.on_ring_buffer_data)((char *)status.name, pBuff, + buffer_entry->entry_size, &status); + } + } else { + ALOGE("Unknown Event"); + return NL_SKIP; + } + return NL_OK; + } +}; + +wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface, + wifi_ring_buffer_data_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGE("Loghandler start, handle = %p", handle); + + SetLogHandler *cmd = new SetLogHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + +#ifdef RING_DUMP + wifi_start_ring_dump(iface, handler); +#endif /* RING_DUMP */ + return result; +} + +wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGE("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle); + +#ifdef RING_DUMP + wifi_stop_ring_dump(iface); +#endif /* RING_DUMP */ + + if (id == -1) { + wifi_ring_buffer_data_handler handler; + memset(&handler, 0, sizeof(handler)); + + SetLogHandler *cmd = new SetLogHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + + return WIFI_SUCCESS; + } + + return wifi_get_cancel_cmd(id, iface); +} + +/////////////////////////////////////////////////////////////////////////////// +class SetAlertHandler : public WifiCommand +{ + wifi_alert_handler mHandler; + int mBuffSize; + char *mBuff; + int mErrCode; + +public: + SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler) + : WifiCommand("SetAlertHandler", iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL), + mErrCode(0) + { } + + int start() { + ALOGV("Start Alerting"); + registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); + return WIFI_SUCCESS; + } + + virtual int cancel() { + ALOGV("Clear alerthandler"); + + /* unregister alert handler */ + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); + wifi_unregister_cmd(wifiHandle(), id()); + ALOGD("Success to clear alerthandler"); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In SetAlertHandler::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d", len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in memory dump response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { + ALOGI("Initiating alert callback"); + if (mHandler.on_alert) { + (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode); + } + if (mBuff) { + free(mBuff); + mBuff = NULL; + } + } + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + char *buffer = NULL; + int buffer_size = 0; + bool is_err_alert = false; + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + ALOGI("Got event: %d", event_id); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + + if (event_id == GOOGLE_DEBUG_MEM_DUMP_EVENT) { + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { + mBuffSize = it.get_u32(); + } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { + buffer_size = it.get_len(); + buffer = (char *)it.get_data(); + } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_ERR_CODE) { + /* Error code is for error alert event only */ + mErrCode = it.get_u32(); + is_err_alert = true; + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + if (is_err_alert) { + mBuffSize = sizeof(mErrCode); + if (mBuff) free(mBuff); + mBuff = (char *)malloc(mBuffSize); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + memcpy(mBuff, (char *)&mErrCode, mBuffSize); + ALOGI("Initiating alert callback"); + if (mHandler.on_alert) { + (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode); + } + if (mBuff) { + free(mBuff); + mBuff = NULL; + } + mBuffSize = 0; + return NL_OK; + } + + if (mBuffSize) { + ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size); + if (mBuff) free(mBuff); + mBuff = (char *)malloc(mBuffSize + buffer_size); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + memcpy(mBuff, buffer, buffer_size); + + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get memory dump request; result = %d", result); + free(mBuff); + return NL_SKIP; + } + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + + result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, + (uint64_t)(mBuff+buffer_size)); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + + request.attr_end(data); + mBuffSize += buffer_size; + + result = requestResponse(request); + + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get momory dump response; result = %d", result); + } + } else { + ALOGE("dump event missing dump length attribute"); + return NL_SKIP; + } + } + return NL_OK; + } +}; + +class SetRestartHandler : public WifiCommand +{ + wifi_subsystem_restart_handler mHandler; + char *mBuff; +public: + SetRestartHandler(wifi_handle handle, wifi_request_id id, wifi_subsystem_restart_handler handler) + : WifiCommand("SetRestartHandler", handle, id), mHandler(handler), mBuff(NULL) + { } + int start() { + ALOGI("Start Restart Handler handler"); + registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED); + return WIFI_SUCCESS; + } + virtual int cancel() { + ALOGI("Clear Restart Handler"); + + /* unregister alert handler */ + unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED); + wifi_unregister_cmd(wifiHandle(), id()); + ALOGI("Success to clear restarthandler"); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + ALOGI("Got event: %d", event_id); + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + if (event_id == BRCM_VENDOR_EVENT_HANGED) { + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_HANG_REASON) { + mBuff = (char *)it.get_data(); + } else { + ALOGI("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + + if (*mHandler.on_subsystem_restart) { + (*mHandler.on_subsystem_restart)(mBuff); + ALOGI("Hang event received. Trigger SSR handler:%p", + mHandler.on_subsystem_restart); + } else { + ALOGI("No Restart handler registered"); + } + } + return NL_OK; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +class SubSystemRestart : public WifiCommand +{ + public: + SubSystemRestart(wifi_interface_handle iface) + : WifiCommand("SubSystemRestart", iface, 0) + { } + + int createRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_TRIGGER_SSR); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int create() { + WifiRequest request(familyId(), ifaceId()); + + int result = createRequest(request); + if (result < 0) { + ALOGE("Failed to create ssr request result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register ssr response; result = %d\n", result); + } + return result; + } + + protected: + int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* NO events to handle here! */ + return NL_SKIP; + } + +}; +/////////////////////////////////////////////////////////////////////////////// +class HalInit : public WifiCommand +{ + int mErrCode; + + public: + HalInit(wifi_interface_handle iface, int id) + : WifiCommand("HalInit", iface, id), mErrCode(0) + { } + + int start() { + ALOGE("Start Set Hal"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, LOGGER_SET_HAL_START); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to set hal start; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set hal start response; result = %d", result); + } + return result; + } + + + virtual int cancel() { + ALOGE("Cancel: Stop Hal"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, LOGGER_HAL_STOP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to stop hal ; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set hal start response; result = %d", result); + } + wifi_unregister_cmd(wifiHandle(), id()); + ALOGV("Stop HAL Successfully Completed, mErrCode = %d\n", mErrCode); + return result; + } + + int preInit() { + ALOGE("Hal preInit"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, LOGGER_SET_HAL_START); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to set Hal preInit; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_string(SET_HAL_START_ATTRIBUTE_PRE_INIT, (char *)HAL_VERSION); + if (result != WIFI_SUCCESS) { + ALOGE("Hal preInit Failed to put data= %d", result); + return result; + } + request.attr_end(data); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set Hal preInit; result = %d", result); + } + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGE("In SetHalStarted::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +#ifdef RING_DUMP +/////////////////////////////////////////////////////////////////////////////// +class RingDump : public WifiCommand +{ + int mLargestBuffSize; + char *mBuff; + int mErrCode; + int mNumMaps; + wifi_buf_ring_map_entry_t *mMap; + int attr_type_len[DUMP_EVENT_ATTR_MAX]; + char *ring_name[DUMP_BUF_ATTR_MAX]; + wifi_ring_buffer_data_handler mHandle; + +public: + RingDump(wifi_interface_handle iface, int id, int num_maps, wifi_buf_ring_map_entry_t *map, + wifi_ring_buffer_data_handler ring_handle) + : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL), + mErrCode(0), mNumMaps(num_maps), mMap(map), mHandle(ring_handle) + { + memset(attr_type_len, 0, sizeof(attr_type_len)); + for (int i = 0; i < DUMP_BUF_ATTR_MAX; i++) { + ring_name[i] = NULL; + } + } + RingDump(wifi_interface_handle iface, int id) + : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL), + mErrCode(0) + { + } + + int start() { + DUMP_INFO(("Start Ring Dump Map_cnt:%d\n", mNumMaps)); + registerVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT); + + //Set ringname to buf hashmap + for (int i = 0; i < mNumMaps; i++) { + int type = mMap[i].type; + ring_name[type] = (char *)malloc(DBGRING_NAME_MAX); + memset(ring_name[type], 0, DBGRING_NAME_MAX); + memcpy(ring_name[type], mMap[i].ring_name, strlen(mMap[i].ring_name)); + DUMP_DEBUG(("Set ringname Buf:%s Ringname:%s len:%lu", + EWP_CmdAttrToString(type), ring_name[type], strlen(mMap[i].ring_name))); + } + return WIFI_SUCCESS; + } + + virtual int freeup() { + DUMP_DEBUG(("freeup:Enter\n")); + if (mBuff) { + free(mBuff); + mBuff = NULL; + DUMP_INFO(("freed allocated memory\n")); + } + return WIFI_SUCCESS; + } + + virtual int cancel() { + /* unregister file dump handler */ + unregisterVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT); + wifi_unregister_cmd(wifiHandle(), id()); + + /* Free up the ring names allocated */ + for (u8 i = 0; i < DUMP_BUF_ATTR_MAX; i++) { + if (ring_name[i]) { + free(ring_name[i]); + ring_name[i] = NULL; + } + } + if (mBuff) { + free(mBuff); + } + + DUMP_INFO(("Stop Ring Dump Successfully Completed, mErrCode = %d\n", mErrCode)); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + DUMP_DEBUG(("RingDump::handleResponse\n")); + int buf_attr = DUMP_BUF_ATTR_INVALID; + int len_attr = DUMP_LEN_ATTR_INVALID; + int index = -1; + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in memory dump response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + buf_attr = it.get_type(); + switch (buf_attr) { + case DUMP_BUF_ATTR_MEMDUMP: + case DUMP_BUF_ATTR_TIMESTAMP: + case DUMP_BUF_ATTR_ECNTRS: + case DUMP_BUF_ATTR_DHD_DUMP: + case DUMP_BUF_ATTR_EXT_TRAP: + case DUMP_BUF_ATTR_HEALTH_CHK: + case DUMP_BUF_ATTR_COOKIE: + case DUMP_BUF_ATTR_FLOWRING_DUMP: + case DUMP_BUF_ATTR_STATUS_LOG: + case DUMP_BUF_ATTR_RTT_LOG: { + if (it.get_u32()) { + ALOGE("Copying data to userspace failed, status = %d\n", it.get_u32()); + return WIFI_ERROR_UNKNOWN; + } + index = logger_attr_buffer_lookup(buf_attr); + if (index == -1) { + ALOGE("Invalid index. buf attr = %s\n", EWP_CmdAttrToString(buf_attr)); + return WIFI_ERROR_UNKNOWN; + } + len_attr = attr_lookup_tbl[index].attr_type; + if (len_attr == DUMP_EVENT_ATTR_MAX) { + ALOGE("Invalid len attr = %s\n", EWP_EventAttrToString(len_attr)); + return WIFI_ERROR_UNKNOWN; + } + if (!mBuff || attr_type_len[len_attr] <= 0) { + return WIFI_ERROR_UNKNOWN; + } + + if (!ring_name[buf_attr]) { + ALOGE("Not allocated buf attr = %s\n", EWP_CmdAttrToString(buf_attr)); + return WIFI_ERROR_UNKNOWN; + } + DUMP_INFO(("RingDump:: buf_attr:%s size = %d ring_name:%s\n", + EWP_CmdAttrToString(buf_attr), attr_type_len[len_attr], + ring_name[buf_attr])); + if (mHandle.on_ring_buffer_data) { + /* on_ring_buffer_data callback requires status memory + * so should pass status memory */ + wifi_ring_buffer_status status; + memset(&status, 0, sizeof(status)); + /* Skip msg header. Retrieved log */ + (*mHandle.on_ring_buffer_data)(ring_name[buf_attr], mBuff, + attr_type_len[len_attr], &status); + } + if (mBuff) { + memset(mBuff, 0, mLargestBuffSize); + } + break; + } + default: { + DUMP_DEBUG(("Ignoring invalid attribute buf_attr = %d, size = %d", + buf_attr, it.get_len())); + break; + } + } + } + return NL_OK; + } + + virtual int request_logger_dump(WifiRequest& request, + buf_data_t *buf, int len_attr) { + + int result = 0; + int buf_attr = DUMP_BUF_ATTR_INVALID; + int index = -1; + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + index = logger_attr_lookup(len_attr); + if (index == -1) { + ALOGE("Invalid index\n"); + return WIFI_ERROR_UNKNOWN; + } + buf_attr = attr_lookup_tbl[index].buf_attr; + + if (buf_attr != DUMP_BUF_ATTR_INVALID) { + result = request.put(buf_attr, buf, sizeof(buf_data_t)); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + } else { + ALOGE("Invalid buf attr = %s, index = %d\n", + EWP_CmdAttrToString(buf_attr), index); + return WIFI_ERROR_UNKNOWN; + } + DUMP_INFO(("Trigger get dump for buf attr = %s\n", + EWP_CmdAttrToString(buf_attr))); + + request.attr_end(data); + return result; + } + + virtual int handleEvent(WifiEvent& event) { + mLargestBuffSize = 0; + mBuff = NULL; + memset(attr_type_len, 0, sizeof(attr_type_len)); + u8 i = 0; + int result = 0; + int mActualBuffSize = 0; + int index = -1; + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + int event_id = event.get_vendor_subcmd(); + int req_attr_cnt = 0; + int req_attr[DUMP_EVENT_ATTR_MAX]; + int buf_attr = DUMP_BUF_ATTR_INVALID; + + if (vendor_data == NULL || len == 0) { + ALOGE("No Debug data found"); + return NL_SKIP; + } + DUMP_INFO(("Ring Dump handler. Got event: %d", event_id)); + + buf_data_t buf; + + memset(&buf, 0, sizeof(buf_data_t)); + buf.ver = 0; + buf.buf_threshold = 0; + + if (event_id == GOOGLE_FILE_DUMP_EVENT) { + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + int attr = it.get_type(); + switch (attr) { + case DUMP_LEN_ATTR_MEMDUMP: + case DUMP_LEN_ATTR_TIMESTAMP: + case DUMP_LEN_ATTR_ECNTRS: + case DUMP_LEN_ATTR_DHD_DUMP: + case DUMP_LEN_ATTR_EXT_TRAP: + case DUMP_LEN_ATTR_HEALTH_CHK: + case DUMP_LEN_ATTR_COOKIE: + case DUMP_LEN_ATTR_FLOWRING_DUMP: + case DUMP_LEN_ATTR_STATUS_LOG: + case DUMP_LEN_ATTR_RTT_LOG: { + mActualBuffSize = it.get_u32(); + DUMP_DEBUG(("len attr %s, len %d\n", + EWP_EventAttrToString(attr), mActualBuffSize)); + if (mActualBuffSize > mLargestBuffSize) + mLargestBuffSize = mActualBuffSize; + attr_type_len[attr] = mActualBuffSize; + + /* Store the order in which attributes are received + * so that file dump can be done in the same order + */ + req_attr[req_attr_cnt++] = attr; + break; + } + default: { + ALOGE("Ignoring invalid attribute type = %d, size = %d", + attr, it.get_len()); + break; + } + } + } + /* Allocation for the largest buffer size to use it recursively for other buf attr. */ + if (mLargestBuffSize) { + DUMP_INFO(("Max dump size: %d", mLargestBuffSize)); + mBuff = (char *)malloc(mLargestBuffSize); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + memset(mBuff, 0, mLargestBuffSize); + } + + WifiRequest request(familyId(), ifaceId()); + result = request.create(GOOGLE_OUI, LOGGER_DEBUG_GET_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get memory dump request; result = %d", result); + freeup(); + goto exit; + } + + /* Requesting logger dump for each received attr */ + for (i = 0; i < req_attr_cnt; i++) { + int attr = req_attr[i]; + + if (attr_type_len[attr] == 0) { + continue; + } + + index = logger_attr_lookup(attr); + buf_attr = attr_lookup_tbl[index].buf_attr; + if (!ring_name[buf_attr]) { + ALOGE("Failed to find ringname index:%d buf_attr:%d", index, buf_attr); + continue; + } + + buf.len = attr_type_len[attr]; + buf.data_buf[0] = mBuff; + DUMP_DEBUG(("buf len = %d, buf ptr= %p for attr = %s\n", + buf.len, buf.data_buf[0], EWP_EventAttrToString(attr))); + result = request_logger_dump(request, &buf, attr); + if (result != WIFI_SUCCESS) { + /* Proceeding further for other attributes */ + ALOGE("Failed to request the logger dump for attr = %s; result = %d", + EWP_EventAttrToString(attr), result); + continue; + } + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get memory dump response for attr = %s; result = %d", + EWP_EventAttrToString(attr), result); + /* Proceeding further for other attributes */ + continue; + } + } + + WifiRequest request2(familyId(), ifaceId()); + result = request2.create(GOOGLE_OUI, LOGGER_FILE_DUMP_DONE_IND); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to trigger dev close; result = %d", result); + freeup(); + goto exit; + } + requestResponse(request2); + freeup(); + } else { + ALOGE("dump event missing dump length attribute"); + return NL_SKIP; + } + exit: + if (result != WIFI_SUCCESS) { + return NL_SKIP; + } + return NL_OK; + } +}; +/////////////////////////////////////////////////////////////////////////////// +#endif /* RING_DUMP */ + +wifi_error wifi_start_hal(wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("HAL INIT start, handle = %p", handle); + + HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, HAL_START_REQUEST_ID, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle,HAL_START_REQUEST_ID); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_hal_preInit(wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("wifi_hal_preInit, handle = %p", handle); + + HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, HAL_START_REQUEST_ID, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->preInit(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle,HAL_START_REQUEST_ID); + cmd->releaseRef(); + return result; + } + return result; +} + +#ifdef RING_DUMP +wifi_error wifi_start_ring_dump(wifi_interface_handle iface, + wifi_ring_buffer_data_handler ring_handle) +{ + wifi_handle handle = getWifiHandle(iface); + DUMP_INFO(("start ring dump, handle = %p", handle)); + wifi_buf_ring_map_entry_t map[DUMP_BUF_ATTR_MAX]; + unsigned int num_maps = DUMP_BUF_ATTR_MAX; + wifi_error result; + + /* Get mapping table from driver */ + DebugCommand *debug_cmd = new DebugCommand(iface, &num_maps, map, GET_BUF_RING_MAP); + NULL_CHECK_RETURN(debug_cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + result = (wifi_error)debug_cmd->start(); + debug_cmd->releaseRef(); + + /* Set ringname to corresponding buf attr */ + RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID, num_maps, map, ring_handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + result = wifi_register_cmd(handle, FILE_DUMP_REQUEST_ID, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, FILE_DUMP_REQUEST_ID); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_stop_ring_dump(wifi_interface_handle iface) +{ + RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + DUMP_INFO(("stop ring dump")); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; +} +#endif /* RING_DUMP */ + +wifi_error wifi_stop_hal(wifi_interface_handle iface) +{ + HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; +} + + +wifi_error wifi_set_subsystem_restart_handler(wifi_handle handle, + wifi_subsystem_restart_handler handler) +{ + hal_info *info = NULL; + + info = (hal_info *)handle; + if (info == NULL) { + ALOGE("Could not find hal info\n"); + return WIFI_ERROR_UNKNOWN; + } + + SetRestartHandler *cmd = new SetRestartHandler(handle, HAL_RESTART_ID, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, HAL_RESTART_ID, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, HAL_RESTART_ID); + cmd->releaseRef(); + return result; + } + + /* Cache the handler to use it for trigger subsystem restart */ + ALOGI("Register SSR handler:%p", handler); + info->restart_handler = handler; + return result; +} + +wifi_error wifi_trigger_subsystem_restart(wifi_handle handle) +{ + wifi_error result = WIFI_SUCCESS; + hal_info *info = NULL; + char error_str[20]; + SubSystemRestart *cmd = NULL; + wifi_interface_handle *ifaceHandles = NULL; + wifi_interface_handle wlan0Handle; + int numIfaceHandles = 0; + + info = (hal_info *)handle; + if (handle == NULL || info == NULL) { + ALOGE("Could not find hal info\n"); + result = WIFI_ERROR_UNKNOWN; + goto exit; + } + + ALOGI("Trigger subsystem restart\n"); + + wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles); + + cmd = new SubSystemRestart(wlan0Handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + result = (wifi_error)cmd->create(); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + strncpy(error_str, "WIFI_ERROR_UNKNOWN", sizeof(error_str)); + ALOGE("Failed to create SSR"); + goto exit; + } + + strncpy(error_str, "WIFI_SUCCESS", sizeof(error_str)); + +exit: + if (result == WIFI_SUCCESS) { + if (info->restart_handler.on_subsystem_restart) { + ALOGI("Trigger ssr handler registered handler:%p", + info->restart_handler.on_subsystem_restart); + (info->restart_handler.on_subsystem_restart)(error_str); + } else { + ALOGI("No trigger ssr handler registered"); + } + } + + return result; +} + +wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface, + wifi_alert_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Alerthandler start, handle = %p", handle); + + SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = wifi_register_cmd(handle, id, cmd); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + wifi_unregister_cmd(handle, id); + cmd->releaseRef(); + return result; + } + return result; +} + +wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface) +{ + wifi_handle handle = getWifiHandle(iface); + ALOGV("Alerthandler reset, wifi_request_id = %d, handle = %p", id, handle); + + if (id == -1) { + wifi_alert_handler handler; + memset(&handler, 0, sizeof(handler)); + + SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + cmd->cancel(); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return wifi_get_cancel_cmd(id, iface); +} + +/////////////////////////////////////////////////////////////////////////////// +class MemoryDumpCommand: public WifiCommand +{ + wifi_firmware_memory_dump_handler mHandler; + int mBuffSize; + char *mBuff; + +public: + MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler) + : WifiCommand("MemoryDumpCommand", iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL) + { } + + int start() { + ALOGD("Start memory dump command"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create trigger fw memory dump request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register trigger memory dump response; result = %d", result); + } + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In MemoryDumpCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGD("len = %d", len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in memory dump response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { + mBuffSize = it.get_u32(); + + if (mBuff) + free(mBuff); + mBuff = (char *)malloc(mBuffSize); + if (!mBuff) { + ALOGE("Buffer allocation failed"); + return NL_SKIP; + } + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to create get memory dump request; result = %d", result); + free(mBuff); + return NL_SKIP; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + + result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to put get memory dump request; result = %d", result); + return result; + } + request.attr_end(data); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get momory dump response; result = %d", result); + } + } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { + ALOGI("Initiating memory dump callback"); + if (mHandler.on_firmware_memory_dump) { + (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize); + } + if (mBuff) { + free(mBuff); + mBuff = NULL; + } + } else { + ALOGW("Ignoring invalid attribute type = %d, size = %d", + it.get_type(), it.get_len()); + } + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +/* API to collect a firmware memory dump for a given iface */ +wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface, + wifi_firmware_memory_dump_handler handler) +{ + MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +class PacketFateCommand: public WifiCommand +{ + void *mReportBufs; + size_t mNoReqFates; + size_t *mNoProvidedFates; + PktFateReqType mReqType; + +public: + PacketFateCommand(wifi_interface_handle handle) + : WifiCommand("PacketFateCommand", handle, 0), mReqType(PACKET_MONITOR_START) + { + mReportBufs = NULL; + mNoReqFates = 0; + mNoProvidedFates = NULL; + } + + PacketFateCommand(wifi_interface_handle handle, wifi_tx_report *tx_report_bufs, + size_t n_requested_fates, size_t *n_provided_fates) + : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(tx_report_bufs), + mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates), + mReqType(TX_PACKET_FATE) + { } + + PacketFateCommand(wifi_interface_handle handle, wifi_rx_report *rx_report_bufs, + size_t n_requested_fates, size_t *n_provided_fates) + : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(rx_report_bufs), + mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates), + mReqType(RX_PACKET_FATE) + { } + + int createRequest(WifiRequest& request) { + if (mReqType == TX_PACKET_FATE) { + ALOGD("%s Get Tx packet fate request\n", __FUNCTION__); + return createTxPktFateRequest(request); + } else if (mReqType == RX_PACKET_FATE) { + ALOGD("%s Get Rx packet fate request\n", __FUNCTION__); + return createRxPktFateRequest(request); + } else if (mReqType == PACKET_MONITOR_START) { + ALOGD("%s Monitor packet fate request\n", __FUNCTION__); + return createMonitorPktFateRequest(request); + } else { + ALOGE("%s Unknown packet fate request\n", __FUNCTION__); + return WIFI_ERROR_NOT_SUPPORTED; + } + return WIFI_SUCCESS; + } + + int createMonitorPktFateRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_START_PKT_FATE_MONITORING); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + request.attr_end(data); + return result; + } + + int createTxPktFateRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_GET_TX_PKT_FATES); + if (result < 0) { + return result; + } + + memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_tx_report))); + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates); + if (result < 0) { + return result; + } + result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs); + if (result < 0) { + return result; + } + request.attr_end(data); + return result; + } + + int createRxPktFateRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_GET_RX_PKT_FATES); + if (result < 0) { + return result; + } + + memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_rx_report))); + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates); + if (result < 0) { + return result; + } + result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs); + if (result < 0) { + return result; + } + request.attr_end(data); + return result; + } + + int start() { + ALOGD("Start get packet fate command\n"); + WifiRequest request(familyId(), ifaceId()); + + int result = createRequest(request); + if (result < 0) { + ALOGE("Failed to create get pkt fate request; result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register get pkt fate response; result = %d\n", result); + } + return result; + } + + int handleResponse(WifiEvent& reply) { + ALOGD("In GetPktFateCommand::handleResponse\n"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGI("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + + if (mReqType == TX_PACKET_FATE) { + ALOGI("Response received for get TX pkt fate command\n"); + } else if (mReqType == RX_PACKET_FATE) { + ALOGI("Response received for get RX pkt fate command\n"); + } else if (mReqType == PACKET_MONITOR_START) { + ALOGI("Response received for monitor pkt fate command\n"); + return NL_OK; + } else { + ALOGE("Response received for unknown pkt fate command\n"); + return NL_SKIP; + } + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + if (it.get_type() == LOGGER_ATTRIBUTE_PKT_FATE_NUM) { + *mNoProvidedFates = it.get_u32(); + ALOGI("No: of pkt fates provided is %zu\n", *mNoProvidedFates); + } else { + ALOGE("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + } + } + + return NL_OK; + } + + int handleEvent(WifiEvent& event) { + /* NO events to handle here! */ + return NL_SKIP; + } +}; + +class GetWakeReasonCountCommand : public WifiCommand { + WLAN_DRIVER_WAKE_REASON_CNT *mWakeReasonCnt; + void *mCmdEventWakeCount; + public: + GetWakeReasonCountCommand(wifi_interface_handle handle, + WLAN_DRIVER_WAKE_REASON_CNT *wlanDriverWakeReasonCount) : + WifiCommand("GetWakeReasonCountCommand", handle, 0), + mWakeReasonCnt(wlanDriverWakeReasonCount) + { + mCmdEventWakeCount = mWakeReasonCnt->cmd_event_wake_cnt; + } + + int createRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, LOGGER_GET_WAKE_REASON_STATS); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + request.attr_end(data); + return WIFI_SUCCESS; + } + + int start() { + ALOGD("Start get wake stats command\n"); + WifiRequest request(familyId(), ifaceId()); + + int result = createRequest(request); + if (result < 0) { + ALOGE("Failed to create request result = %d\n", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register wake stats response; result = %d\n", result); + } + return result; + } + + protected: + int handleResponse(WifiEvent& reply) { + ALOGE("In GetWakeReasonCountCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetGetWakeReasonCountCommand response; ignoring it"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + switch (it.get_type()) { + case WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW: + mWakeReasonCnt->total_driver_fw_local_wake = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_TOTAL: + mWakeReasonCnt->total_cmd_event_wake = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED: + mWakeReasonCnt->cmd_event_wake_cnt_used = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_WAKE: + memcpy(mCmdEventWakeCount, it.get_data(), + (mWakeReasonCnt->cmd_event_wake_cnt_used * sizeof(int))); + break; + case WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE: + mWakeReasonCnt->total_rx_data_wake = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT: + mWakeReasonCnt->rx_wake_details.rx_unicast_cnt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT: + mWakeReasonCnt->rx_wake_details.rx_multicast_cnt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT: + mWakeReasonCnt->rx_wake_details.rx_broadcast_cnt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT: + mWakeReasonCnt->rx_wake_pkt_classification_info.icmp_pkt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT: + mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_pkt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA: + mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_ra = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA: + mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_na = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS: + mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_ns = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT: + mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT: + mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt = + it.get_u32(); + break; + case WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT: + mWakeReasonCnt->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt = + it.get_u32(); + break; + default: + break; + } + + } + return NL_OK; + } +}; + +wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle) +{ + PacketFateCommand *cmd = new PacketFateCommand(handle); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle, + wifi_tx_report *tx_report_bufs, size_t n_requested_fates, + size_t *n_provided_fates) +{ + PacketFateCommand *cmd = new PacketFateCommand(handle, tx_report_bufs, + n_requested_fates, n_provided_fates); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle, + wifi_rx_report *rx_report_bufs, size_t n_requested_fates, + size_t *n_provided_fates) +{ + PacketFateCommand *cmd = new PacketFateCommand(handle, rx_report_bufs, + n_requested_fates, n_provided_fates); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle, + WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt) +{ + GetWakeReasonCountCommand *cmd = + new GetWakeReasonCountCommand(handle, wifi_wake_reason_cnt); + wifi_error result = (wifi_error)cmd->start(); + cmd->releaseRef(); + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +class OtaUpdateCommand : public WifiCommand +{ + + public: + OtaUpdateCommand(wifi_interface_handle iface) + : WifiCommand("OtaUpdateCommand", iface, 0) + { } + + int start() { + ALOGE("Start OtaUpdateCommand"); + WifiRequest request(familyId(), ifaceId()); + + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_GET_OTA_CURRUNT_INFO); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to set hal start; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set hal start response; result = %d", result); + } + return result; + } + + int otaDownload(ota_info_buf_t* buf, uint32_t ota_version) { + u32 force_reg_on = false; + WifiRequest request(familyId(), ifaceId()); + int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_OTA_UPDATE); + + ALOGE("Download the OTA configuration"); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to set Hal preInit; result = %d", result); + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + + result = request.put_u32(OTA_DOWNLOAD_CLM_LENGTH_ATTR, buf->ota_clm_len); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + result = request.put(OTA_DOWNLOAD_CLM_ATTR, buf->ota_clm_buf, sizeof(*buf->ota_clm_buf)); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + result = request.put_u32(OTA_DOWNLOAD_NVRAM_LENGTH_ATTR, buf->ota_nvram_len); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + result = request.put(OTA_DOWNLOAD_NVRAM_ATTR, + buf->ota_nvram_buf, sizeof(*buf->ota_nvram_buf)); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + if (applied_ota_version != ota_version) { + force_reg_on = true; + applied_ota_version = ota_version; + } + result = request.put_u32(OTA_SET_FORCE_REG_ON, force_reg_on); + if (result != WIFI_SUCCESS) { + ALOGE("otaDownload Failed to put data= %d", result); + return result; + } + + request.attr_end(data); + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("Failed to register set otaDownload; result = %d", result); + } + + return result; + } + + virtual int handleResponse(WifiEvent& reply) { + ALOGD("In OtaUpdateCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = reply.get_vendor_data_len(); + + ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); + + if (vendor_data == NULL || len == 0) { + ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n"); + return NL_SKIP; + } + + for (nl_iterator it(vendor_data); it.has_next(); it.next()) { + switch (it.get_type()) { + case OTA_CUR_NVRAM_EXT_ATTR: + strncpy(ota_nvram_ext, (char*)it.get_string(), it.get_len()); + ALOGI("Current Nvram ext [%s]\n", ota_nvram_ext); + break; + default: + ALOGE("Ignoring invalid attribute type = %d, size = %d\n", + it.get_type(), it.get_len()); + break; + } + } + return NL_OK; + } + + virtual int handleEvent(WifiEvent& event) { + /* NO events! */ + return NL_SKIP; + } +}; + +wifi_error read_ota_file(char* file, char** buffer, uint32_t* size) +{ + FILE* fp = NULL; + int file_size; + char* buf; + fp = fopen(file, "r"); + + if (fp == NULL) { + ALOGI("File [%s] doesn't exist.", file); + return WIFI_ERROR_NOT_AVAILABLE; + } + + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + + buf = (char *)malloc(file_size + 1); + if (buf == NULL) { + fclose(fp); + return WIFI_ERROR_UNKNOWN; + } + memset(buf, 0, file_size + 1); + fseek(fp, 0, SEEK_SET); + fread(buf, file_size, 1, fp); + + *buffer = (char*) buf; + *size = file_size; + fclose(fp); + return WIFI_SUCCESS; +} + +wifi_error check_multiple_nvram_clm(uint32_t type, char* hw_revision, char* hw_sku, + char** buffer, uint32_t* buffer_len) +{ + char file_name[MAX_NV_FILE][FILE_NAME_LEN]; + char nvram_clmblob_default_file[FILE_NAME_LEN] = {0,}; + wifi_error result = WIFI_SUCCESS; + + if (type == CLM_BLOB) { + sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_CLM_FILE); + } + else if (type == NVRAM) { + sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_NVRAM_FILE); + } + for (unsigned int i = 0; i < MAX_NV_FILE; i++) { + memset(file_name[i], 0, FILE_NAME_LEN); + } + + sprintf(file_name[0], "%s_%s_%s", nvram_clmblob_default_file, hw_revision, hw_sku); + sprintf(file_name[1], "%s_%s", nvram_clmblob_default_file, hw_revision); + sprintf(file_name[2], "%s_%s", nvram_clmblob_default_file, hw_sku); + sprintf(file_name[3], "%s", nvram_clmblob_default_file); + + for (unsigned int i = 0; i < MAX_NV_FILE; i++) { + result = read_ota_file(file_name[i], buffer, buffer_len); + if (result == WIFI_SUCCESS) { + ALOGI("[OTA] %s PATH %s", type == NVRAM ? "NVRAM" : "CLM", file_name[i]); + break; + } + } + return result; +} + +wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version) +{ + wifi_handle handle = getWifiHandle(iface); + wifi_error result = WIFI_SUCCESS; + ota_info_buf_t buf; + char *buffer_nvram = NULL; + char *buffer_clm = NULL; + char prop_revision_buf[PROPERTY_VALUE_MAX] = {0,}; + char prop_sku_buf[PROPERTY_VALUE_MAX] = {0,}; + char sku_name[MAX_SKU_NAME_LEN] = {0,}; + + OtaUpdateCommand *cmd = new OtaUpdateCommand(iface); + NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY); + + ALOGD("wifi_hal_ota_update, handle = %p, ota_version %d\n", handle, ota_version); + + result = (wifi_error)cmd->start(); + if (result != WIFI_SUCCESS) { + cmd->releaseRef(); + return result; + } + + property_get(HW_DEV_PROP, prop_revision_buf, NULL); + property_get(HW_SKU_PROP, prop_sku_buf, NULL); + + strncpy(sku_name, "NA", MAX_SKU_NAME_LEN); + for (int i = 0; i < ARRAYSIZE(sku_table); i ++) { + if (strcmp(prop_sku_buf, sku_table[i].hw_id) == 0) { + strncpy(sku_name, sku_table[i].sku, MAX_SKU_NAME_LEN); + break; + } + } + ALOGD("prop_sku_buf is %s, sku_name is %s", prop_sku_buf, sku_name); + + check_multiple_nvram_clm(CLM_BLOB, prop_revision_buf, sku_name, &buffer_clm, &buf.ota_clm_len); + if (buffer_clm == NULL) { + ALOGE("buffer_clm is null"); + goto exit; + } + buf.ota_clm_buf[0] = buffer_clm; + + check_multiple_nvram_clm(NVRAM, prop_revision_buf, sku_name, + &buffer_nvram, &buf.ota_nvram_len); + if (buffer_nvram == NULL) { + ALOGE("buffer_nvram is null"); + goto exit; + } + buf.ota_nvram_buf[0] = buffer_nvram; + cmd->otaDownload(&buf, ota_version); + +exit: + if (buffer_clm != NULL) { + free(buffer_clm); + } + if (buffer_nvram != NULL) { + free(buffer_nvram); + } + + cmd->releaseRef(); + + return result; +} |