You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2300 lines
95 KiB
2300 lines
95 KiB
/* 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. |
|
*/ |
|
|
|
/* 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" |
|
|
|
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); |
|
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; |
|
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_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_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 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(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(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 >= 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 (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; |
|
} |
|
|
|
|
|
static wifi_error parse_stats_record(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; |
|
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; |
|
} |
|
status = parse_stats_record(info, pkt_stats_header); |
|
if (status != WIFI_SUCCESS) { |
|
ALOGE("Failed to parse the stats type : %d", |
|
pkt_stats_header->log_type); |
|
return status; |
|
} |
|
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; |
|
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; |
|
}
|
|
|