| /* Copyright (c) 2015, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Changes from Qualcomm Innovation Center are provided under the following license: |
| * |
| * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted (subject to the limitations in the |
| * disclaimer below) provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * |
| * * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE |
| * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT |
| * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
| * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* Suppress -Waddress-of-packed-member for new toolchain update. |
| * Bug: http://b/33566695 |
| */ |
| #if __clang_major__ >= 4 |
| #pragma clang diagnostic ignored "-Waddress-of-packed-member" |
| #endif |
| |
| #include <netlink/genl/genl.h> |
| #include <netlink/genl/family.h> |
| #include <netlink/genl/ctrl.h> |
| #include <linux/rtnetlink.h> |
| #include <netinet/in.h> |
| #include <cld80211_lib.h> |
| #include "wifiloggercmd.h" |
| #include "wifilogger_event_defs.h" |
| #include "wifilogger_diag.h" |
| #include "wifilogger_vendor_tag_defs.h" |
| #include "pkt_stats.h" |
| #include <errno.h> |
| #include "wifi_hal_ctrl.h" |
| |
| #define MAX_EVENT_REASON_CODE 1024 |
| static uint32_t get_le32(const uint8_t *pos) |
| { |
| return pos[0] | (pos[1] << 8) | (pos[2] << 16) | (pos[3] << 24); |
| } |
| |
| #define MAX_CONNECTIVITY_EVENTS 18 // should match the value in wifi_logger.h |
| static event_remap_t events[MAX_CONNECTIVITY_EVENTS] = { |
| {WLAN_PE_DIAG_ASSOC_REQ_EVENT, WIFI_EVENT_ASSOCIATION_REQUESTED}, |
| {WLAN_PE_DIAG_AUTH_COMP_EVENT, WIFI_EVENT_AUTH_COMPLETE}, |
| {WLAN_PE_DIAG_CONNECTED, WIFI_EVENT_ASSOC_COMPLETE}, |
| {WLAN_PE_DIAG_AUTH_START_EVENT, WIFI_EVENT_FW_AUTH_STARTED}, |
| {WLAN_PE_DIAG_ASSOC_START_EVENT, WIFI_EVENT_FW_ASSOC_STARTED}, |
| {WLAN_PE_DIAG_REASSOC_START_EVENT, WIFI_EVENT_FW_RE_ASSOC_STARTED}, |
| {WLAN_PE_DIAG_SCAN_REQ_EVENT, WIFI_EVENT_DRIVER_SCAN_REQUESTED}, |
| {WLAN_PE_DIAG_SCAN_RES_FOUND_EVENT, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND}, |
| {WLAN_PE_DIAG_SCAN_COMP_EVENT, WIFI_EVENT_DRIVER_SCAN_COMPLETE}, |
| {WLAN_PE_DIAG_DISASSOC_REQ_EVENT, WIFI_EVENT_DISASSOCIATION_REQUESTED}, |
| {WLAN_PE_DIAG_ASSOC_REQ_EVENT, WIFI_EVENT_RE_ASSOCIATION_REQUESTED}, |
| {WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, WIFI_EVENT_ROAM_AUTH_STARTED}, |
| {WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, WIFI_EVENT_ROAM_AUTH_COMPLETE}, |
| {WLAN_PE_DIAG_ROAM_ASSOC_START_EVENT, WIFI_EVENT_ROAM_ASSOC_STARTED}, |
| {WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, WIFI_EVENT_ROAM_ASSOC_COMPLETE}, |
| {WLAN_PE_DIAG_SWITCH_CHL_REQ_EVENT, WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT}, |
| {WLAN_PE_DIAG_ASSOC_TIMEOUT, WIFI_EVENT_ASSOC_TIMEOUT}, |
| {WLAN_PE_DIAG_AUTH_TIMEOUT, WIFI_EVENT_AUTH_TIMEOUT}, |
| }; |
| |
| tlv_log* addLoggerTlv(u16 type, u16 length, u8* value, tlv_log *pOutTlv) |
| { |
| |
| pOutTlv->tag = type; |
| pOutTlv->length = length; |
| memcpy(&pOutTlv->value[0], value, length); |
| |
| return((tlv_log *)((u8 *)pOutTlv + sizeof(tlv_log) + length)); |
| } |
| |
| int add_reason_code_tag(tlv_log **tlvs, u16 reason_code) |
| { |
| *tlvs = addLoggerTlv(WIFI_TAG_REASON_CODE, sizeof(u16), |
| (u8 *)&reason_code, *tlvs); |
| return (sizeof(tlv_log) + sizeof(u16)); |
| } |
| |
| int add_status_tag(tlv_log **tlvs, int status) |
| { |
| *tlvs = addLoggerTlv(WIFI_TAG_STATUS, sizeof(int), |
| (u8 *)&status, *tlvs); |
| return (sizeof(tlv_log) + sizeof(int)); |
| } |
| |
| static wifi_error update_connectivity_ring_buf(hal_info *info, |
| wifi_ring_buffer_entry *rbe, |
| u32 size) |
| { |
| struct timeval time; |
| u32 total_length = size + sizeof(wifi_ring_buffer_entry); |
| |
| rbe->entry_size = size; |
| rbe->flags = RING_BUFFER_ENTRY_FLAGS_HAS_BINARY | |
| RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP; |
| rbe->type = ENTRY_TYPE_CONNECT_EVENT; |
| gettimeofday(&time,NULL); |
| rbe->timestamp = (u64)time.tv_usec + (u64)time.tv_sec * 1000 * 1000; |
| |
| /* Write if verbose level and handler are set */ |
| if (info->rb_infos[CONNECTIVITY_EVENTS_RB_ID].verbose_level >= 1 && |
| info->on_ring_buffer_data) { |
| return ring_buffer_write(&info->rb_infos[CONNECTIVITY_EVENTS_RB_ID], |
| (u8*)rbe, total_length, 1, total_length); |
| } |
| |
| return WIFI_SUCCESS; |
| } |
| |
| #define SCAN_CAP_ENTRY_SIZE 1024 |
| static wifi_error process_log_extscan_capabilities(hal_info *info, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| wlan_ext_scan_capabilities_payload_type *pScanCapabilities; |
| wifi_gscan_capabilities gscan_cap; |
| gscan_capabilities_vendor_data_t cap_vendor_data; |
| memset(&cap_vendor_data, 0, sizeof(cap_vendor_data)); |
| |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[SCAN_CAP_ENTRY_SIZE]; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, SCAN_CAP_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_CAPABILITIES; |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| pScanCapabilities = (wlan_ext_scan_capabilities_payload_type *)buf; |
| pTlv = addLoggerTlv(WIFI_TAG_REQUEST_ID, |
| sizeof(pScanCapabilities->request_id), |
| (u8 *)&pScanCapabilities->request_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pScanCapabilities->request_id); |
| |
| gscan_cap.max_scan_cache_size = |
| pScanCapabilities->extscan_cache_capabilities.scan_cache_entry_size; |
| gscan_cap.max_scan_buckets = |
| pScanCapabilities->extscan_cache_capabilities.max_buckets; |
| gscan_cap.max_ap_cache_per_scan = |
| pScanCapabilities->extscan_cache_capabilities.max_bssid_per_scan; |
| gscan_cap.max_rssi_sample_size = FEATURE_NOT_SUPPORTED; |
| gscan_cap.max_scan_reporting_threshold = |
| pScanCapabilities->extscan_cache_capabilities.max_table_usage_threshold; |
| gscan_cap.max_hotlist_bssids = |
| pScanCapabilities->extscan_hotlist_monitor_capabilities.max_hotlist_entries; |
| gscan_cap.max_hotlist_ssids = |
| pScanCapabilities->extscan_capabilities.num_extscan_hotlist_ssid; |
| gscan_cap.max_significant_wifi_change_aps = FEATURE_NOT_SUPPORTED; |
| gscan_cap.max_bssid_history_entries = FEATURE_NOT_SUPPORTED; |
| gscan_cap.max_number_epno_networks = |
| pScanCapabilities->extscan_capabilities.num_epno_networks; |
| gscan_cap.max_number_epno_networks_by_ssid = |
| pScanCapabilities->extscan_capabilities.num_epno_networks; |
| gscan_cap.max_number_of_white_listed_ssid = |
| pScanCapabilities->extscan_capabilities.num_roam_ssid_whitelist; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_GSCAN_CAPABILITIES, |
| sizeof(wifi_gscan_capabilities), |
| (u8 *)&gscan_cap, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(wifi_gscan_capabilities); |
| |
| cap_vendor_data.hotlist_mon_table_id = |
| pScanCapabilities->extscan_hotlist_monitor_capabilities.table_id; |
| cap_vendor_data.wlan_hotlist_entry_size = |
| pScanCapabilities->extscan_hotlist_monitor_capabilities.wlan_hotlist_entry_size; |
| cap_vendor_data.cache_cap_table_id = |
| pScanCapabilities->extscan_cache_capabilities.table_id; |
| cap_vendor_data.requestor_id = |
| pScanCapabilities->extscan_capabilities.requestor_id; |
| cap_vendor_data.vdev_id = |
| pScanCapabilities->extscan_capabilities.vdev_id; |
| cap_vendor_data.num_extscan_cache_tables = |
| pScanCapabilities->extscan_capabilities.num_extscan_cache_tables; |
| cap_vendor_data.num_wlan_change_monitor_tables = |
| pScanCapabilities->extscan_capabilities.num_wlan_change_monitor_tables; |
| cap_vendor_data.num_hotlist_monitor_tables = |
| pScanCapabilities->extscan_capabilities.num_hotlist_monitor_tables; |
| cap_vendor_data.rtt_one_sided_supported = |
| pScanCapabilities->extscan_capabilities.rtt_one_sided_supported; |
| cap_vendor_data.rtt_11v_supported = |
| pScanCapabilities->extscan_capabilities.rtt_11v_supported; |
| cap_vendor_data.rtt_ftm_supported = |
| pScanCapabilities->extscan_capabilities.rtt_ftm_supported; |
| cap_vendor_data.num_extscan_cache_capabilities = |
| pScanCapabilities->extscan_capabilities.num_extscan_cache_capabilities; |
| cap_vendor_data.num_extscan_wlan_change_capabilities = |
| pScanCapabilities->extscan_capabilities.num_extscan_wlan_change_capabilities; |
| cap_vendor_data.num_extscan_hotlist_capabilities = |
| pScanCapabilities->extscan_capabilities.num_extscan_hotlist_capabilities; |
| cap_vendor_data.num_roam_bssid_blacklist = |
| pScanCapabilities->extscan_capabilities.num_roam_bssid_blacklist; |
| cap_vendor_data.num_roam_bssid_preferred_list = |
| pScanCapabilities->extscan_capabilities.num_roam_bssid_preferred_list; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(gscan_capabilities_vendor_data_t), |
| (u8 *)&cap_vendor_data, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(gscan_capabilities_vendor_data_t); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write ext scan capabilities event into ring buffer"); |
| } |
| return status; |
| } |
| |
| static wifi_error process_bt_coex_scan_event(hal_info *info, |
| u32 id, u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| if (id == EVENT_WLAN_BT_COEX_BT_SCAN_START) { |
| wlan_bt_coex_bt_scan_start_payload_type *pBtScanStart; |
| bt_coex_bt_scan_start_vendor_data_t btScanStartVenData; |
| |
| pConnectEvent->event = WIFI_EVENT_BT_COEX_BT_SCAN_START; |
| |
| pBtScanStart = (wlan_bt_coex_bt_scan_start_payload_type *)buf; |
| btScanStartVenData.scan_type = pBtScanStart->scan_type; |
| btScanStartVenData.scan_bitmap = pBtScanStart->scan_bitmap; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(bt_coex_bt_scan_start_vendor_data_t), |
| (u8 *)&btScanStartVenData, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(bt_coex_bt_scan_start_vendor_data_t); |
| } else if(id == EVENT_WLAN_BT_COEX_BT_SCAN_STOP) { |
| wlan_bt_coex_bt_scan_stop_payload_type *pBtScanStop; |
| bt_coex_bt_scan_stop_vendor_data_t btScanStopVenData; |
| |
| pConnectEvent->event = WIFI_EVENT_BT_COEX_BT_SCAN_STOP; |
| |
| pBtScanStop = (wlan_bt_coex_bt_scan_stop_payload_type *)buf; |
| btScanStopVenData.scan_type = pBtScanStop->scan_type; |
| btScanStopVenData.scan_bitmap = pBtScanStop->scan_bitmap; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(bt_coex_bt_scan_stop_vendor_data_t), |
| (u8 *)&btScanStopVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(bt_coex_bt_scan_stop_vendor_data_t); |
| } |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write bt_coex_scan event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_bt_coex_event(hal_info *info, u32 id, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| u8 link_id, link_state, link_role, link_type = 0, Rsco = 0; |
| u16 Tsco = 0; |
| wifi_error status; |
| bt_coex_hid_vendor_data_t btCoexHidVenData; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| switch (id) { |
| case EVENT_WLAN_BT_COEX_BT_SCO_START: |
| { |
| wlan_bt_coex_bt_sco_start_payload_type *pBtCoexStartPL; |
| pBtCoexStartPL = (wlan_bt_coex_bt_sco_start_payload_type *)buf; |
| |
| link_id = pBtCoexStartPL->link_id; |
| link_state = pBtCoexStartPL->link_state; |
| link_role = pBtCoexStartPL->link_role; |
| link_type = pBtCoexStartPL->link_type; |
| Tsco = pBtCoexStartPL->Tsco; |
| Rsco = pBtCoexStartPL->Rsco; |
| |
| pConnectEvent->event = WIFI_EVENT_BT_COEX_BT_SCO_START; |
| } |
| break; |
| case EVENT_WLAN_BT_COEX_BT_SCO_STOP: |
| { |
| wlan_bt_coex_bt_sco_stop_payload_type *pBtCoexStopPL; |
| pBtCoexStopPL = (wlan_bt_coex_bt_sco_stop_payload_type *)buf; |
| |
| link_id = pBtCoexStopPL->link_id; |
| link_state = pBtCoexStopPL->link_state; |
| link_role = pBtCoexStopPL->link_role; |
| link_type = pBtCoexStopPL->link_type; |
| Tsco = pBtCoexStopPL->Tsco; |
| Rsco = pBtCoexStopPL->Rsco; |
| |
| pConnectEvent->event = WIFI_EVENT_BT_COEX_BT_SCO_STOP; |
| } |
| break; |
| case EVENT_WLAN_BT_COEX_BT_HID_START: |
| { |
| wlan_bt_coex_bt_hid_start_payload_type *pBtCoexHidStartPL; |
| pBtCoexHidStartPL = (wlan_bt_coex_bt_hid_start_payload_type *)buf; |
| |
| link_id = pBtCoexHidStartPL->link_id; |
| link_state = pBtCoexHidStartPL->link_state; |
| link_role = pBtCoexHidStartPL->link_role; |
| btCoexHidVenData.Tsniff = pBtCoexHidStartPL->Tsniff; |
| btCoexHidVenData.attempts = pBtCoexHidStartPL->attempts; |
| |
| pConnectEvent->event = WIFI_EVENT_BT_COEX_BT_HID_START; |
| } |
| break; |
| case EVENT_WLAN_BT_COEX_BT_HID_STOP: |
| { |
| wlan_bt_coex_bt_hid_stop_payload_type *pBtCoexHidStopPL; |
| pBtCoexHidStopPL = (wlan_bt_coex_bt_hid_stop_payload_type *)buf; |
| |
| link_id = pBtCoexHidStopPL->link_id; |
| link_state = pBtCoexHidStopPL->link_state; |
| link_role = pBtCoexHidStopPL->link_role; |
| btCoexHidVenData.Tsniff = pBtCoexHidStopPL->Tsniff; |
| btCoexHidVenData.attempts = pBtCoexHidStopPL->attempts; |
| |
| pConnectEvent->event = WIFI_EVENT_BT_COEX_BT_HID_STOP; |
| } |
| break; |
| default: |
| return WIFI_SUCCESS; |
| } |
| |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_LINK_ID, sizeof(link_id), &link_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(link_id); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_LINK_ROLE, sizeof(link_role), |
| &link_role, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(link_role); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_LINK_STATE, sizeof(link_state), |
| &link_state, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(link_state); |
| |
| if ((pConnectEvent->event == EVENT_WLAN_BT_COEX_BT_SCO_START) || |
| (pConnectEvent->event == EVENT_WLAN_BT_COEX_BT_SCO_STOP)) { |
| pTlv = addLoggerTlv(WIFI_TAG_LINK_TYPE, sizeof(link_type), |
| &link_type, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(link_type); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_TSCO, sizeof(Tsco), (u8 *)&Tsco, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(Tsco); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_RSCO, sizeof(Rsco), &Rsco, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(Rsco); |
| } else if ((pConnectEvent->event == EVENT_WLAN_BT_COEX_BT_HID_START) || |
| (pConnectEvent->event == EVENT_WLAN_BT_COEX_BT_HID_STOP)) { |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(bt_coex_hid_vendor_data_t), |
| (u8 *)&btCoexHidVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(bt_coex_hid_vendor_data_t); |
| } |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write bt_coex_event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_extscan_event(hal_info *info, u32 id, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| switch (id) { |
| case EVENT_WLAN_EXTSCAN_CYCLE_STARTED: |
| { |
| ext_scan_cycle_vendor_data_t extScanCycleVenData; |
| wlan_ext_scan_cycle_started_payload_type *pExtScanCycleStarted; |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_CYCLE_STARTED; |
| pExtScanCycleStarted = |
| (wlan_ext_scan_cycle_started_payload_type *)buf; |
| pTlv = addLoggerTlv(WIFI_TAG_SCAN_ID, sizeof(u32), |
| (u8 *)&pExtScanCycleStarted->scan_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(u32); |
| |
| extScanCycleVenData.timer_tick = pExtScanCycleStarted->timer_tick; |
| extScanCycleVenData.scheduled_bucket_mask = |
| pExtScanCycleStarted->scheduled_bucket_mask; |
| extScanCycleVenData.scan_cycle_count = |
| pExtScanCycleStarted->scan_cycle_count; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(ext_scan_cycle_vendor_data_t), |
| (u8 *)&extScanCycleVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(ext_scan_cycle_vendor_data_t); |
| } |
| break; |
| case EVENT_WLAN_EXTSCAN_CYCLE_COMPLETED: |
| { |
| ext_scan_cycle_vendor_data_t extScanCycleVenData; |
| wlan_ext_scan_cycle_completed_payload_type *pExtScanCycleCompleted; |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_CYCLE_COMPLETED; |
| pExtScanCycleCompleted = |
| (wlan_ext_scan_cycle_completed_payload_type *)buf; |
| pTlv = addLoggerTlv(WIFI_TAG_SCAN_ID, sizeof(u32), |
| (u8 *)&pExtScanCycleCompleted->scan_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(u32); |
| |
| extScanCycleVenData.timer_tick = pExtScanCycleCompleted->timer_tick; |
| extScanCycleVenData.scheduled_bucket_mask = |
| pExtScanCycleCompleted->scheduled_bucket_mask; |
| extScanCycleVenData.scan_cycle_count = |
| pExtScanCycleCompleted->scan_cycle_count; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(ext_scan_cycle_vendor_data_t), |
| (u8 *)&extScanCycleVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(ext_scan_cycle_vendor_data_t); |
| } |
| break; |
| case EVENT_WLAN_EXTSCAN_BUCKET_STARTED: |
| { |
| wlan_ext_scan_bucket_started_payload_type *pExtScanBucketStarted; |
| u32 bucket_id; |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_BUCKET_STARTED; |
| pExtScanBucketStarted = |
| (wlan_ext_scan_bucket_started_payload_type *)buf; |
| bucket_id = (u32)pExtScanBucketStarted->bucket_id; |
| pTlv = addLoggerTlv(WIFI_TAG_BUCKET_ID, sizeof(u32), |
| (u8 *)&bucket_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(u32); |
| } |
| break; |
| case EVENT_WLAN_EXTSCAN_BUCKET_COMPLETED: |
| { |
| wlan_ext_scan_bucket_completed_payload_type *pExtScanBucketCmpleted; |
| u32 bucket_id; |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_BUCKET_COMPLETED; |
| pExtScanBucketCmpleted = |
| (wlan_ext_scan_bucket_completed_payload_type *)buf; |
| bucket_id = (u32)pExtScanBucketCmpleted->bucket_id; |
| pTlv = addLoggerTlv(WIFI_TAG_BUCKET_ID, sizeof(u32), |
| (u8 *)&bucket_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(u32); |
| } |
| break; |
| case EVENT_WLAN_EXTSCAN_FEATURE_STOP: |
| { |
| wlan_ext_scan_feature_stop_payload_type *pExtScanStop; |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_STOP; |
| pExtScanStop = (wlan_ext_scan_feature_stop_payload_type *)buf; |
| pTlv = addLoggerTlv(WIFI_TAG_REQUEST_ID, |
| sizeof(pExtScanStop->request_id), |
| (u8 *)&pExtScanStop->request_id, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(wlan_ext_scan_feature_stop_payload_type); |
| } |
| break; |
| case EVENT_WLAN_EXTSCAN_RESULTS_AVAILABLE: |
| { |
| wlan_ext_scan_results_available_payload_type *pExtScanResultsAvail; |
| ext_scan_results_available_vendor_data_t extScanResultsAvailVenData; |
| u32 request_id; |
| pConnectEvent->event = WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE; |
| pExtScanResultsAvail = |
| (wlan_ext_scan_results_available_payload_type *)buf; |
| request_id = pExtScanResultsAvail->request_id; |
| pTlv = addLoggerTlv(WIFI_TAG_REQUEST_ID, sizeof(u32), |
| (u8 *)&request_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(u32); |
| |
| extScanResultsAvailVenData.table_type = |
| pExtScanResultsAvail->table_type; |
| extScanResultsAvailVenData.entries_in_use = |
| pExtScanResultsAvail->entries_in_use; |
| extScanResultsAvailVenData.maximum_entries = |
| pExtScanResultsAvail->maximum_entries; |
| extScanResultsAvailVenData.scan_count_after_getResults = |
| pExtScanResultsAvail->scan_count_after_getResults; |
| extScanResultsAvailVenData.threshold_num_scans = |
| pExtScanResultsAvail->threshold_num_scans; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(ext_scan_results_available_vendor_data_t), |
| (u8 *)&extScanResultsAvailVenData, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(ext_scan_results_available_vendor_data_t); |
| } |
| break; |
| } |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write ext_scan event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_addba_success_event(hal_info *info, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wlan_add_block_ack_success_payload_type *pAddBASuccess; |
| addba_success_vendor_data_t addBASuccessVenData; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| pAddBASuccess = (wlan_add_block_ack_success_payload_type *)buf; |
| |
| addBASuccessVenData.ucBaTid = pAddBASuccess->ucBaTid; |
| addBASuccessVenData.ucBaBufferSize = pAddBASuccess->ucBaBufferSize; |
| addBASuccessVenData.ucBaSSN = pAddBASuccess->ucBaSSN; |
| addBASuccessVenData.fInitiator = pAddBASuccess->fInitiator; |
| |
| pConnectEvent->event = WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE; |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_ADDR, sizeof(pAddBASuccess->ucBaPeerMac), |
| (u8 *)pAddBASuccess->ucBaPeerMac, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pAddBASuccess->ucBaPeerMac); |
| |
| tot_len += add_status_tag(&pTlv, (int)ADDBA_SUCCESS); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(addba_success_vendor_data_t), |
| (u8 *)&addBASuccessVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(addba_success_vendor_data_t); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write addba event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_addba_failed_event(hal_info *info, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wlan_add_block_ack_failed_payload_type *pAddBAFailed; |
| addba_failed_vendor_data_t addBAFailedVenData; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| pAddBAFailed = (wlan_add_block_ack_failed_payload_type *)buf; |
| addBAFailedVenData.ucBaTid = pAddBAFailed->ucBaTid; |
| addBAFailedVenData.fInitiator = pAddBAFailed->fInitiator; |
| |
| pConnectEvent->event = WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE; |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_ADDR, sizeof(pAddBAFailed->ucBaPeerMac), |
| (u8 *)pAddBAFailed->ucBaPeerMac, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pAddBAFailed->ucBaPeerMac); |
| |
| tot_len += add_status_tag(&pTlv, (int)ADDBA_FAILURE); |
| |
| tot_len += add_reason_code_tag(&pTlv, (u16)pAddBAFailed->ucReasonCode); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(addba_failed_vendor_data_t), |
| (u8 *)&addBAFailedVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(addba_failed_vendor_data_t); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write addba event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_roam_event(hal_info *info, u32 id, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| switch (id) |
| { |
| case EVENT_WLAN_ROAM_SCAN_STARTED: |
| { |
| wlan_roam_scan_started_payload_type *pRoamScanStarted; |
| roam_scan_started_vendor_data_t roamScanStartedVenData; |
| pConnectEvent->event = WIFI_EVENT_ROAM_SCAN_STARTED; |
| pRoamScanStarted = (wlan_roam_scan_started_payload_type *)buf; |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_SCAN_ID, |
| sizeof(pRoamScanStarted->scan_id), |
| (u8 *)&pRoamScanStarted->scan_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pRoamScanStarted->scan_id); |
| roamScanStartedVenData.roam_scan_flags = |
| pRoamScanStarted->roam_scan_flags; |
| roamScanStartedVenData.cur_rssi = pRoamScanStarted->cur_rssi; |
| memcpy(roamScanStartedVenData.scan_params, |
| pRoamScanStarted->scan_params, |
| sizeof(roamScanStartedVenData.scan_params)); |
| memcpy(roamScanStartedVenData.scan_channels, |
| pRoamScanStarted->scan_channels, |
| sizeof(roamScanStartedVenData.scan_channels)); |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(roam_scan_started_vendor_data_t), |
| (u8 *)&roamScanStartedVenData, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(roam_scan_started_vendor_data_t); |
| } |
| break; |
| case EVENT_WLAN_ROAM_SCAN_COMPLETE: |
| { |
| wlan_roam_scan_complete_payload_type *pRoamScanComplete; |
| roam_scan_complete_vendor_data_t roamScanCompleteVenData; |
| pConnectEvent->event = WIFI_EVENT_ROAM_SCAN_COMPLETE; |
| pRoamScanComplete = (wlan_roam_scan_complete_payload_type *)buf; |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_SCAN_ID, |
| sizeof(pRoamScanComplete->scan_id), |
| (u8 *)&pRoamScanComplete->scan_id, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pRoamScanComplete->scan_id); |
| |
| roamScanCompleteVenData.reason = pRoamScanComplete->reason; |
| roamScanCompleteVenData.completion_flags = |
| pRoamScanComplete->completion_flags; |
| roamScanCompleteVenData.num_candidate = |
| pRoamScanComplete->num_candidate; |
| roamScanCompleteVenData.flags = pRoamScanComplete->flags; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(roam_scan_complete_vendor_data_t), |
| (u8 *)&roamScanCompleteVenData, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(roam_scan_complete_vendor_data_t); |
| } |
| break; |
| case EVENT_WLAN_ROAM_CANDIDATE_FOUND: |
| { |
| wlan_roam_candidate_found_payload_type *pRoamCandidateFound; |
| roam_candidate_found_vendor_data_t roamCandidateFoundVendata; |
| memset(&roamCandidateFoundVendata, 0, |
| sizeof(roamCandidateFoundVendata)); |
| pConnectEvent->event = WIFI_EVENT_ROAM_CANDIDATE_FOUND; |
| pRoamCandidateFound = (wlan_roam_candidate_found_payload_type *)buf; |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_CHANNEL, |
| sizeof(pRoamCandidateFound->channel), |
| (u8 *)&pRoamCandidateFound->channel, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pRoamCandidateFound->channel); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_RSSI, |
| sizeof(pRoamCandidateFound->rssi), |
| (u8 *)&pRoamCandidateFound->rssi, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pRoamCandidateFound->rssi); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_BSSID, |
| sizeof(pRoamCandidateFound->bssid), |
| (u8 *)pRoamCandidateFound->bssid, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pRoamCandidateFound->bssid); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_SSID, |
| sizeof(pRoamCandidateFound->ssid), |
| (u8 *)pRoamCandidateFound->ssid, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pRoamCandidateFound->ssid); |
| |
| roamCandidateFoundVendata.auth_mode = |
| pRoamCandidateFound->auth_mode; |
| roamCandidateFoundVendata.ucast_cipher = |
| pRoamCandidateFound->ucast_cipher; |
| roamCandidateFoundVendata.mcast_cipher = |
| pRoamCandidateFound->mcast_cipher; |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(roam_candidate_found_vendor_data_t), |
| (u8 *)&roamCandidateFoundVendata, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(roam_candidate_found_vendor_data_t); |
| } |
| break; |
| case EVENT_WLAN_ROAM_SCAN_CONFIG: |
| { |
| wlan_roam_scan_config_payload_type *pRoamScanConfig; |
| roam_scan_config_vendor_data_t roamScanConfigVenData; |
| |
| pConnectEvent->event = WIFI_EVENT_ROAM_SCAN_CONFIG; |
| pRoamScanConfig = (wlan_roam_scan_config_payload_type *)buf; |
| |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| roamScanConfigVenData.flags = pRoamScanConfig->flags; |
| memcpy(roamScanConfigVenData.roam_scan_config, |
| pRoamScanConfig->roam_scan_config, |
| sizeof(roamScanConfigVenData.roam_scan_config)); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(roam_scan_config_vendor_data_t), |
| (u8 *)&roamScanConfigVenData, pTlv); |
| tot_len += sizeof(tlv_log) + |
| sizeof(roam_scan_config_vendor_data_t); |
| } |
| break; |
| } |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write roam event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| wifi_error process_firmware_prints(hal_info *info, u8 *buf, u16 length) |
| { |
| wifi_ring_buffer_entry rb_entry_hdr; |
| struct timeval time; |
| wifi_error status; |
| |
| rb_entry_hdr.entry_size = length; |
| rb_entry_hdr.flags = RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP; |
| rb_entry_hdr.type = ENTRY_TYPE_DATA; |
| gettimeofday(&time, NULL); |
| rb_entry_hdr.timestamp = (u64)time.tv_usec + (u64)time.tv_sec * 1000 * 1000; |
| |
| /* Write if verbose and handler is set */ |
| if (info->rb_infos[FIRMWARE_PRINTS_RB_ID].verbose_level >= 1 && |
| info->on_ring_buffer_data) { |
| /* Write header and payload separately to avoid |
| * complete payload memcpy */ |
| if (sizeof(wifi_ring_buffer_entry) + length > 2000) { |
| ALOGE("Invalid length of buffer wifi_ring_buffer_entry size: %zu length %u ",sizeof(wifi_ring_buffer_entry), length); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| status = ring_buffer_write(&info->rb_infos[FIRMWARE_PRINTS_RB_ID], |
| (u8*)&rb_entry_hdr, |
| sizeof(wifi_ring_buffer_entry), |
| 0, |
| sizeof(wifi_ring_buffer_entry) + length); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write firmware prints rb header %d", status); |
| return status; |
| } |
| status = ring_buffer_write(&info->rb_infos[FIRMWARE_PRINTS_RB_ID], |
| buf, length, 1, length); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write firmware prints rb payload %d", status); |
| return status; |
| } |
| } |
| |
| return WIFI_SUCCESS; |
| } |
| |
| static wifi_error process_beacon_received_event(hal_info *info, |
| u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wlan_beacon_received_payload_type *pBeaconRcvd; |
| u32 rssi; |
| wifi_error status; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| pBeaconRcvd = (wlan_beacon_received_payload_type *)buf; |
| |
| pConnectEvent->event = WIFI_EVENT_BEACON_RECEIVED; |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_BSSID, sizeof(pBeaconRcvd->bssid), |
| (u8 *)pBeaconRcvd->bssid, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pBeaconRcvd->bssid); |
| |
| rssi = get_rssi(pBeaconRcvd->beacon_rssi); |
| pTlv = addLoggerTlv(WIFI_TAG_RSSI, |
| sizeof(rssi), (u8 *)&rssi, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pBeaconRcvd->beacon_rssi); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write addba event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_fw_diag_msg(hal_info *info, u8* buf, u32 length) |
| { |
| u32 count = 0, id; |
| u32 payloadlen = 0; |
| u16 hdr_size = 0; |
| wifi_error status; |
| fw_diag_msg_fixed_hdr_t *diag_msg_fixed_hdr; |
| fw_diag_msg_hdr_t *diag_msg_hdr; |
| fw_diag_msg_hdr_v2_t *diag_msg_hdr_v2; |
| u8 *payload = NULL; |
| |
| buf += 4; |
| length -= 4; |
| |
| while ((info && !info->clean_up) |
| && (length > (count + sizeof(fw_diag_msg_fixed_hdr_t)))) { |
| diag_msg_fixed_hdr = (fw_diag_msg_fixed_hdr_t *)(buf + count); |
| |
| if (diag_msg_fixed_hdr->diag_event_type > WLAN_DIAG_TYPE_LEGACY_MSG) { |
| hdr_size = sizeof(fw_diag_msg_hdr_v2_t); |
| } else { |
| hdr_size = sizeof(fw_diag_msg_hdr_t); |
| } |
| |
| if ((count + hdr_size) > length) |
| { |
| ALOGE("process_fw_diag_msg (%d) - possible buffer over access, length=%d count=%d hdr_size=%d", |
| diag_msg_fixed_hdr->diag_event_type, length, count, hdr_size); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| switch (diag_msg_fixed_hdr->diag_event_type) { |
| case WLAN_DIAG_TYPE_EVENT: |
| case WLAN_DIAG_TYPE_EVENT_V2: |
| { |
| if (WLAN_DIAG_TYPE_EVENT == |
| diag_msg_fixed_hdr->diag_event_type) { |
| diag_msg_hdr = (fw_diag_msg_hdr_t *)diag_msg_fixed_hdr; |
| id = diag_msg_hdr->diag_id; |
| payloadlen = diag_msg_hdr->u.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_t); |
| payload = diag_msg_hdr->payload; |
| } else { |
| diag_msg_hdr_v2 = |
| (fw_diag_msg_hdr_v2_t *)diag_msg_fixed_hdr; |
| id = diag_msg_hdr_v2->diag_id; |
| payloadlen = diag_msg_hdr_v2->u.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_v2_t); |
| payload = diag_msg_hdr_v2->payload; |
| } |
| if ((count + hdr_size + payloadlen) > length) { |
| ALOGE("WLAN_DIAG_TYPE_EVENT - possible buffer over access, length=%d count=%d hdr_size=%d payload len=%d", |
| length, count, hdr_size, payloadlen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| switch (id) { |
| case EVENT_WLAN_BT_COEX_BT_SCO_START: |
| case EVENT_WLAN_BT_COEX_BT_SCO_STOP: |
| case EVENT_WLAN_BT_COEX_BT_HID_START: |
| case EVENT_WLAN_BT_COEX_BT_HID_STOP: |
| status = process_bt_coex_event(info, id, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process bt_coex event"); |
| return status; |
| } |
| break; |
| case EVENT_WLAN_BT_COEX_BT_SCAN_START: |
| case EVENT_WLAN_BT_COEX_BT_SCAN_STOP: |
| status = process_bt_coex_scan_event(info, id, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process bt_coex_scan event"); |
| return status; |
| } |
| break; |
| case EVENT_WLAN_EXTSCAN_CYCLE_STARTED: |
| case EVENT_WLAN_EXTSCAN_CYCLE_COMPLETED: |
| case EVENT_WLAN_EXTSCAN_BUCKET_STARTED: |
| case EVENT_WLAN_EXTSCAN_BUCKET_COMPLETED: |
| case EVENT_WLAN_EXTSCAN_FEATURE_STOP: |
| case EVENT_WLAN_EXTSCAN_RESULTS_AVAILABLE: |
| status = process_extscan_event(info, id, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process extscan event"); |
| return status; |
| } |
| break; |
| case EVENT_WLAN_ROAM_SCAN_STARTED: |
| case EVENT_WLAN_ROAM_SCAN_COMPLETE: |
| case EVENT_WLAN_ROAM_CANDIDATE_FOUND: |
| case EVENT_WLAN_ROAM_SCAN_CONFIG: |
| status = process_roam_event(info, id, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process roam event"); |
| return status; |
| } |
| break; |
| case EVENT_WLAN_ADD_BLOCK_ACK_SUCCESS: |
| status = process_addba_success_event(info, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process addba success event"); |
| return status; |
| } |
| break; |
| case EVENT_WLAN_ADD_BLOCK_ACK_FAILED: |
| status = process_addba_failed_event(info, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process addba failed event"); |
| return status; |
| } |
| break; |
| case EVENT_WLAN_BEACON_EVENT: |
| status = process_beacon_received_event(info, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process beacon received event"); |
| return status; |
| } |
| break; |
| default: |
| return WIFI_SUCCESS; |
| } |
| } |
| break; |
| case WLAN_DIAG_TYPE_LOG: |
| case WLAN_DIAG_TYPE_LOG_V2: |
| { |
| if (WLAN_DIAG_TYPE_LOG == diag_msg_fixed_hdr->diag_event_type) { |
| diag_msg_hdr = (fw_diag_msg_hdr_t *)diag_msg_fixed_hdr; |
| id = diag_msg_hdr->diag_id; |
| payloadlen = diag_msg_hdr->u.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_t); |
| payload = diag_msg_hdr->payload; |
| } else { |
| diag_msg_hdr_v2 = (fw_diag_msg_hdr_v2_t *)diag_msg_fixed_hdr; |
| id = diag_msg_hdr_v2->diag_id; |
| payloadlen = diag_msg_hdr_v2->u.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_v2_t); |
| payload = diag_msg_hdr_v2->payload; |
| } |
| if ((count + hdr_size + payloadlen) > length) { |
| ALOGE("WLAN_DIAG_TYPE_LOG - possible buffer over access, length=%d count=%d hdr_size=%d payload len=%d", |
| length, count, hdr_size, payloadlen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| switch (id) { |
| case LOG_WLAN_EXTSCAN_CAPABILITIES: |
| status = process_log_extscan_capabilities(info, |
| payload, |
| payloadlen); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to process extscan capabilities"); |
| return status; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| break; |
| case WLAN_DIAG_TYPE_MSG: |
| diag_msg_hdr = (fw_diag_msg_hdr_t *)diag_msg_fixed_hdr; |
| id = diag_msg_hdr->diag_id; |
| /* Length field is only one byte for WLAN_DIAG_TYPE_MSG */ |
| payloadlen = diag_msg_hdr->u.msg_hdr.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_t); |
| payload = diag_msg_hdr->payload; |
| if ((count + hdr_size + payloadlen) > length) { |
| ALOGE("WLAN_DIAG_TYPE_MSG - possible buffer over access, length=%d count=%d hdr_size=%d payload len=%d", |
| length, count, hdr_size, payloadlen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| process_firmware_prints(info, (u8 *)diag_msg_fixed_hdr, |
| payloadlen + hdr_size); |
| break; |
| case WLAN_DIAG_TYPE_MSG_V2: |
| diag_msg_hdr_v2 = (fw_diag_msg_hdr_v2_t *)diag_msg_fixed_hdr; |
| id = diag_msg_hdr_v2->diag_id; |
| /* Length field is only one byte for WLAN_DIAG_TYPE_MSG_V2 */ |
| payloadlen = diag_msg_hdr_v2->u.msg_hdr.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_v2_t); |
| payload = diag_msg_hdr_v2->payload; |
| if ((count + hdr_size + payloadlen) > length) { |
| ALOGE("WLAN_DIAG_TYPE_MSG_V2 - possible buffer over access, length=%d count=%d hdr_size=%d payload len=%d", |
| length, count, hdr_size, payloadlen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| process_firmware_prints(info, (u8 *)diag_msg_fixed_hdr, |
| payloadlen + hdr_size); |
| break; |
| case WLAN_DIAG_TYPE_CONFIG: |
| { |
| /* Base timestamp is part of this diag type */ |
| diag_msg_hdr = (fw_diag_msg_hdr_t *) diag_msg_fixed_hdr; |
| id = diag_msg_hdr->diag_id; |
| payload = diag_msg_hdr->payload; |
| payloadlen = diag_msg_hdr->u.payload_len; |
| hdr_size = sizeof(fw_diag_msg_hdr_t); |
| if ((count + hdr_size + payloadlen) > length) { |
| ALOGE("WLAN_DIAG_TYPE_CONFIG - possible buffer over access, length=%d count=%d hdr_size=%d payload len=%d", |
| length, count, hdr_size, payloadlen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| process_firmware_prints(info, (u8 *)diag_msg_hdr, |
| payloadlen + hdr_size); |
| } |
| break; |
| default: |
| return WIFI_SUCCESS; |
| } |
| count += payloadlen + hdr_size; |
| } |
| return WIFI_SUCCESS; |
| } |
| |
| static wifi_error remap_event(int in_event, int *out_event) |
| { |
| int i = 0; |
| while (i < MAX_CONNECTIVITY_EVENTS) { |
| if (events[i].q_event == in_event) { |
| *out_event = events[i].g_event; |
| return WIFI_SUCCESS; |
| } |
| i++; |
| } |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| static wifi_error process_wlan_pe_event(hal_info *info, u8* buf, int length) |
| { |
| wlan_pe_event_t *pWlanPeEvent; |
| pe_event_vendor_data_t peEventVenData; |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| tlv_log *pTlv; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| wifi_error status; |
| |
| pWlanPeEvent = (wlan_pe_event_t *)buf; |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| status = remap_event(pWlanPeEvent->event_type, |
| (int *)&pConnectEvent->event); |
| if (status != WIFI_SUCCESS) |
| return status; |
| |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_BSSID, sizeof(pWlanPeEvent->bssid), |
| (u8 *)pWlanPeEvent->bssid, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pWlanPeEvent->bssid); |
| |
| tot_len += add_status_tag(&pTlv, (int)pWlanPeEvent->status); |
| |
| pTlv = addLoggerTlv(WIFI_TAG_REASON_CODE, sizeof(pWlanPeEvent->reason_code), |
| (u8 *)&pWlanPeEvent->reason_code, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pWlanPeEvent->reason_code); |
| |
| peEventVenData.sme_state = pWlanPeEvent->sme_state; |
| peEventVenData.mlm_state = pWlanPeEvent->mlm_state; |
| |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(pe_event_vendor_data_t), |
| (u8 *)&peEventVenData, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pe_event_vendor_data_t); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write pe event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_wlan_eapol_event(hal_info *info, u8* buf, int length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wlan_eapol_event_t *pWlanEapolEvent; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| tlv_log *pTlv; |
| u32 eapol_msg_type = 0; |
| wifi_error status; |
| |
| pWlanEapolEvent = (wlan_eapol_event_t *)buf; |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| if (pWlanEapolEvent->event_sub_type == |
| WLAN_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED) |
| pConnectEvent->event = WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED; |
| else |
| pConnectEvent->event = WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED; |
| |
| pTlv = &pConnectEvent->tlvs[0]; |
| |
| if ((pWlanEapolEvent->eapol_key_info & EAPOL_MASK) == EAPOL_M1_MASK) |
| eapol_msg_type = 1; |
| else if ((pWlanEapolEvent->eapol_key_info & EAPOL_MASK) == EAPOL_M2_MASK) |
| eapol_msg_type = 2; |
| else if ((pWlanEapolEvent->eapol_key_info & EAPOL_MASK) == EAPOL_M3_MASK) |
| eapol_msg_type = 3; |
| else if ((pWlanEapolEvent->eapol_key_info & EAPOL_MASK) == EAPOL_M4_MASK) |
| eapol_msg_type = 4; |
| else |
| ALOGI("Unknown EAPOL message type \n"); |
| pTlv = addLoggerTlv(WIFI_TAG_EAPOL_MESSAGE_TYPE, sizeof(u32), |
| (u8 *)&eapol_msg_type, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(u32); |
| pTlv = addLoggerTlv(WIFI_TAG_ADDR1, sizeof(pWlanEapolEvent->dest_addr), |
| (u8 *)pWlanEapolEvent->dest_addr, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pWlanEapolEvent->dest_addr); |
| pTlv = addLoggerTlv(WIFI_TAG_ADDR2, sizeof(pWlanEapolEvent->src_addr), |
| (u8 *)pWlanEapolEvent->src_addr, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(pWlanEapolEvent->src_addr); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write eapol event into ring buffer"); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error process_wakelock_event(hal_info *info, u8* buf, int length) |
| { |
| wlan_wake_lock_event_t *pWlanWakeLockEvent; |
| wake_lock_event *pWakeLockEvent; |
| wifi_power_event *pPowerEvent; |
| tlv_log *pTlv; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| u16 len_ring_buffer_entry; |
| struct timeval time; |
| wifi_error status; |
| u8 wl_ring_buffer[RING_BUF_ENTRY_SIZE]; |
| u16 entry_size; |
| |
| pWlanWakeLockEvent = (wlan_wake_lock_event_t *)(buf); |
| entry_size = sizeof(wifi_power_event) + |
| sizeof(tlv_log) + |
| sizeof(wake_lock_event) + |
| pWlanWakeLockEvent->name_len + 1; |
| len_ring_buffer_entry = sizeof(wifi_ring_buffer_entry) + entry_size; |
| |
| if (len_ring_buffer_entry > RING_BUF_ENTRY_SIZE) { |
| pRingBufferEntry = (wifi_ring_buffer_entry *)malloc( |
| len_ring_buffer_entry); |
| if (pRingBufferEntry == NULL) { |
| ALOGE("%s: Failed to allocate memory", __FUNCTION__); |
| return WIFI_ERROR_OUT_OF_MEMORY; |
| } |
| } else { |
| pRingBufferEntry = (wifi_ring_buffer_entry *)wl_ring_buffer; |
| } |
| |
| pPowerEvent = (wifi_power_event *)(pRingBufferEntry + 1); |
| pPowerEvent->event = WIFI_TAG_WAKE_LOCK_EVENT; |
| |
| pTlv = &pPowerEvent->tlvs[0]; |
| pTlv->tag = WIFI_TAG_WAKE_LOCK_EVENT; |
| pTlv->length = sizeof(wake_lock_event) + |
| pWlanWakeLockEvent->name_len + 1; |
| |
| pWakeLockEvent = (wake_lock_event *)pTlv->value; |
| pWakeLockEvent->status = pWlanWakeLockEvent->status; |
| pWakeLockEvent->reason = pWlanWakeLockEvent->reason; |
| memcpy(pWakeLockEvent->name, pWlanWakeLockEvent->name, |
| pWlanWakeLockEvent->name_len); |
| |
| pRingBufferEntry->entry_size = entry_size; |
| pRingBufferEntry->flags = RING_BUFFER_ENTRY_FLAGS_HAS_BINARY | |
| RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP; |
| pRingBufferEntry->type = ENTRY_TYPE_POWER_EVENT; |
| gettimeofday(&time, NULL); |
| pRingBufferEntry->timestamp = (u64)time.tv_usec + (u64)time.tv_sec * 1000 * 1000; |
| |
| /* Write if verbose and handler is set */ |
| if (info->rb_infos[POWER_EVENTS_RB_ID].verbose_level >= 1 && |
| info->on_ring_buffer_data) { |
| status = ring_buffer_write(&info->rb_infos[POWER_EVENTS_RB_ID], |
| (u8*)pRingBufferEntry, |
| len_ring_buffer_entry, |
| 1, |
| len_ring_buffer_entry); |
| } else { |
| status = WIFI_SUCCESS; |
| } |
| |
| if ((u8 *)pRingBufferEntry != wl_ring_buffer) { |
| ALOGI("Message with more than RING_BUF_ENTRY_SIZE"); |
| free(pRingBufferEntry); |
| } |
| |
| return status; |
| } |
| |
| static void process_wlan_log_complete_event(hal_info *info, |
| u8* buf, |
| int length) |
| { |
| wlan_log_complete_event_t *lfd_event; |
| |
| ALOGV("Received log completion event from driver"); |
| lfd_event = (wlan_log_complete_event_t *)buf; |
| |
| push_out_all_ring_buffers(info); |
| |
| if (lfd_event->is_fatal == WLAN_LOG_TYPE_FATAL) { |
| ALOGE("Received log complete event, sending alert"); |
| send_alert(info, lfd_event->reason_code); |
| } |
| } |
| |
| static void process_wlan_data_stall_event(hal_info *info, |
| u8* buf, |
| int length) |
| { |
| wlan_data_stall_event_t *event; |
| int reason_code = 0; |
| |
| ALOGV("Received Data Stall Event from Driver"); |
| event = (wlan_data_stall_event_t *)buf; |
| ALOGE("Received Data Stall event, sending alert %d", event->reason); |
| if(event->reason >= MAX_EVENT_REASON_CODE) |
| reason_code = 0; |
| else |
| reason_code = event->reason; |
| |
| send_alert(info, DATA_STALL_OFFSET_REASON_CODE + reason_code); |
| } |
| |
| static void process_wlan_low_resource_failure(hal_info *info, |
| u8* buf, |
| u16 length) |
| { |
| wifi_ring_buffer_driver_connectivity_event *pConnectEvent; |
| wlan_low_resource_failure_event_t *pWlanResourceEvent; |
| resource_failure_vendor_data_t cap_vendor_data; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| u8 out_buf[RING_BUF_ENTRY_SIZE]; |
| int tot_len = sizeof(wifi_ring_buffer_driver_connectivity_event); |
| tlv_log *pTlv; |
| wifi_error status; |
| |
| pWlanResourceEvent = (wlan_low_resource_failure_event_t *)buf; |
| pRingBufferEntry = (wifi_ring_buffer_entry *)&out_buf[0]; |
| memset(pRingBufferEntry, 0, RING_BUF_ENTRY_SIZE); |
| pConnectEvent = (wifi_ring_buffer_driver_connectivity_event *) |
| (pRingBufferEntry + 1); |
| |
| pConnectEvent->event = WIFI_EVENT_MEM_ALLOC_FAILURE; |
| memset(&cap_vendor_data, 0, sizeof(resource_failure_vendor_data_t)); |
| |
| if (length > sizeof(resource_failure_vendor_data_t)) { |
| ALOGE("Received resource failure event of size : %d, whereas expected" |
| " size is <= %zu bytes", length, |
| sizeof(resource_failure_vendor_data_t)); |
| return; |
| } |
| memcpy(&cap_vendor_data, pWlanResourceEvent, length); |
| |
| pTlv = &pConnectEvent->tlvs[0]; |
| pTlv = addLoggerTlv(WIFI_TAG_VENDOR_SPECIFIC, |
| sizeof(resource_failure_vendor_data_t), |
| (u8 *)&cap_vendor_data, pTlv); |
| tot_len += sizeof(tlv_log) + sizeof(resource_failure_vendor_data_t); |
| |
| status = update_connectivity_ring_buf(info, pRingBufferEntry, tot_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write resource failure event into ring buffer"); |
| } |
| } |
| |
| static wifi_error update_stats_to_ring_buf(hal_info *info, |
| u8 *rb_entry, u32 size) |
| { |
| int num_records = 1; |
| wifi_ring_buffer_entry *pRingBufferEntry = |
| (wifi_ring_buffer_entry *)rb_entry; |
| struct timeval time; |
| |
| pRingBufferEntry->entry_size = size - sizeof(wifi_ring_buffer_entry); |
| pRingBufferEntry->flags = RING_BUFFER_ENTRY_FLAGS_HAS_BINARY | |
| RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP; |
| pRingBufferEntry->type = ENTRY_TYPE_PKT; |
| gettimeofday(&time,NULL); |
| pRingBufferEntry->timestamp = (u64)time.tv_usec + (u64)time.tv_sec * 1000 * 1000; |
| |
| // Write if verbose and handler is set |
| if ((info->rb_infos[PKT_STATS_RB_ID].verbose_level >= VERBOSE_DEBUG_PROBLEM) |
| && info->on_ring_buffer_data) { |
| ring_buffer_write(&info->rb_infos[PKT_STATS_RB_ID], |
| (u8*)pRingBufferEntry, |
| size, |
| num_records, |
| size); |
| } |
| |
| return WIFI_SUCCESS; |
| } |
| |
| static u8 cck_ratecode_mapping(u8 rate) |
| { |
| u8 rate_code = 0; |
| |
| switch (rate) { |
| case 0x1: |
| rate_code = 0x3; |
| break; |
| case 0x2: |
| case 0x5: |
| rate_code = 0x2; |
| break; |
| case 0x3: |
| case 0x6: |
| rate_code = 0x1; |
| break; |
| case 0x4: |
| case 0x7: |
| rate_code = 0x0; |
| break; |
| } |
| return rate_code; |
| } |
| |
| static u8 ofdm_ratecode_mapping(u8 rate) |
| { |
| u8 rate_code = 0; |
| |
| rate_code = rate - 8; |
| return rate_code; |
| } |
| |
| static u16 get_rate_v1(u16 mcs_r) |
| { |
| MCS mcs; |
| int index = 0; |
| u16 tx_rate = 0; |
| u8 nss; |
| |
| mcs.mcs = mcs_r; |
| nss = mcs.mcs_s.nss + 1; |
| |
| switch (mcs.mcs_s.preamble) { |
| case WIFI_HW_RATECODE_PREAM_OFDM: |
| for (index = 0; index < MAX_OFDM_MCS_IDX; index++) { |
| if ((mcs.mcs_s.rate & 0xF) == index) |
| tx_rate = (u16) ofdm_mcs_nss1[index].ofdm_rate[mcs.mcs_s.short_gi] / 1000; |
| } |
| break; |
| case WIFI_HW_RATECODE_PREAM_CCK: |
| for (index = 0; index < MAX_CCK_MCS_IDX; index++) { |
| if ((mcs.mcs_s.rate & 0xF) == index) |
| tx_rate = (u16) cck_mcs_nss1[index].cck_rate[mcs.mcs_s.short_gi] / 1000; |
| } |
| break; |
| case WIFI_HW_RATECODE_PREAM_HT: |
| if (nss == 1) { |
| for (index = 0; index < MAX_HT_MCS_IDX; index++) { |
| if (mcs.mcs_s.rate == index) { |
| if (mcs.mcs_s.bw == BW_20MHZ) |
| tx_rate = (u16) mcs_nss1[index].ht20_rate[mcs.mcs_s.short_gi] / 10; |
| if (mcs.mcs_s.bw == BW_40MHZ) |
| tx_rate = (u16) mcs_nss1[index].ht40_rate[mcs.mcs_s.short_gi] / 10; |
| } |
| } |
| } else if (nss == 2) { |
| for (index = 0; index < MAX_HT_MCS_IDX; index++) { |
| if (mcs.mcs_s.rate == index) { |
| if (mcs.mcs_s.bw == BW_20MHZ) |
| tx_rate = (u16) mcs_nss2[index].ht20_rate[mcs.mcs_s.short_gi] / 10; |
| if (mcs.mcs_s.bw == BW_40MHZ) |
| tx_rate = (u16) mcs_nss2[index].ht40_rate[mcs.mcs_s.short_gi] / 10; |
| } |
| } |
| } else { |
| ALOGE("Unexpected nss %d", nss); |
| } |
| break; |
| case WIFI_HW_RATECODE_PREAM_VHT: |
| if (nss == 1) { |
| for (index = 0; index < MAX_VHT_MCS_IDX; index++) { |
| if (mcs.mcs_s.rate == index) { |
| if (mcs.mcs_s.bw == BW_20MHZ) |
| tx_rate = (u16) vht_mcs_nss1[index].ht20_rate[mcs.mcs_s.short_gi] / 10; |
| if (mcs.mcs_s.bw == BW_40MHZ) |
| tx_rate = (u16) vht_mcs_nss1[index].ht40_rate[mcs.mcs_s.short_gi] / 10; |
| if (mcs.mcs_s.bw == BW_80MHZ) |
| tx_rate = (u16) vht_mcs_nss1[index].ht40_rate[mcs.mcs_s.short_gi] / 10; |
| } |
| } |
| } else if (nss == 2) { |
| for (index = 0; index < MAX_VHT_MCS_IDX; index++) { |
| if (mcs.mcs_s.rate == index) { |
| if (mcs.mcs_s.bw == BW_20MHZ) |
| tx_rate = (u16) vht_mcs_nss2[index].ht20_rate[mcs.mcs_s.short_gi] / 10; |
| if (mcs.mcs_s.bw == BW_40MHZ) |
| tx_rate = (u16) vht_mcs_nss2[index].ht40_rate[mcs.mcs_s.short_gi] / 10; |
| if (mcs.mcs_s.bw == BW_80MHZ) |
| tx_rate = (u16) vht_mcs_nss2[index].ht40_rate[mcs.mcs_s.short_gi] / 10; |
| } |
| } |
| } else { |
| ALOGE("Unexpected nss %d", nss); |
| } |
| break; |
| default: |
| ALOGE("Unexpected preamble %d", mcs.mcs_s.preamble); |
| } |
| return tx_rate; |
| } |
| |
| static u16 get_rate(u16 mcs_r) |
| { |
| u16 tx_rate = 0; |
| MCS mcs; |
| static u16 rate_lookup[][8] = {{96, 48, 24, 12, 108, 72, 36, 18}, |
| {22, 11, 4, 2, 22, 11, 4, 0}}; |
| static u16 MCS_rate_lookup_ht[][8] = |
| {{ 13, 14, 27, 30, 59, 65, 117, 130}, |
| { 26, 29, 54, 60, 117, 130, 234, 260}, |
| { 39, 43, 81, 90, 176, 195, 351, 390}, |
| { 52, 58, 108, 120, 234, 260, 468, 520}, |
| { 78, 87, 162, 180, 351, 390, 702, 780}, |
| {104, 116, 216, 240, 468, 520, 936, 1040}, |
| {117, 130, 243, 270, 527, 585, 1053, 1170}, |
| {130, 144, 270, 300, 585, 650, 1170, 1300}, |
| {156, 173, 324, 360, 702, 780, 1404, 1560}, |
| { 0, 0, 360, 400, 780, 867, 1560, 1733}, |
| { 26, 29, 54, 60, 117, 130, 234, 260}, |
| { 52, 58, 108, 120, 234, 260, 468, 520}, |
| { 78, 87, 162, 180, 351, 390, 702, 780}, |
| {104, 116, 216, 240, 468, 520, 936, 1040}, |
| {156, 173, 324, 360, 702, 780, 1404, 1560}, |
| {208, 231, 432, 480, 936,1040, 1872, 2080}, |
| {234, 261, 486, 540,1053,1170, 2106, 2340}, |
| {260, 289, 540, 600,1170,1300, 2340, 2600}, |
| {312, 347, 648, 720,1404,1560, 2808, 3120}, |
| { 0, 0, 720, 800,1560,1733, 3120, 3467}}; |
| |
| mcs.mcs = mcs_r; |
| if ((mcs.mcs_s.preamble <= WL_PREAMBLE_VHT) && (mcs.mcs_s.rate < 10)) { |
| switch(mcs.mcs_s.preamble) |
| { |
| case WL_PREAMBLE_CCK: |
| case WL_PREAMBLE_OFDM: |
| if(mcs.mcs_s.rate<8) { |
| tx_rate = rate_lookup [mcs.mcs_s.preamble][mcs.mcs_s.rate]; |
| if (mcs.mcs_s.nss) |
| tx_rate *=2; |
| } else { |
| ALOGE("Unexpected rate value"); |
| } |
| break; |
| case WL_PREAMBLE_HT: |
| if(mcs.mcs_s.rate<8) { |
| if (!mcs.mcs_s.nss) |
| tx_rate = MCS_rate_lookup_ht[mcs.mcs_s.rate] |
| [2*mcs.mcs_s.bw+mcs.mcs_s.short_gi]; |
| else |
| tx_rate = MCS_rate_lookup_ht[10+mcs.mcs_s.rate] |
| [2*mcs.mcs_s.bw+mcs.mcs_s.short_gi]; |
| } else { |
| ALOGE("Unexpected HT mcs.mcs_s index"); |
| } |
| break; |
| case WL_PREAMBLE_VHT: |
| if (!mcs.mcs_s.nss) |
| tx_rate = MCS_rate_lookup_ht[mcs.mcs_s.rate] |
| [2*mcs.mcs_s.bw+mcs.mcs_s.short_gi]; |
| else |
| tx_rate = MCS_rate_lookup_ht[10+mcs.mcs_s.rate] |
| [2*mcs.mcs_s.bw+mcs.mcs_s.short_gi]; |
| break; |
| default: |
| ALOGE("Unexpected preamble"); |
| } |
| } |
| return tx_rate; |
| } |
| |
| static wifi_error populate_rx_aggr_stats(hal_info *info) |
| { |
| wifi_error status; |
| wifi_ring_buffer_entry *pRingBufferEntry = info->rx_aggr_pkts; |
| wifi_ring_per_packet_status_entry *pps_entry; |
| u32 index = 0; |
| |
| while (!info->clean_up && (index < info->rx_buf_size_occupied)) { |
| pps_entry = (wifi_ring_per_packet_status_entry *)(pRingBufferEntry + 1); |
| |
| pps_entry->MCS = info->aggr_stats.RxMCS.mcs; |
| pps_entry->last_transmit_rate = info->aggr_stats.last_transmit_rate; |
| pps_entry->rssi = info->aggr_stats.rssi; |
| pps_entry->firmware_entry_timestamp = info->aggr_stats.timestamp; |
| pps_entry->tid = info->aggr_stats.tid; |
| |
| index += pRingBufferEntry->entry_size; |
| status = update_stats_to_ring_buf(info, (u8 *)pRingBufferEntry, |
| pRingBufferEntry->entry_size); |
| |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write Rx stats into the ring buffer"); |
| return status; |
| } |
| /* update_stats_to_ring_buf() modifies the size. Update the same again |
| * here by adding sizeof(wifi_ring_buffer_entry) to continue parsing |
| */ |
| pRingBufferEntry = (wifi_ring_buffer_entry *)((u8 *)pRingBufferEntry |
| + sizeof(wifi_ring_buffer_entry) |
| + pRingBufferEntry->entry_size); |
| } |
| memset(info->rx_aggr_pkts, 0, info->rx_buf_size_occupied); |
| info->rx_buf_size_occupied = 0; |
| |
| return WIFI_SUCCESS; |
| } |
| |
| static wifi_error parse_rx_stats_v2(hal_info *info, u8 *buf, u16 size) |
| { |
| wifi_error status = WIFI_SUCCESS; |
| rb_pkt_stats_t_v1 *rx_stats_rcvd = (rb_pkt_stats_t_v1 *)buf; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| u32 len_ring_buffer_entry = 0; |
| |
| if (size < sizeof(rb_pkt_stats_t)) { |
| ALOGE("%s Unexpected rx stats event length: %d", __FUNCTION__, size); |
| memset(info->rx_aggr_pkts, 0, info->rx_buf_size_occupied); |
| memset(&info->aggr_stats, 0, sizeof(rx_aggr_stats)); |
| info->rx_buf_size_occupied = 0; |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| len_ring_buffer_entry = sizeof(wifi_ring_buffer_entry) |
| + sizeof(wifi_ring_per_packet_status_entry) |
| + RX_HTT_HDR_STATUS_LEN_V1; |
| |
| if (len_ring_buffer_entry + info->rx_buf_size_occupied |
| > info->rx_buf_size_allocated) { |
| wifi_ring_buffer_entry *temp; |
| temp = (wifi_ring_buffer_entry *)realloc(info->rx_aggr_pkts, |
| len_ring_buffer_entry + info->rx_buf_size_occupied); |
| if (temp == NULL) { |
| ALOGE("%s: Failed to reallocate memory", __FUNCTION__); |
| free(info->rx_aggr_pkts); |
| info->rx_aggr_pkts = NULL; |
| return WIFI_ERROR_OUT_OF_MEMORY; |
| } |
| info->rx_aggr_pkts = temp; |
| memset((u8 *)info->rx_aggr_pkts + info->rx_buf_size_allocated, 0, |
| len_ring_buffer_entry + info->rx_buf_size_occupied |
| - info->rx_buf_size_allocated); |
| info->rx_buf_size_allocated = |
| len_ring_buffer_entry + info->rx_buf_size_occupied; |
| } |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)((u8 *)info->rx_aggr_pkts |
| + info->rx_buf_size_occupied); |
| |
| info->rx_buf_size_occupied += len_ring_buffer_entry; |
| |
| /* Fill size of the entry in rb entry which can be used while populating |
| * the data. Actual size that needs to be sent to ring buffer is only pps |
| * entry size |
| */ |
| pRingBufferEntry->entry_size = len_ring_buffer_entry; |
| wifi_ring_per_packet_status_entry *rb_pkt_stats = |
| (wifi_ring_per_packet_status_entry *)(pRingBufferEntry + 1); |
| |
| memset(rb_pkt_stats, 0, sizeof(wifi_ring_per_packet_status_entry)); |
| |
| /* Peer tx packet and it is an Rx packet for us */ |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_DIRECTION_TX; |
| |
| if (!((rx_stats_rcvd->mpdu_end.overflow_err) || |
| (rx_stats_rcvd->attention.fcs_err) || |
| (rx_stats_rcvd->attention.mpdu_length_err) || |
| (rx_stats_rcvd->attention.msdu_length_err) || |
| (rx_stats_rcvd->attention.tkip_mic_err) || |
| (rx_stats_rcvd->attention.decrypt_err))) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_80211_HEADER; |
| |
| if (rx_stats_rcvd->mpdu_start.encrypted) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_PROTECTED; |
| |
| if (rx_stats_rcvd->attention.first_mpdu) { |
| MCS *mcs = &info->aggr_stats.RxMCS; |
| u32 ht_vht_sig; |
| |
| /* Flush the cached stats as this is the first MPDU. */ |
| memset(&info->aggr_stats, 0, sizeof(rx_aggr_stats)); |
| if (rx_stats_rcvd->ppdu_start.preamble_type == PREAMBLE_L_SIG_RATE) { |
| if (rx_stats_rcvd->ppdu_start.l_sig_rate_select) { |
| mcs->mcs_s.preamble = WIFI_HW_RATECODE_PREAM_CCK; |
| mcs->mcs_s.rate = cck_ratecode_mapping(rx_stats_rcvd->ppdu_start.l_sig_rate); |
| } else { |
| mcs->mcs_s.preamble = WIFI_HW_RATECODE_PREAM_OFDM; |
| mcs->mcs_s.rate = ofdm_ratecode_mapping(rx_stats_rcvd->ppdu_start.l_sig_rate); |
| } |
| /*BW is 0 for legacy cases*/ |
| } else if (rx_stats_rcvd->ppdu_start.preamble_type == |
| PREAMBLE_VHT_SIG_A_1) { |
| ht_vht_sig = rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_1; |
| mcs->mcs_s.nss = ((ht_vht_sig >> 3) & 0x3); |
| //mcs->mcs_s.nss = (ht_vht_sig & BITMASK(7)) >> 3; |
| mcs->mcs_s.preamble = WIFI_HW_RATECODE_PREAM_HT; |
| mcs->mcs_s.rate = ((ht_vht_sig & BITMASK(7)) % 8) & 0xF; |
| mcs->mcs_s.bw = ((ht_vht_sig >> 7) & 1); |
| mcs->mcs_s.short_gi = |
| ((rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_2 >> 7) & 1); |
| } else if (rx_stats_rcvd->ppdu_start.preamble_type == |
| PREAMBLE_VHT_SIG_A_2) { |
| ht_vht_sig = rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_1; |
| mcs->mcs_s.nss = ((ht_vht_sig >> 10) & 0x3); |
| mcs->mcs_s.preamble = WIFI_HW_RATECODE_PREAM_VHT; |
| mcs->mcs_s.rate = |
| (rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_2 >> 4) & BITMASK(4); |
| mcs->mcs_s.bw = (ht_vht_sig & 3); |
| mcs->mcs_s.short_gi = |
| (rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_2 & 1); |
| } |
| |
| info->aggr_stats.last_transmit_rate |
| = get_rate_v1(info->aggr_stats.RxMCS.mcs); |
| |
| info->aggr_stats.rssi = rx_stats_rcvd->ppdu_start.rssi_comb; |
| info->aggr_stats.tid = rx_stats_rcvd->mpdu_start.tid; |
| } |
| rb_pkt_stats->link_layer_transmit_sequence |
| = rx_stats_rcvd->mpdu_start.seq_num; |
| |
| memcpy(&rb_pkt_stats->data[0], &rx_stats_rcvd->rx_hdr_status[0], |
| RX_HTT_HDR_STATUS_LEN_V1); |
| |
| if ((rx_stats_rcvd->attention.last_mpdu |
| && rx_stats_rcvd->msdu_end.last_msdu) |
| || (rx_stats_rcvd->attention.first_mpdu |
| && rx_stats_rcvd->attention.last_mpdu)) { |
| info->aggr_stats.timestamp = rx_stats_rcvd->ppdu_end.wb_timestamp_lower_32; |
| |
| status = populate_rx_aggr_stats(info); |
| } |
| |
| return status; |
| } |
| |
| static wifi_error parse_rx_stats(hal_info *info, u8 *buf, u16 size) |
| { |
| wifi_error status = WIFI_SUCCESS; |
| rb_pkt_stats_t *rx_stats_rcvd = (rb_pkt_stats_t *)buf; |
| wifi_ring_buffer_entry *pRingBufferEntry; |
| u32 len_ring_buffer_entry = 0; |
| |
| if (size < sizeof(rb_pkt_stats_t)) { |
| ALOGE("%s Unexpected rx stats event length: %d", __FUNCTION__, size); |
| memset(info->rx_aggr_pkts, 0, info->rx_buf_size_occupied); |
| memset(&info->aggr_stats, 0, sizeof(rx_aggr_stats)); |
| info->rx_buf_size_occupied = 0; |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| len_ring_buffer_entry = sizeof(wifi_ring_buffer_entry) |
| + sizeof(wifi_ring_per_packet_status_entry) |
| + RX_HTT_HDR_STATUS_LEN; |
| |
| if (len_ring_buffer_entry + info->rx_buf_size_occupied |
| > info->rx_buf_size_allocated) { |
| wifi_ring_buffer_entry *temp; |
| temp = (wifi_ring_buffer_entry *)realloc(info->rx_aggr_pkts, |
| len_ring_buffer_entry + info->rx_buf_size_occupied); |
| if (temp == NULL) { |
| ALOGE("%s: Failed to reallocate memory", __FUNCTION__); |
| free(info->rx_aggr_pkts); |
| info->rx_aggr_pkts = NULL; |
| return WIFI_ERROR_OUT_OF_MEMORY; |
| } |
| info->rx_aggr_pkts = temp; |
| memset((u8 *)info->rx_aggr_pkts + info->rx_buf_size_allocated, 0, |
| len_ring_buffer_entry + info->rx_buf_size_occupied |
| - info->rx_buf_size_allocated); |
| info->rx_buf_size_allocated = |
| len_ring_buffer_entry + info->rx_buf_size_occupied; |
| } |
| |
| pRingBufferEntry = (wifi_ring_buffer_entry *)((u8 *)info->rx_aggr_pkts |
| + info->rx_buf_size_occupied); |
| |
| info->rx_buf_size_occupied += len_ring_buffer_entry; |
| |
| /* Fill size of the entry in rb entry which can be used while populating |
| * the data. Actual size that needs to be sent to ring buffer is only pps |
| * entry size |
| */ |
| pRingBufferEntry->entry_size = len_ring_buffer_entry; |
| wifi_ring_per_packet_status_entry *rb_pkt_stats = |
| (wifi_ring_per_packet_status_entry *)(pRingBufferEntry + 1); |
| |
| memset(rb_pkt_stats, 0, sizeof(wifi_ring_per_packet_status_entry)); |
| |
| /* Peer tx packet and it is an Rx packet for us */ |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_DIRECTION_TX; |
| |
| if (!((rx_stats_rcvd->mpdu_end.overflow_err) || |
| (rx_stats_rcvd->attention.fcs_err) || |
| (rx_stats_rcvd->attention.mpdu_length_err) || |
| (rx_stats_rcvd->attention.msdu_length_err) || |
| (rx_stats_rcvd->attention.tkip_mic_err) || |
| (rx_stats_rcvd->attention.decrypt_err))) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_80211_HEADER; |
| |
| if (rx_stats_rcvd->mpdu_start.encrypted) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_PROTECTED; |
| |
| if (rx_stats_rcvd->attention.first_mpdu) { |
| MCS *mcs = &info->aggr_stats.RxMCS; |
| u32 ht_vht_sig; |
| |
| /* Flush the cached stats as this is the first MPDU. */ |
| memset(&info->aggr_stats, 0, sizeof(rx_aggr_stats)); |
| if (rx_stats_rcvd->ppdu_start.preamble_type == PREAMBLE_L_SIG_RATE) { |
| if (rx_stats_rcvd->ppdu_start.l_sig_rate_select) |
| mcs->mcs_s.preamble = WL_PREAMBLE_OFDM; |
| mcs->mcs_s.rate = rx_stats_rcvd->ppdu_start.l_sig_rate - 8; |
| /*BW is 0 for legacy cases*/ |
| } else if (rx_stats_rcvd->ppdu_start.preamble_type == |
| PREAMBLE_VHT_SIG_A_1) { |
| ht_vht_sig = rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_1; |
| mcs->mcs_s.nss = ((ht_vht_sig >> 3) & 0x3); |
| mcs->mcs_s.preamble = WL_PREAMBLE_HT; |
| mcs->mcs_s.rate = (ht_vht_sig & BITMASK(7)) >> 3; |
| mcs->mcs_s.bw = ((ht_vht_sig >> 7) & 1); |
| mcs->mcs_s.short_gi = |
| ((rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_2 >> 7) & 1); |
| } else if (rx_stats_rcvd->ppdu_start.preamble_type == |
| PREAMBLE_VHT_SIG_A_2) { |
| ht_vht_sig = rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_1; |
| mcs->mcs_s.nss = ((ht_vht_sig >> 10) & 0x3); |
| mcs->mcs_s.preamble = WL_PREAMBLE_VHT; |
| mcs->mcs_s.rate = |
| (rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_2 >> 4) & BITMASK(4); |
| mcs->mcs_s.bw = (ht_vht_sig & 3); |
| mcs->mcs_s.short_gi = |
| (rx_stats_rcvd->ppdu_start.ht_sig_vht_sig_a_2 & 1); |
| } |
| |
| info->aggr_stats.last_transmit_rate |
| = get_rate(info->aggr_stats.RxMCS.mcs); |
| |
| info->aggr_stats.rssi = rx_stats_rcvd->ppdu_start.rssi_comb; |
| info->aggr_stats.tid = rx_stats_rcvd->mpdu_start.tid; |
| } |
| rb_pkt_stats->link_layer_transmit_sequence |
| = rx_stats_rcvd->mpdu_start.seq_num; |
| |
| memcpy(&rb_pkt_stats->data[0], &rx_stats_rcvd->rx_hdr_status[0], |
| RX_HTT_HDR_STATUS_LEN); |
| |
| if ((rx_stats_rcvd->attention.last_mpdu |
| && rx_stats_rcvd->msdu_end.last_msdu) |
| || (rx_stats_rcvd->attention.first_mpdu |
| && rx_stats_rcvd->attention.last_mpdu)) { |
| info->aggr_stats.timestamp = rx_stats_rcvd->ppdu_end.tsf_timestamp; |
| status = populate_rx_aggr_stats(info); |
| } |
| |
| return status; |
| } |
| |
| static u16 get_tx_mcs_v1(u8 *data) |
| { |
| MCS mcs; |
| RATE_CODE rate_code; |
| u16 extended_flags; |
| mcs.mcs = 0; |
| |
| rate_code = *((RATE_CODE*)(data + RATE_CODE_OFFSET)); |
| extended_flags = *((u16*)(data + EXT_FLAGS_OFFSET)); |
| |
| mcs.mcs_s.rate = rate_code.rateCode & 0xF; |
| mcs.mcs_s.nss = (rate_code.rateCode >> 4) & 0x3; |
| mcs.mcs_s.preamble = (rate_code.rateCode >> 6) & 0x3; |
| mcs.mcs_s.short_gi = (((extended_flags >> 12) & 0x1) == 1) ? 1 : 0; |
| mcs.mcs_s.bw = (rate_code.flags >> 5) & 0x3; |
| |
| return mcs.mcs; |
| } |
| |
| static u16 get_tx_mcs(u8 series, |
| struct tx_ppdu_start *ppdu_start) |
| { |
| MCS mcs; |
| struct series_bw *sbw = NULL; |
| |
| mcs.mcs = 0; |
| |
| if (series == 0) { |
| if (ppdu_start->valid_s0_bw20) |
| sbw = &ppdu_start->s0_bw20; |
| else if (ppdu_start->valid_s0_bw40) |
| sbw = &ppdu_start->s0_bw40; |
| else if (ppdu_start->valid_s0_bw80) |
| sbw = &ppdu_start->s0_bw80; |
| else if (ppdu_start->valid_s0_bw160) |
| sbw = &ppdu_start->s0_bw160; |
| } else { |
| if (ppdu_start->valid_s1_bw20) |
| sbw = &ppdu_start->s1_bw20; |
| else if (ppdu_start->valid_s1_bw40) |
| sbw = &ppdu_start->s1_bw40; |
| else if (ppdu_start->valid_s1_bw80) |
| sbw = &ppdu_start->s1_bw80; |
| else if (ppdu_start->valid_s1_bw160) |
| sbw = &ppdu_start->s1_bw160; |
| } |
| |
| if (sbw) { |
| mcs.mcs_s.rate = sbw->rate; |
| mcs.mcs_s.nss = sbw->nss; |
| mcs.mcs_s.preamble = sbw->preamble_type; |
| mcs.mcs_s.short_gi = sbw->short_gi; |
| } |
| |
| return mcs.mcs; |
| } |
| |
| static void get_tx_aggr_stats(struct tx_ppdu_start *ppdu_start, hal_info *info) |
| { |
| u32 baBitmap0 = 0; |
| u32 baBitmap1 = 0; |
| |
| info->pkt_stats->tx_seqnum_bitmap_31_0 = ppdu_start->seqnum_bitmap_31_0; |
| info->pkt_stats->tx_seqnum_bitmap_63_32 = ppdu_start->seqnum_bitmap_63_32; |
| |
| if (info->pkt_stats->isBlockAck) { |
| int baShift = ppdu_start->start_seq_num - info->pkt_stats->ba_seq_num; |
| //There are 4 scenarios in total: |
| //1.TxSeq No. >= BaSeq No. and no roll over. |
| //2.TxSeq No. >= BaSeq No. and TxSeq No. rolls over. |
| //3.TxSeq No. <= BaSeq No. and no roll over. |
| //4.TxSeq No. <= BaSeq No. and BaSeq No. rolls over. |
| |
| baBitmap0 = info->pkt_stats->ba_bitmap_31_0; |
| baBitmap1 = info->pkt_stats->ba_bitmap_63_32; |
| |
| if (((baShift >= 0) && (baShift < SEQ_NUM_RANGE/2)) || |
| (baShift < -SEQ_NUM_RANGE/2)) { |
| //Scenario No.1 and No.2 |
| baShift = baShift < -SEQ_NUM_RANGE/2 ? (SEQ_NUM_RANGE + baShift) : |
| baShift; |
| |
| if (baShift < BITMAP_VAR_SIZE) { |
| info->pkt_stats->shifted_bitmap_31_0 = |
| ((baBitmap1 << (32 - baShift)) | (baBitmap0 >> baShift)); |
| info->pkt_stats->shifted_bitmap_63_32 = baBitmap1 >> baShift; |
| } else { |
| info->pkt_stats->shifted_bitmap_31_0 = |
| baBitmap1 >> (baShift - BITMAP_VAR_SIZE); |
| info->pkt_stats->shifted_bitmap_63_32 = 0; |
| } |
| } else { |
| baShift = (baShift >= SEQ_NUM_RANGE/2) ? (SEQ_NUM_RANGE - baShift) : |
| -baShift; |
| if (baShift < BITMAP_VAR_SIZE) { |
| info->pkt_stats->shifted_bitmap_31_0 = baBitmap0 << baShift; |
| info->pkt_stats->shifted_bitmap_63_32 = |
| ((baBitmap0 << (32 - baShift)) | |
| (baBitmap1 >> baShift)); |
| } else { |
| info->pkt_stats->shifted_bitmap_31_0 = 0; |
| info->pkt_stats->shifted_bitmap_63_32 = |
| baBitmap0 << (baShift - BITMAP_VAR_SIZE); |
| } |
| } |
| } else { |
| info->pkt_stats->shifted_bitmap_31_0 = 0; |
| info->pkt_stats->shifted_bitmap_63_32 = 0; |
| } |
| } |
| |
| static void get_try_status_params(hal_info *info, |
| struct tx_ppdu_end *tx_ppdu_end) |
| { |
| int try_list_index; |
| |
| if (tx_ppdu_end->stat.total_tries > 0) |
| try_list_index = tx_ppdu_end->stat.total_tries - 1; |
| else |
| try_list_index = 0; |
| |
| info->pkt_stats->tx_bandwidth = |
| tx_ppdu_end->try_list.try_st[try_list_index].packet_bw; |
| info->pkt_stats->series = |
| tx_ppdu_end->try_list.try_st[try_list_index].series; |
| } |
| |
| static wifi_error parse_tx_stats(hal_info *info, void *buf, |
| u32 buflen, u8 logtype) |
| { |
| wifi_error status = WIFI_SUCCESS; |
| int i; |
| wifi_ring_buffer_entry *pRingBufferEntry = |
| (wifi_ring_buffer_entry *)info->pkt_stats->tx_stats; |
| |
| wifi_ring_per_packet_status_entry *rb_pkt_stats = |
| (wifi_ring_per_packet_status_entry *)(pRingBufferEntry + 1); |
| |
| ALOGV("Received Tx stats: log_type : %d", logtype); |
| switch (logtype) |
| { |
| case PKTLOG_TYPE_TX_CTRL: |
| { |
| if (buflen < sizeof (wh_pktlog_txctl)) { |
| ALOGE("Unexpected tx_ctrl event length: %d", buflen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| wh_pktlog_txctl *stats = (wh_pktlog_txctl *)buf; |
| struct tx_ppdu_start *ppdu_start = |
| (struct tx_ppdu_start *)(&stats->u.ppdu_start); |
| |
| if (ppdu_start->frame_control & BIT(DATA_PROTECTED)) |
| rb_pkt_stats->flags |= |
| PER_PACKET_ENTRY_FLAGS_PROTECTED; |
| rb_pkt_stats->link_layer_transmit_sequence |
| = ppdu_start->start_seq_num; |
| info->pkt_stats->start_seq_num = ppdu_start->start_seq_num; |
| rb_pkt_stats->tid = ppdu_start->qos_ctl & 0xF; |
| rb_pkt_stats->MCS = get_tx_mcs(info->pkt_stats->series, ppdu_start) | |
| (info->pkt_stats->tx_bandwidth << BW_OFFSET); |
| rb_pkt_stats->last_transmit_rate = get_rate(rb_pkt_stats->MCS); |
| |
| if (ppdu_start->ampdu) |
| get_tx_aggr_stats(ppdu_start, info); |
| info->pkt_stats->tx_stats_events |= BIT(PKTLOG_TYPE_TX_CTRL); |
| } |
| break; |
| case PKTLOG_TYPE_TX_STAT: |
| { |
| if (buflen < sizeof(struct tx_ppdu_end)) { |
| ALOGE("Unexpected tx_stat event length: %d", buflen); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| /* This should be the first event for tx-stats: So, |
| * previous stats are invalid. Flush the old stats and treat |
| * this as new packet |
| */ |
| if (info->pkt_stats->tx_stats_events) |
| memset(rb_pkt_stats, 0, |
| sizeof(wifi_ring_per_packet_status_entry)); |
| |
| struct tx_ppdu_end *tx_ppdu_end = (struct tx_ppdu_end*)(buf); |
| |
| info->pkt_stats->ba_seq_num = tx_ppdu_end->stat.ba_start_seq_num; |
| info->pkt_stats->isBlockAck = tx_ppdu_end->stat.ba_status; |
| |
| if (tx_ppdu_end->stat.tx_ok) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| info->pkt_stats->isBlockAck = tx_ppdu_end->stat.ba_status; |
| |
| info->pkt_stats->ba_bitmap_31_0 = tx_ppdu_end->stat.ba_bitmap_31_0; |
| info->pkt_stats->ba_bitmap_63_32 = |
| tx_ppdu_end->stat.ba_bitmap_63_32; |
| rb_pkt_stats->transmit_success_timestamp = |
| tx_ppdu_end->try_list.try_st[0].timestamp; |
| rb_pkt_stats->rssi = tx_ppdu_end->stat.ack_rssi_ave; |
| rb_pkt_stats->num_retries = tx_ppdu_end->stat.total_tries; |
| get_try_status_params(info, tx_ppdu_end); |
| |
| info->pkt_stats->tx_stats_events |= BIT(PKTLOG_TYPE_TX_STAT); |
| } |
| break; |
| case PKTLOG_TYPE_TX_MSDU_ID: |
| { |
| memset(info->pkt_stats, 0, sizeof(struct pkt_stats_s)); |
| info->pkt_stats->num_msdu = *(u8 *)buf; |
| info->pkt_stats->tx_stats_events = BIT(PKTLOG_TYPE_TX_MSDU_ID); |
| } |
| break; |
| case PKTLOG_TYPE_RC_UPDATE: |
| case PKTLOG_TYPE_TX_FRM_HDR: |
| case PKTLOG_TYPE_RC_FIND: |
| case PKTLOG_TYPE_TX_VIRT_ADDR: |
| ALOGV("%s : Unsupported log_type received : %d", |
| __FUNCTION__, logtype); |
| break; |
| default: |
| { |
| ALOGV("%s : Unexpected log_type received : %d", |
| __FUNCTION__, logtype); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| } |
| |
| if ((info->pkt_stats->tx_stats_events & BIT(PKTLOG_TYPE_TX_CTRL)) && |
| (info->pkt_stats->tx_stats_events & BIT(PKTLOG_TYPE_TX_STAT)) && |
| (info->pkt_stats->tx_stats_events & BIT(PKTLOG_TYPE_TX_MSDU_ID))) { |
| /* No tx payload as of now, add the length to parameter size(3rd) |
| * if there is any payload |
| */ |
| |
| if (info->pkt_stats->num_msdu == 1) { |
| if (!(rb_pkt_stats->flags & PER_PACKET_ENTRY_FLAGS_TX_SUCCESS)) |
| rb_pkt_stats->rssi = INVALID_RSSI; |
| /* Handle non aggregated cases */ |
| status = update_stats_to_ring_buf(info, |
| (u8 *)pRingBufferEntry, |
| sizeof(wifi_ring_buffer_entry) + |
| sizeof(wifi_ring_per_packet_status_entry)); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write into the ring buffer : %d", logtype); |
| } |
| } else { |
| /* Handle aggregated cases */ |
| for (i = 0; i < MAX_BA_WINDOW_SIZE; i++) { |
| if (i < BITMAP_VAR_SIZE) { |
| if (info->pkt_stats->tx_seqnum_bitmap_31_0 & BIT(i)) { |
| if (info->pkt_stats->shifted_bitmap_31_0 & BIT(i)) { |
| rb_pkt_stats->flags |= |
| PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| } else { |
| rb_pkt_stats->flags &= |
| ~PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| rb_pkt_stats->rssi = INVALID_RSSI; |
| } |
| } else { |
| continue; |
| } |
| } else { |
| if (info->pkt_stats->tx_seqnum_bitmap_63_32 |
| & BIT(i - BITMAP_VAR_SIZE)) { |
| if (info->pkt_stats->shifted_bitmap_63_32 |
| & BIT(i - BITMAP_VAR_SIZE)) { |
| rb_pkt_stats->flags |= |
| PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| } else { |
| rb_pkt_stats->flags &= |
| ~PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| rb_pkt_stats->rssi = INVALID_RSSI; |
| } |
| } else { |
| continue; |
| } |
| } |
| rb_pkt_stats->link_layer_transmit_sequence = |
| info->pkt_stats->start_seq_num + i; |
| |
| /* Take care of roll over SEQ_NUM_RANGE */ |
| rb_pkt_stats->link_layer_transmit_sequence &= 0xFFF; |
| |
| status = update_stats_to_ring_buf(info, |
| (u8 *)pRingBufferEntry, |
| sizeof(wifi_ring_buffer_entry) + |
| sizeof(wifi_ring_per_packet_status_entry)); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write into the ring buffer: %d", logtype); |
| break; |
| } |
| } |
| } |
| |
| /* Flush the local copy after writing the stats to ring buffer |
| * for tx-stats. |
| */ |
| info->pkt_stats->tx_stats_events = 0; |
| memset(rb_pkt_stats, 0, |
| sizeof(wifi_ring_per_packet_status_entry)); |
| |
| } |
| |
| return status; |
| } |
| |
| wifi_error write_per_packet_stats_to_rb(hal_info *info, u8 *buf, u16 length) |
| { |
| wifi_ring_buffer_entry rb_entry_hdr; |
| struct timeval time; |
| wifi_error status; |
| |
| rb_entry_hdr.entry_size = length; |
| rb_entry_hdr.flags = RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP; |
| rb_entry_hdr.type = ENTRY_TYPE_PKT; |
| gettimeofday(&time, NULL); |
| rb_entry_hdr.timestamp = (u64)time.tv_usec + (u64)time.tv_sec * 1000 * 1000; |
| |
| /* Write if verbose and handler is set */ |
| if (info->rb_infos[PKT_STATS_RB_ID].verbose_level >= 3 && |
| info->on_ring_buffer_data) { |
| /* Write header and payload separately to avoid |
| * complete payload memcpy */ |
| status = ring_buffer_write(&info->rb_infos[PKT_STATS_RB_ID], |
| (u8*)&rb_entry_hdr, |
| sizeof(wifi_ring_buffer_entry), |
| 0, |
| sizeof(wifi_ring_buffer_entry) + length); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write driver prints rb header %d", status); |
| return status; |
| } |
| status = ring_buffer_write(&info->rb_infos[PKT_STATS_RB_ID], |
| buf, |
| length, |
| 1, |
| length); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write PKT stats into the ring buffer"); |
| } |
| } |
| |
| return WIFI_SUCCESS; |
| } |
| |
| static wifi_error parse_tx_pkt_fate_stats(hal_info *info, u8 *buf, u16 size) |
| { |
| pktdump_hdr *log = (pktdump_hdr *)buf; |
| wifi_tx_report_i *pkt_fate_stats; |
| |
| if (info->pkt_fate_stats->n_tx_stats_collected >= MAX_FATE_LOG_LEN) { |
| ALOGD("Only %u events are expected, don't process this event", |
| MAX_FATE_LOG_LEN); |
| return WIFI_SUCCESS; |
| } |
| |
| pkt_fate_stats = &info->pkt_fate_stats->tx_fate_stats[ |
| info->pkt_fate_stats->n_tx_stats_collected]; |
| |
| pkt_fate_stats->fate = (wifi_tx_packet_fate)log->status; |
| |
| if (pkt_fate_stats->fate > TX_PKT_FATE_DRV_DROP_OTHER) { |
| ALOGE("Invalid Tx pkt fate status %d, set to drv_drop_other", |
| pkt_fate_stats->fate); |
| pkt_fate_stats->fate = TX_PKT_FATE_DRV_DROP_OTHER; |
| } |
| |
| if (log->type == TX_MGMT_PKT) |
| pkt_fate_stats->frame_inf.payload_type = FRAME_TYPE_80211_MGMT; |
| else |
| pkt_fate_stats->frame_inf.payload_type = FRAME_TYPE_ETHERNET_II; |
| |
| pkt_fate_stats->frame_inf.driver_timestamp_usec = log->driver_ts; |
| pkt_fate_stats->frame_inf.firmware_timestamp_usec = log->fw_ts; |
| pkt_fate_stats->frame_inf.frame_len = size - sizeof(pktdump_hdr); |
| pkt_fate_stats->frame_inf.frame_content = |
| (char *)malloc(pkt_fate_stats->frame_inf.frame_len * sizeof(char)); |
| if (pkt_fate_stats->frame_inf.frame_content) { |
| memcpy(pkt_fate_stats->frame_inf.frame_content, |
| buf + sizeof(pktdump_hdr), pkt_fate_stats->frame_inf.frame_len); |
| } else { |
| ALOGE("Failed to allocate mem for Tx frame_content for packet: %zu", |
| info->pkt_fate_stats->n_tx_stats_collected); |
| pkt_fate_stats->frame_inf.frame_len = 0; |
| } |
| |
| info->pkt_fate_stats->n_tx_stats_collected++; |
| |
| return WIFI_SUCCESS; |
| } |
| |
| |
| static wifi_error parse_rx_pkt_fate_stats(hal_info *info, u8 *buf, u16 size) |
| { |
| pktdump_hdr *log = (pktdump_hdr *)buf; |
| wifi_rx_report_i *pkt_fate_stats; |
| |
| if (info->pkt_fate_stats->n_rx_stats_collected >= MAX_FATE_LOG_LEN) { |
| ALOGD("Only %u events are expected, don't process this event", |
| MAX_FATE_LOG_LEN); |
| return WIFI_SUCCESS; |
| } |
| |
| pkt_fate_stats = &info->pkt_fate_stats->rx_fate_stats[ |
| info->pkt_fate_stats->n_rx_stats_collected]; |
| |
| pkt_fate_stats->fate = (wifi_rx_packet_fate)log->status; |
| if (log->type == RX_MGMT_PKT) |
| pkt_fate_stats->frame_inf.payload_type = FRAME_TYPE_80211_MGMT; |
| else |
| pkt_fate_stats->frame_inf.payload_type = FRAME_TYPE_ETHERNET_II; |
| |
| pkt_fate_stats->frame_inf.driver_timestamp_usec = log->driver_ts; |
| pkt_fate_stats->frame_inf.firmware_timestamp_usec = log->fw_ts; |
| pkt_fate_stats->frame_inf.frame_len = size - sizeof(pktdump_hdr); |
| pkt_fate_stats->frame_inf.frame_content = |
| (char *)malloc(pkt_fate_stats->frame_inf.frame_len * sizeof(char)); |
| if (pkt_fate_stats->frame_inf.frame_content) { |
| memcpy(pkt_fate_stats->frame_inf.frame_content, |
| buf + sizeof(pktdump_hdr), pkt_fate_stats->frame_inf.frame_len); |
| } else { |
| ALOGE("Failed to allocate mem for Rx frame_content for packet: %zu", |
| info->pkt_fate_stats->n_rx_stats_collected); |
| pkt_fate_stats->frame_inf.frame_len = 0; |
| } |
| |
| info->pkt_fate_stats->n_rx_stats_collected++; |
| |
| return WIFI_SUCCESS; |
| } |
| |
| |
| static wifi_error trigger_fate_stats(hal_info *info, u8 *buf, u16 size) |
| { |
| int i; |
| packet_fate_monitor_info *pkt_fate_stats = info->pkt_fate_stats; |
| |
| for (i=0; i<MAX_FATE_LOG_LEN; i++) { |
| if (pkt_fate_stats->tx_fate_stats[i].frame_inf.frame_content) { |
| free (pkt_fate_stats->tx_fate_stats[i].frame_inf.frame_content); |
| pkt_fate_stats->tx_fate_stats[i].frame_inf.frame_content = NULL; |
| } |
| |
| if (pkt_fate_stats->rx_fate_stats[i].frame_inf.frame_content) { |
| free (pkt_fate_stats->rx_fate_stats[i].frame_inf.frame_content); |
| pkt_fate_stats->rx_fate_stats[i].frame_inf.frame_content = NULL; |
| } |
| } |
| memset(pkt_fate_stats, 0, sizeof(packet_fate_monitor_info)); |
| |
| return WIFI_SUCCESS; |
| } |
| |
| |
| static wifi_error report_fate_stats(hal_info *info, u8 *buf, u16 size) |
| { |
| ALOGI("Fate Tx-Rx: Packet fate stats stop received"); |
| return WIFI_SUCCESS; |
| } |
| |
| |
| static wifi_error parse_pkt_fate_stats(hal_info *info, u8 *buf, u16 size) |
| { |
| pktdump_hdr *hdr = (pktdump_hdr *)buf; |
| |
| switch (hdr->type) |
| { |
| case START_MONITOR: |
| trigger_fate_stats(info, buf, size); |
| break; |
| case STOP_MONITOR: |
| report_fate_stats(info, buf, size); |
| break; |
| case TX_MGMT_PKT: |
| case TX_DATA_PKT: |
| parse_tx_pkt_fate_stats(info, buf, size); |
| break; |
| case RX_MGMT_PKT: |
| case RX_DATA_PKT: |
| parse_rx_pkt_fate_stats(info, buf, size); |
| break; |
| default: |
| ALOGE("Unsupported type : %d", hdr->type); |
| return WIFI_ERROR_INVALID_ARGS; |
| } |
| return WIFI_SUCCESS; |
| } |
| |
| /* |
| * --------------------------------------------------------------------------------- |
| * | pkt log | packet log data contain sub packet log info | |
| * | header |------------------------------------------------------------------| |
| * | | sub pkt log | sub pkt log | sub pkt log | sub pkt log | | |
| * | | header | data | header | data |..... | |
| * |-------------------------------------------------------------------------------- |
| */ |
| static wifi_error parse_stats_sw_event(hal_info *info, |
| wh_pktlog_hdr_v2_t *pkt_stats_header) |
| { |
| u32 pkt_stats_len; |
| int num_of_node = 0; |
| u8 *data; |
| u8 *node_pkt_data; |
| wh_pktlog_hdr_v2_t *pkt_stats_node_header; |
| int node_pkt_type,pkt_sub_type,i; |
| int node_pkt_len = 0; |
| wifi_error status = WIFI_SUCCESS; |
| node_pkt_stats node_pkt_t; |
| node_pkt_t.bmap_enqueued = 0; |
| node_pkt_t.bmap_failed = 0; |
| wifi_ring_buffer_entry *pRingBufferEntry = |
| (wifi_ring_buffer_entry *)info->pkt_stats->tx_stats; |
| |
| wifi_ring_per_packet_status_entry *rb_pkt_stats = |
| (wifi_ring_per_packet_status_entry *)(pRingBufferEntry + 1); |
| |
| pkt_stats_len = pkt_stats_header->size; |
| data = ((u8 *)pkt_stats_header + sizeof(wh_pktlog_hdr_v2_t)); |
| num_of_node = (pkt_stats_header->reserved >> 16) & 0xFFFF; |
| pkt_sub_type = pkt_stats_header->reserved & 0xFFFF; |
| |
| do { |
| if (pkt_stats_len < sizeof(wh_pktlog_hdr_v2_t)) { |
| status = WIFI_ERROR_INVALID_ARGS; |
| break; |
| } |
| if (pkt_sub_type == 1) { |
| pkt_stats_node_header = (wh_pktlog_hdr_v2_t *)data; |
| if (pkt_stats_node_header) { |
| node_pkt_type = pkt_stats_node_header->log_type; |
| node_pkt_len = pkt_stats_node_header->size; |
| node_pkt_data = ((u8 *)pkt_stats_node_header + sizeof(wh_pktlog_hdr_v2_t)); |
| switch (node_pkt_type) { |
| case PKTLOG_TYPE_TX_CTRL: |
| info->pkt_stats->tx_stats_events |= BIT(PKTLOG_TYPE_TX_CTRL); |
| break; |
| case PKTLOG_TYPE_TX_STAT: |
| { |
| memset(rb_pkt_stats, 0, sizeof(wifi_ring_per_packet_status_entry)); |
| memset(&node_pkt_t, 0, sizeof(node_pkt_stats)); |
| node_pkt_t.frm_ctrl = *((u16*)(node_pkt_data + FRAME_CTRL_OFFSET)); |
| if (node_pkt_t.frm_ctrl & BIT(DATA_PROTECTED)) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_PROTECTED; |
| rb_pkt_stats->transmit_success_timestamp = |
| *((u64*)(node_pkt_data + TX_SUCCESS_TMS_OFFSET)); |
| rb_pkt_stats->link_layer_transmit_sequence = |
| *((u16*)(node_pkt_data + LINK_LAYER_TX_SQN_OFFSET)); |
| node_pkt_t.tx_ok = *((u8*)(node_pkt_data + TX_STATUS_OFFSET)); |
| if (node_pkt_t.tx_ok == 0) |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| rb_pkt_stats->rssi = *((u8*)(node_pkt_data + TX_RSSI_OFFSET)); |
| rb_pkt_stats->num_retries = *((u8*)(node_pkt_data + NO_RETRIES_OFFSET)); |
| node_pkt_t.qos_ctrl = *((u8*)(node_pkt_data + QOS_CTRL_OFFSET)); |
| rb_pkt_stats->tid = node_pkt_t.qos_ctrl & 0xF; |
| rb_pkt_stats->MCS = get_tx_mcs_v1(node_pkt_data); |
| if ((rb_pkt_stats->MCS & INVALID_RATE_CODE) != INVALID_RATE_CODE) |
| rb_pkt_stats->last_transmit_rate = get_rate_v1(rb_pkt_stats->MCS); |
| node_pkt_t.bmap_failed = *((u64*)(node_pkt_data + BMAP_FAILED_OFFSET)); |
| node_pkt_t.bmap_enqueued = *((u64*)(node_pkt_data + BMAP_ENQUEUED_OFFSET)); |
| |
| info->pkt_stats->tx_stats_events |= BIT(PKTLOG_TYPE_TX_STAT); |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_80211_HEADER; |
| } |
| break; |
| default: |
| // TODO: Unexpected PKTLOG types |
| break; |
| } |
| if (info->pkt_stats->tx_stats_events & BIT(PKTLOG_TYPE_TX_STAT)) { |
| /* if bmap_enqueued is 1 ,Handle non aggregated cases */ |
| if (node_pkt_t.bmap_enqueued == 1) { |
| status = update_stats_to_ring_buf(info, |
| (u8 *)pRingBufferEntry, |
| sizeof(wifi_ring_buffer_entry) + |
| sizeof(wifi_ring_per_packet_status_entry)); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write into the ring buffer : %d", node_pkt_type); |
| } |
| } else { |
| /* if bmap_enqueued is more than 1 ,Handle aggregated cases */ |
| for (i = 0; i < MAX_BA_WINDOW_SIZE; i++) { |
| if (((node_pkt_t.bmap_enqueued >> i) & 0x1) == 1) { |
| if (((node_pkt_t.bmap_failed >> i) & 0x1) == 1) { |
| rb_pkt_stats->flags &= ~PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| } else { |
| rb_pkt_stats->flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS; |
| } |
| status = update_stats_to_ring_buf(info, |
| (u8 *)pRingBufferEntry, |
| sizeof(wifi_ring_buffer_entry) + |
| sizeof(wifi_ring_per_packet_status_entry)); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write into the ring buffer : %d", node_pkt_type); |
| break; |
| } |
| rb_pkt_stats->link_layer_transmit_sequence += 1; |
| } |
| } |
| } |
| } |
| } |
| pkt_stats_len = (pkt_stats_len - (sizeof(wh_pktlog_hdr_v2_t) + node_pkt_len)); |
| data = (u8*) (data + sizeof(wh_pktlog_hdr_v2_t) + node_pkt_len); |
| info->pkt_stats->tx_stats_events = 0; |
| } else { |
| //TODO parsing of unknown packet sub type |
| status = WIFI_ERROR_INVALID_ARGS; |
| break; |
| } |
| } while (!info->clean_up && (pkt_stats_len > 0)); |
| return status; |
| } |
| |
| /* Added This function to parse stats based on PKT_LOG_V2 Version */ |
| static wifi_error parse_stats_record_v2(hal_info *info, |
| wh_pktlog_hdr_v2_t *pkt_stats_header) |
| { |
| wifi_error status = WIFI_SUCCESS; |
| |
| if (pkt_stats_header->log_type == PKTLOG_TYPE_RX_STAT) { |
| /* Ignore the event if it doesn't carry RX descriptor */ |
| if (pkt_stats_header->flags & PKT_INFO_FLG_RX_RXDESC_MASK) |
| status = parse_rx_stats_v2(info, |
| (u8 *)(pkt_stats_header + 1), |
| pkt_stats_header->size); |
| else |
| status = WIFI_SUCCESS; |
| } else if (pkt_stats_header->log_type == PKTLOG_TYPE_PKT_DUMP_V2) { |
| pthread_mutex_lock(&info->pkt_fate_stats_lock); |
| if (info->fate_monitoring_enabled) { |
| if (pkt_stats_header->flags & PKT_INFO_FLG_PKT_DUMP_V2) |
| status = parse_pkt_fate_stats(info, |
| (u8 *)pkt_stats_header + sizeof(wh_pktlog_hdr_v2_t), |
| pkt_stats_header->size); |
| else |
| status = WIFI_SUCCESS; |
| } else |
| status = WIFI_SUCCESS; |
| pthread_mutex_unlock(&info->pkt_fate_stats_lock); |
| } else if (pkt_stats_header->log_type == PKTLOG_TYPE_PKT_SW_EVENT) { |
| status = parse_stats_sw_event(info, pkt_stats_header); |
| } else if (pkt_stats_header->log_type == PKTLOG_TYPE_TX_STAT || |
| pkt_stats_header->log_type == PKTLOG_TYPE_RX_STATBUF || |
| pkt_stats_header->log_type == PKTLOG_TYPE_LITE_T2H || |
| pkt_stats_header->log_type == PKTLOG_TYPE_LITE_RX) { |
| //TODO Parsing of per packet log. |
| } else { |
| //No Parsing on Default packet log type. |
| } |
| return status; |
| } |
| |
| static wifi_error parse_stats_record_v1(hal_info *info, |
| wh_pktlog_hdr_t *pkt_stats_header) |
| { |
| wifi_error status; |
| if (pkt_stats_header->log_type == PKTLOG_TYPE_PKT_STATS) { |
| status = write_per_packet_stats_to_rb(info, |
| (u8 *)(pkt_stats_header + 1), |
| pkt_stats_header->size); |
| } else if (pkt_stats_header->log_type == PKTLOG_TYPE_RX_STAT) { |
| /* Ignore the event if it doesn't carry RX descriptor */ |
| if (pkt_stats_header->flags & PKT_INFO_FLG_RX_RXDESC_MASK) |
| status = parse_rx_stats(info, |
| (u8 *)(pkt_stats_header + 1), |
| pkt_stats_header->size); |
| else |
| status = WIFI_SUCCESS; |
| } else if (pkt_stats_header->log_type == PKTLOG_TYPE_PKT_DUMP || |
| pkt_stats_header->log_type == PKTLOG_TYPE_PKT_DUMP_V2) { |
| pthread_mutex_lock(&info->pkt_fate_stats_lock); |
| if (info->fate_monitoring_enabled) { |
| if (pkt_stats_header->flags & PKT_INFO_FLG_PKT_DUMP_V2) |
| status = parse_pkt_fate_stats(info, |
| (u8 *)pkt_stats_header + sizeof(wh_pktlog_hdr_v2_t), |
| pkt_stats_header->size); |
| else |
| status = parse_pkt_fate_stats(info, |
| (u8 *)pkt_stats_header + sizeof(wh_pktlog_hdr_t), |
| pkt_stats_header->size); |
| } else |
| status = WIFI_SUCCESS; |
| pthread_mutex_unlock(&info->pkt_fate_stats_lock); |
| } else { |
| status = parse_tx_stats(info, |
| (u8 *)(pkt_stats_header + 1), |
| pkt_stats_header->size, |
| pkt_stats_header->log_type); |
| } |
| return status; |
| } |
| |
| static wifi_error parse_stats(hal_info *info, u8 *data, u32 buflen) |
| { |
| wh_pktlog_hdr_t *pkt_stats_header; |
| wh_pktlog_hdr_v2_t *pkt_stats_header_v2_t; |
| wifi_error status = WIFI_SUCCESS; |
| |
| do { |
| u32 record_len; |
| |
| if (buflen < sizeof(wh_pktlog_hdr_t)) { |
| status = WIFI_ERROR_INVALID_ARGS; |
| break; |
| } |
| |
| pkt_stats_header = (wh_pktlog_hdr_t *)data; |
| pkt_stats_header_v2_t = (wh_pktlog_hdr_v2_t *)data; |
| |
| if (info->pkt_log_ver == PKT_LOG_V2) { |
| if (buflen < sizeof(wh_pktlog_hdr_v2_t)) { |
| status = WIFI_ERROR_INVALID_ARGS; |
| break; |
| } |
| record_len = (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header_v2_t->size); |
| } else { |
| if (pkt_stats_header->flags & PKT_INFO_FLG_PKT_DUMP_V2){ |
| if (buflen < sizeof(wh_pktlog_hdr_v2_t)) { |
| status = WIFI_ERROR_INVALID_ARGS; |
| break; |
| } |
| record_len = (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header_v2_t->size); |
| } else { |
| record_len = (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size); |
| } |
| } |
| |
| if (buflen < record_len) { |
| status = WIFI_ERROR_INVALID_ARGS; |
| break; |
| } |
| /* Pkt_log_V2 based packet parsing */ |
| if (info->pkt_log_ver == PKT_LOG_V2) { |
| status = parse_stats_record_v2(info, pkt_stats_header_v2_t); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to parse the stats type : %d", |
| pkt_stats_header_v2_t->log_type); |
| return status; |
| } |
| /* Pkt_log_V1 based packet parsing */ |
| } else { |
| status = parse_stats_record_v1(info, pkt_stats_header); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to parse the stats type : %d", |
| pkt_stats_header->log_type); |
| return status; |
| } |
| } |
| data += record_len; |
| buflen -= record_len; |
| |
| } while (!info->clean_up && (buflen > 0)); |
| |
| return status; |
| } |
| |
| wifi_error process_driver_prints(hal_info *info, u8 *buf, u16 length) |
| { |
| wifi_ring_buffer_entry rb_entry_hdr; |
| struct timeval time; |
| wifi_error status; |
| |
| rb_entry_hdr.entry_size = length; |
| rb_entry_hdr.flags = RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP; |
| rb_entry_hdr.type = ENTRY_TYPE_DATA; |
| gettimeofday(&time, NULL); |
| rb_entry_hdr.timestamp = (u64)time.tv_usec + (u64)time.tv_sec * 1000 * 1000; |
| |
| /* Write if verbose and handler is set */ |
| if (info->rb_infos[DRIVER_PRINTS_RB_ID].verbose_level >= 1 && |
| info->on_ring_buffer_data) { |
| /* Write header and payload separately to avoid |
| * complete payload memcpy */ |
| status = ring_buffer_write(&info->rb_infos[DRIVER_PRINTS_RB_ID], |
| (u8*)&rb_entry_hdr, |
| sizeof(wifi_ring_buffer_entry), |
| 0, |
| sizeof(wifi_ring_buffer_entry) + length); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write driver prints rb header %d", status); |
| return status; |
| } |
| status = ring_buffer_write(&info->rb_infos[DRIVER_PRINTS_RB_ID], |
| buf, length, 1, length); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("Failed to write driver prints rb payload %d", status); |
| return status; |
| } |
| } |
| |
| return WIFI_SUCCESS; |
| } |
| |
| wifi_error diag_message_handler(hal_info *info, nl_msg *msg) |
| { |
| tAniNlHdr *wnl; |
| u8 *buf; |
| wifi_error status; |
| tAniCLDHdr *clh = NULL; |
| int cmd = 0; |
| |
| if (info->cldctx) { |
| struct nlattr *attrs[CLD80211_ATTR_MAX + 1]; |
| struct genlmsghdr *genlh; |
| struct nlattr *tb_vendor[CLD80211_ATTR_MAX + 1]; |
| struct nlmsghdr *nlh = nlmsg_hdr(msg); |
| |
| genlh = (struct genlmsghdr *)nlmsg_data(nlh); |
| if (genlh->cmd == ANI_NL_MSG_PUMAC || |
| genlh->cmd == ANI_NL_MSG_LOG || |
| genlh->cmd == ANI_NL_MSG_CNSS_DIAG || |
| genlh->cmd == WLAN_NL_MSG_OEM) |
| { |
| cmd = genlh->cmd; |
| int result = nla_parse(attrs, CLD80211_ATTR_MAX, genlmsg_attrdata(genlh, 0), |
| genlmsg_attrlen(genlh, 0), NULL); |
| |
| if (!result && attrs[CLD80211_ATTR_VENDOR_DATA]) { |
| nla_parse(tb_vendor, CLD80211_ATTR_MAX, |
| (struct nlattr *)nla_data(attrs[CLD80211_ATTR_VENDOR_DATA]), |
| nla_len(attrs[CLD80211_ATTR_VENDOR_DATA]), NULL); |
| |
| if (tb_vendor[CLD80211_ATTR_DATA]) { |
| clh = (tAniCLDHdr *)nla_data(tb_vendor[CLD80211_ATTR_DATA]); |
| } |
| } else { |
| ALOGE("Invalid data received"); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| if (genlh->cmd != WLAN_NL_MSG_OEM && !clh) { |
| ALOGE("Invalid data received from driver"); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| |
| if((info->wifihal_ctrl_sock.s > 0) && (genlh->cmd == WLAN_NL_MSG_OEM)) { |
| wifihal_ctrl_event_t *ctrl_evt; |
| wifihal_mon_sock_t *reg; |
| |
| if (!(tb_vendor[CLD80211_ATTR_DATA] || tb_vendor[CLD80211_ATTR_CMD])) { |
| ALOGE("Invalid oem data received from driver"); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| ctrl_evt = (wifihal_ctrl_event_t *)malloc(sizeof(*ctrl_evt) + nlh->nlmsg_len); |
| |
| if(ctrl_evt == NULL) |
| { |
| ALOGE("Memory allocation failure"); |
| return WIFI_ERROR_OUT_OF_MEMORY; |
| } |
| memset((char *)ctrl_evt, 0, sizeof(*ctrl_evt) + nlh->nlmsg_len); |
| |
| ctrl_evt->family_name = CLD80211_FAMILY; |
| ctrl_evt->cmd_id = WLAN_NL_MSG_OEM; |
| ctrl_evt->data_len = nlh->nlmsg_len; |
| memcpy(ctrl_evt->data, (char *)nlh, ctrl_evt->data_len); |
| |
| //! Send oem data to all the registered clients |
| |
| list_for_each_entry(reg, &info->monitor_sockets, list) { |
| |
| if (reg->family_name != CLD80211_FAMILY || reg->cmd_id != WLAN_NL_MSG_OEM) |
| continue; |
| |
| /* found match! */ |
| /* Indicate the received OEM msg to respective client |
| it is responsibility of the registered client to check |
| the oem_msg is meant for them or not based on oem_msg sub type */ |
| ALOGI("send oem msg of len : %d to apps",ctrl_evt->data_len); |
| if (sendto(info->wifihal_ctrl_sock.s, (char *)ctrl_evt, |
| sizeof(*ctrl_evt) + ctrl_evt->data_len, 0, |
| (struct sockaddr *)®->monsock, reg->monsock_len) < 0) |
| { |
| int _errno = errno; |
| ALOGE("socket send failed : %d",_errno); |
| |
| if (_errno == ENOBUFS || _errno == EAGAIN) { |
| /* |
| * The socket send buffer could be full. This |
| * may happen if client programs are not |
| * receiving their pending messages. Close and |
| * reopen the socket as a workaround to avoid |
| * getting stuck being unable to send any new |
| * responses. |
| */ |
| } |
| } |
| } |
| free(ctrl_evt); |
| return WIFI_SUCCESS; |
| } |
| } |
| } else { |
| wnl = (tAniNlHdr *)nlmsg_hdr(msg); |
| cmd = wnl->nlh.nlmsg_type; |
| } |
| |
| /* Check nlmsg_type also to avoid processing unintended msgs */ |
| if (cmd == ANI_NL_MSG_PUMAC) { |
| if (!info->cldctx) { |
| if ((wnl->nlh.nlmsg_len <= sizeof(tAniNlHdr)) || |
| (wnl->nlh.nlmsg_len < (sizeof(tAniNlHdr) + ntohs(wnl->clh.wmsg.length)))) { |
| ALOGV("Received UMAC message with insufficent length: %d", |
| wnl->nlh.nlmsg_len); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| clh = &wnl->clh; |
| } |
| if (clh->wmsg.type == ANI_NL_MSG_LOG_HOST_EVENT_LOG_TYPE) { |
| uint32_t diag_host_type; |
| |
| buf = (uint8_t *)(clh + 1); |
| diag_host_type = *(uint32_t *)(buf); |
| #ifdef QC_HAL_DEBUG |
| ALOGV("diag type = %d", diag_host_type); |
| #endif |
| buf += sizeof(uint32_t); //diag_type |
| if (diag_host_type == DIAG_TYPE_HOST_EVENTS) { |
| host_event_hdr_t *event_hdr = |
| (host_event_hdr_t *)(buf); |
| #ifdef QC_HAL_DEBUG |
| ALOGV("diag event_id = %x length %d", |
| event_hdr->event_id, event_hdr->length); |
| #endif |
| buf += sizeof(host_event_hdr_t); |
| switch (event_hdr->event_id) { |
| case EVENT_WLAN_WAKE_LOCK: |
| process_wakelock_event(info, buf, event_hdr->length); |
| break; |
| case EVENT_WLAN_PE: |
| process_wlan_pe_event(info, buf, event_hdr->length); |
| break; |
| case EVENT_WLAN_EAPOL: |
| process_wlan_eapol_event(info, buf, event_hdr->length); |
| break; |
| case EVENT_WLAN_LOG_COMPLETE: |
| process_wlan_log_complete_event(info, buf, event_hdr->length); |
| break; |
| case EVENT_WLAN_LOW_RESOURCE_FAILURE: |
| process_wlan_low_resource_failure(info, buf, event_hdr->length); |
| break; |
| case EVENT_WLAN_STA_DATA_STALL: |
| process_wlan_data_stall_event(info, buf, event_hdr->length); |
| break; |
| case EVENT_WLAN_POWERSAVE_WOW: |
| case EVENT_WLAN_POWERSAVE_WOW_STATS: |
| case EVENT_WLAN_STA_KICKOUT: |
| case EVENT_WLAN_BRINGUP_STATUS: |
| /* Handle DIAG events properly */ |
| break; |
| default: |
| return WIFI_SUCCESS; |
| } |
| } else if (diag_host_type == DIAG_TYPE_HOST_LOG_MSGS) { |
| drv_msg_t *drv_msg = (drv_msg_t *) (buf); |
| #ifdef QC_HAL_DEBUG |
| ALOGV("diag event_type = %0x length = %d", |
| drv_msg->event_type, drv_msg->length); |
| #endif |
| if (drv_msg->event_type == WLAN_PKT_LOG_STATS) { |
| if ((info->prev_seq_no + 1) != |
| drv_msg->u.pkt_stats_event.msg_seq_no) { |
| ALOGE("Few pkt stats messages missed: rcvd = %d, prev = %d", |
| drv_msg->u.pkt_stats_event.msg_seq_no, |
| info->prev_seq_no); |
| if (info->pkt_stats->tx_stats_events) { |
| info->pkt_stats->tx_stats_events = 0; |
| memset(&info->pkt_stats->tx_stats, 0, |
| sizeof(wifi_ring_per_packet_status_entry)); |
| } |
| } |
| |
| info->prev_seq_no = |
| drv_msg->u.pkt_stats_event.msg_seq_no; |
| status = parse_stats(info, |
| drv_msg->u.pkt_stats_event.payload, |
| drv_msg->u.pkt_stats_event.payload_len); |
| if (status != WIFI_SUCCESS) { |
| ALOGE("%s: Failed to parse Tx-Rx stats", __FUNCTION__); |
| ALOGE("Received msg Seq_num : %d", |
| drv_msg->u.pkt_stats_event.msg_seq_no); |
| hexdump((char *)drv_msg->u.pkt_stats_event.payload, |
| drv_msg->u.pkt_stats_event.payload_len); |
| return status; |
| } |
| } |
| } |
| } |
| } else if (cmd == ANI_NL_MSG_LOG) { |
| if (!info->cldctx) { |
| if ((wnl->nlh.nlmsg_len <= sizeof(tAniNlHdr)) || |
| (wnl->nlh.nlmsg_len < (sizeof(tAniNlHdr) + wnl->clh.wmsg.length))) { |
| ALOGE("Received LOG message with insufficent length: %d", |
| wnl->nlh.nlmsg_len); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| clh = &wnl->clh; |
| } |
| if (clh->wmsg.type == ANI_NL_MSG_LOG_HOST_PRINT_TYPE) { |
| process_driver_prints(info, (u8 *)(clh + 1), clh->wmsg.length); |
| } else if (clh->wmsg.type == ANI_NL_MSG_LOG_FW_MSG_TYPE) { |
| process_firmware_prints(info, (u8 *)(clh + 1), clh->wmsg.length); |
| } |
| } else if (cmd == ANI_NL_MSG_CNSS_DIAG) { |
| uint16_t diag_fw_type; |
| struct nlmsghdr *nlh = nlmsg_hdr(msg); |
| |
| if (!info->cldctx) { |
| buf = (uint8_t *)NLMSG_DATA(wnl) + sizeof(wnl->clh.radio); |
| } else { |
| buf = (uint8_t *)&clh->wmsg; |
| } |
| |
| fw_event_hdr_t *event_hdr = |
| (fw_event_hdr_t *)(buf); |
| if (!info->cldctx) { |
| if ((wnl->nlh.nlmsg_len <= NLMSG_HDRLEN + sizeof(fw_event_hdr_t)) || |
| (wnl->nlh.nlmsg_len < (NLMSG_HDRLEN + sizeof(fw_event_hdr_t) + |
| event_hdr->length))) { |
| ALOGE("Received CNSS_DIAG message with insufficent length: %d", |
| wnl->nlh.nlmsg_len); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| } else { |
| if (nlh->nlmsg_len <= NLMSG_HDRLEN + sizeof(dbglog_slot)) { |
| ALOGE("Received CNSS_DIAG message with insufficent length: %d: %s:%d", |
| nlh->nlmsg_len, __FUNCTION__, __LINE__); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| } |
| diag_fw_type = event_hdr->diag_type; |
| if (diag_fw_type == DIAG_TYPE_FW_MSG) { |
| dbglog_slot *slot; |
| u32 length = 0; |
| |
| slot = (dbglog_slot *)buf; |
| length = get_le32((u8 *)&slot->length); |
| if (nlh->nlmsg_len < (NLMSG_HDRLEN + sizeof(dbglog_slot) + |
| length)) { |
| ALOGE("Received CNSS_DIAG message with insufficent length: %d:" |
| " expected: %zu, %s:%d", |
| nlh->nlmsg_len, |
| (NLMSG_HDRLEN + sizeof(dbglog_slot) +length), |
| __FUNCTION__, |
| __LINE__); |
| return WIFI_ERROR_UNKNOWN; |
| } |
| process_fw_diag_msg(info, &slot->payload[0], length); |
| } |
| } |
| return WIFI_SUCCESS; |
| } |