/* Copyright (c) 2015, 2018 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. */ /* 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 #include #include #include #include #include #include "wifiloggercmd.h" #include "wifilogger_event_defs.h" #include "wifilogger_diag.h" #include "wifilogger_vendor_tag_defs.h" #include "pkt_stats.h" 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 = time.tv_usec + 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; 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); memset(&cap_vendor_data, 0, sizeof(gscan_capabilities_vendor_data_t)); 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; pConnectEvent->event = WIFI_EVENT_ROAM_CANDIDATE_FOUND; pRoamCandidateFound = (wlan_roam_candidate_found_payload_type *)buf; memset(&roamCandidateFoundVendata, 0, sizeof(roam_candidate_found_vendor_data_t)); 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 = time.tv_usec + 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 */ 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, u16 length) { u16 count = 0, id; u16 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 (length > (count + sizeof(fw_diag_msg_fixed_hdr_t))) { diag_msg_fixed_hdr = (fw_diag_msg_fixed_hdr_t *)(buf + count); 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; } 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; } 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; 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; 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); 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 = time.tv_usec + 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 fatal 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; ALOGV("Received Data Stall Event from Driver"); event = (wlan_data_stall_event_t *)buf; ALOGE("Received Data Stall event, sending alert %d", event->reason); send_alert(info, DATA_STALL_OFFSET_REASON_CODE + event->reason); } 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 = time.tv_usec + time.tv_sec * 1000 * 1000; // Write if verbose and handler is set if ((info->rb_infos[PKT_STATS_RB_ID].verbose_level >= VERBOSE_REPRO_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 (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 = time.tv_usec + time.tv_sec * 1000 * 1000; /* Write if verbose and handler is set */ if (info->rb_infos[PKT_STATS_RB_ID].verbose_level >= VERBOSE_REPRO_PROBLEM && 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 (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; itx_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,node_pkt_len,i; wifi_error status = WIFI_SUCCESS; node_pkt_stats node_pkt_t; 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); 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; } 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; } } while (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 ALOGE("%s: invalid log_type %d",__FUNCTION__, pkt_stats_header->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_t; wifi_error status = WIFI_SUCCESS; do { if (buflen < sizeof(wh_pktlog_hdr_t)) { status = WIFI_ERROR_INVALID_ARGS; break; } pkt_stats_header = (wh_pktlog_hdr_t *)data; if (buflen < (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size)) { status = WIFI_ERROR_INVALID_ARGS; break; } /* Pkt_log_V2 based packet parsing */ if (info->pkt_log_ver == PKT_LOG_V2) { pkt_stats_header_t = (wh_pktlog_hdr_v2_t *)data; status = parse_stats_record_v2(info, pkt_stats_header_t); if (status != WIFI_SUCCESS) { ALOGE("Failed to parse the stats type : %d", pkt_stats_header_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; } } if (info->pkt_log_ver == PKT_LOG_V2) { data += (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); buflen -= (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); } else { if (pkt_stats_header->flags & PKT_INFO_FLG_PKT_DUMP_V2){ data += (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); buflen -= (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); } else { data += (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size); buflen -= (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size); } } } while (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 = time.tv_usec + 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) { 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]); } } if (!clh) { ALOGE("Invalid data received from driver"); 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)))) { ALOGE("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; 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; u16 length = 0; slot = (dbglog_slot *)buf; if (nlh->nlmsg_len < (NLMSG_HDRLEN + sizeof(dbglog_slot) + slot->length)) { ALOGE("Received CNSS_DIAG message with insufficent length: %d:" " expected: %zu, %s:%d", nlh->nlmsg_len, (NLMSG_HDRLEN + sizeof(dbglog_slot) +slot->length), __FUNCTION__, __LINE__); return WIFI_ERROR_UNKNOWN; } length = get_le32((u8 *)&slot->length); process_fw_diag_msg(info, &slot->payload[0], length); } } return WIFI_SUCCESS; }