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