unplugged-vendor/system/bt/mediatek/hci/snoop_packetizer.cc

279 lines
9.7 KiB
C++

/* Copyright Statement:
* *
* * This software/firmware and related documentation ("MediaTek Software") are
* * protected under relevant copyright laws. The information contained herein
* * is confidential and proprietary to MediaTek Inc. and/or its licensors.
* * Without the prior written permission of MediaTek inc. and/or its licensors,
* * any reproduction, modification, use or disclosure of MediaTek Software,
* * and information contained herein, in whole or in part, shall be strictly prohibited.
* *
* * MediaTek Inc. (C) 2016. All rights reserved.
* *
* * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
* * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
* * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
* * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
* * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
* * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
* * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
* * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
* *
* * The following software/firmware and/or related documentation ("MediaTek Software")
* * have been modified by MediaTek Inc. All revisions are subject to any receiver's
* * applicable license agreements with MediaTek Inc.
* */
#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
#define LOG_TAG "bt_log_snoop_packetizer"
#include "snoop_packetizer.h"
#include <inttypes.h>
#include <netinet/in.h>
#include <string.h>
#include <base/logging.h>
#include <base/synchronization/waitable_event.h>
#include "bt_hci_bdroid.h"
#include "bt_types.h"
#include "mtk_util.h"
#include "osi/include/log.h"
#include "snoop_log_config.h"
namespace vendor {
namespace mediatek {
namespace bt {
namespace stack {
BTSnoopPacketWrapper& BTSnoopPacketWrapper::operator=(
const BTSnoopPacketWrapper& wrapper) {
if (this != &wrapper) {
is_received_ = wrapper.is_received();
timestamp_us_ = wrapper.timestamp_us();
delete [] buffer_;
buffer_ = Clone(wrapper.buffer());
}
return *this;
}
BTSnoopPacketWrapper::~BTSnoopPacketWrapper() {
if (buffer_) {
delete [] buffer_;
buffer_ = nullptr;
}
}
BT_HDR* BTSnoopPacketWrapper::Clone(const BT_HDR* buffer) {
BT_HDR* packet = nullptr;
if (buffer) {
// Total buffer size = len + offset
size_t packet_size = buffer->len + sizeof(BT_HDR) + buffer->offset;
packet = reinterpret_cast<BT_HDR*>(new uint8_t[packet_size]);
if (packet) {
packet->offset = buffer->offset;
packet->len = buffer->len;
packet->layer_specific = buffer->layer_specific;
packet->event = buffer->event;
memcpy(packet->data, buffer->data, buffer->len+buffer->offset);
}
}
return packet;
}
void BtSnoopPacketizer::OnDataReady(const BT_HDR* buffer,
bool is_received, uint64_t timestamp_us) {
parcels_.push_back(MakeParcel(buffer, is_received, timestamp_us));
if (IsParcelReady()) {
parcels_ready_cb_(parcels_, NULL);
parcels_.clear();
}
}
BTSnoopParcel BtSnoopPacketizer::MakeParcel(const BT_HDR* buffer,
bool is_received, uint64_t timestamp_us) {
uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
switch (buffer->event & MSG_EVT_MASK) {
case MSG_HC_TO_STACK_HCI_EVT:
return ComposePackets(kEventPacket, p, false, timestamp_us);
case MSG_HC_TO_STACK_HCI_ACL:
case MSG_STACK_TO_HC_HCI_ACL:
return ComposePackets(kAclPacket, p, is_received, timestamp_us);
case MSG_HC_TO_STACK_HCI_SCO:
case MSG_STACK_TO_HC_HCI_SCO:
return ComposePackets(kScoPacket, p, is_received, timestamp_us);
case MSG_HC_TO_STACK_HCI_ISO:
case MSG_STACK_TO_HC_HCI_ISO:
return ComposePackets(kIsoPacket, p, is_received, timestamp_us);
case MSG_STACK_TO_HC_HCI_CMD:
return ComposePackets(kCommandPacket, p, true, timestamp_us);
default: {
// Should never goes into here
LOG_ALWAYS_FATAL(
"%s: invalid: is_received: %d, buffer: event: %u, len: %u, data: %s",
__func__, is_received, buffer->event, buffer->len,
DataArrayToString<uint8_t>(buffer->data, buffer->len).c_str());
// Dummy call here
return ComposePackets(kEventPacket, p, false, timestamp_us);
}
}
}
BTSnoopParcel BtSnoopPacketizer::ComposePackets(PacketType type,
uint8_t* packet, bool is_received, uint64_t timestamp_us) {
uint32_t length_he = 0;
uint32_t flags = 0;
switch (type) {
case kCommandPacket:
length_he = packet[2] + 4;
flags = 2;
break;
case kAclPacket:
length_he = (packet[3] << 8) + packet[2] + 5;
flags = is_received;
break;
case kScoPacket:
length_he = packet[2] + 4;
flags = is_received;
break;
case kEventPacket:
length_he = packet[1] + 3;
flags = 3;
break;
case kIsoPacket:
length_he = ((packet[3] & 0x3F) << 8) + packet[2] + 5;
flags = is_received;
LOG_DEBUG("%s [IsoTest][%d] data: %s", __func__, flags, DataArrayToString<uint8_t>(packet, (length_he - 1)).c_str());
break;
}
btsnoop_header_t header;
header.length_original = htonl(length_he);
header.length_captured = header.length_original;
header.flags = htonl(flags);
header.dropped_packets = 0;
header.timestamp = timestamp_us;
header.type = type;
/*LOG_DEBUG("%s len_ori: %x, len_captured: %x, flags: %x, type: %x",
__func__, header.length_original, header.length_captured,
header.flags, header.type);
LOG_DEBUG("%s data: %s", __func__,
DataArrayToString<uint8_t>(packet, (length_he - 1)).c_str());*/
std::vector<uint8_t> packets(packet, (packet + (length_he - 1)));
BTSnoopParcel parcel(std::move(header), std::move(packets));
packet_ready_cb_(parcel);
return parcel;
}
void BtSnoopPacketizer::OnShutdown(base::WaitableEvent* event) {
if (parcels_.size()) {
parcels_ready_cb_(parcels_, event);
parcels_.clear();
} else {
// No left data, to notify event directly
if (event) {
event->Signal();
}
}
}
BTSnoopParcel BtSnoopPacketizer::ConvertToParcel(
const BTSnoopPacketWrapper& packet) {
// TODO: change this chatty LOG_INFO into DBG_LOG when it is stable
LOG_INFO(
"%s: wrapper: is_received: %d, "
"buffer: event: 0x%x, len: %u, offset: %u, "
"layer_specific: %u, data: %s",
__func__,
packet.is_received(),
packet.buffer()->event, packet.buffer()->len,
packet.buffer()->offset, packet.buffer()->layer_specific,
DataArrayToString<uint8_t>(
packet.buffer()->data,
packet.buffer()->len).c_str());
return MakeParcel(packet.buffer(),
packet.is_received(),
packet.timestamp_us());
}
bool BtSnoopPacketizer::IsParcelReady() {
return (parcels_.size() >=
static_cast<size_t>(
SnoopLogConfig::GetInstance()->GetPacketCacheUpperLimit()));
}
bool BtSnoopPacketizer::Validate(const BT_HDR* buffer, bool is_received) {
bool is_valid(false);
if (buffer) {
uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
switch (buffer->event & MSG_EVT_MASK) {
case MSG_HC_TO_STACK_HCI_EVT:
// 1 byte (event type) + 1 byte event length (p1]) + event data
is_valid = ((p[1] + 2) == buffer->len);
break;
case MSG_HC_TO_STACK_HCI_ACL:
case MSG_STACK_TO_HC_HCI_ACL:
// 2 byte (handle) + 2 byte acl length (p[3]<<8 + p[2]) + acl data
is_valid = (((p[3] << 8) + p[2] + 4) == buffer->len);
break;
case MSG_HC_TO_STACK_HCI_SCO:
case MSG_STACK_TO_HC_HCI_SCO:
is_valid = ((p[2] + 3) == buffer->len);
break;
case MSG_HC_TO_STACK_HCI_ISO:
case MSG_STACK_TO_HC_HCI_ISO:
// 2 byte (handle) + 2 byte iso length (p[3]<<8 + p[2]) + iso data
is_valid = ((((p[3] & 0x3F) << 8) + p[2] + 4) == buffer->len);
break;
case MSG_STACK_TO_HC_HCI_CMD:
// 2 byte (OP code) + 1 byte cmd length (p[2] + cmd data length
is_valid = ((p[2] + 3) == buffer->len);
break;
default: {
// Should never goes into here
LOG_ALWAYS_FATAL(
"%s: invalid: is_received: %d, buffer: event: %u, len: %u, "
"data: %s",
__func__, is_received, buffer->event, buffer->len,
DataArrayToString<uint8_t>(buffer->data, buffer->len).c_str());
break;
}
}
}
if (!is_valid) {
LOG_INFO(
"%s: invalid data, to be dropped: is_received: %d, "
"buffer: %p, event: 0x%x, len: %u, offset: %u, "
"layer_specific: %u, data: %s",
__func__,
is_received, buffer,
buffer->event, buffer->len,
buffer->offset, buffer->layer_specific,
DataArrayToString<uint8_t>(buffer->data,
buffer->len).c_str());
}
return is_valid;
}
} // namespace stack
} // namespace bt
} // namespace mediatek
} // namespace vendor
#endif