/* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "hci_sniffer.h" #include "pcap.h" namespace rootcanal { HciSniffer::HciSniffer(std::shared_ptr transport, std::shared_ptr outputStream) : transport_(transport) { SetOutputStream(outputStream); } void HciSniffer::SetOutputStream(std::shared_ptr outputStream) { output_ = outputStream; if (output_) { uint32_t linktype = 201; // http://www.tcpdump.org/linktypes.html // LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR pcap::WriteHeader(*output_, linktype); } } void HciSniffer::AppendRecord(PacketDirection packet_direction, PacketType packet_type, const std::vector& packet) { if (output_ == nullptr) { return; } pcap::WriteRecordHeader(*output_, 4 + 1 + packet.size()); // http://www.tcpdump.org/linktypes.html LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR char direction[4] = {0, 0, 0, static_cast(packet_direction)}; uint8_t idc = static_cast(packet_type); output_->write(direction, sizeof(direction)); output_->write((char*)&idc, 1); output_->write((char*)packet.data(), packet.size()); output_->flush(); } void HciSniffer::RegisterCallbacks(PacketCallback command_callback, PacketCallback acl_callback, PacketCallback sco_callback, PacketCallback iso_callback, CloseCallback close_callback) { transport_->RegisterCallbacks( [this, command_callback](const std::shared_ptr> command) { AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::COMMAND, *command); command_callback(command); }, [this, acl_callback](const std::shared_ptr> acl) { AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::ACL, *acl); acl_callback(acl); }, [this, sco_callback](const std::shared_ptr> sco) { AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::SCO, *sco); sco_callback(sco); }, [this, iso_callback](const std::shared_ptr> iso) { AppendRecord(PacketDirection::HOST_TO_CONTROLLER, PacketType::ISO, *iso); iso_callback(iso); }, close_callback); } void HciSniffer::TimerTick() { transport_->TimerTick(); } void HciSniffer::Close() { transport_->Close(); output_->flush(); } void HciSniffer::SendEvent(const std::vector& packet) { AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::EVENT, packet); transport_->SendEvent(packet); } void HciSniffer::SendAcl(const std::vector& packet) { AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::ACL, packet); transport_->SendAcl(packet); } void HciSniffer::SendSco(const std::vector& packet) { AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::SCO, packet); transport_->SendSco(packet); } void HciSniffer::SendIso(const std::vector& packet) { AppendRecord(PacketDirection::CONTROLLER_TO_HOST, PacketType::ISO, packet); transport_->SendIso(packet); } } // namespace rootcanal