blob: 81de642de1be912758b27036d20e057aadc17218 [file] [log] [blame]
// Copyright 2022 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/hci_packet_transport.h"
#include <limits>
#include <memory>
#include <optional>
#include "model/hci/hci_transport.h"
#include "netsim-daemon/src/ffi.rs.h"
#include "netsim/hci_packet.pb.h"
#include "rust/cxx.h"
#include "util/log.h"
using netsim::packet::HCIPacket;
namespace netsim {
namespace hci {
std::unordered_map<uint32_t, std::shared_ptr<HciPacketTransport>>
rootcanal_id_to_transport_;
/**
* @class HciPacketTransport
*
* Connects hci packets between packet_hub and rootcanal.
*
*/
HciPacketTransport::HciPacketTransport(
uint32_t chip_id, std::shared_ptr<rootcanal::AsyncManager> async_manager)
: rootcanalId(std::nullopt),
netsimChipId(chip_id),
mAsyncManager(std::move(async_manager)) {}
/**
* @brief Connect the phy device to the transport
*
* @param - rootcanal_id identifier of the owning device
*
* @param - chip_id identifier generated from netsimd
*/
void HciPacketTransport::Connect(
rootcanal::PhyDevice::Identifier rootcanal_id) {
assert(!rootcanalId.has_value());
rootcanalId.emplace(rootcanal_id);
}
// Called by HCITransport (rootcanal)
void HciPacketTransport::Send(rootcanal::PacketType packet_type,
const std::vector<uint8_t> &data) {
// The packet types have standard values, converting from
// rootcanal::PacketType to HCIPacket_PacketType is safe.
packet::HCIPacket_PacketType hci_packet_type =
static_cast<packet::HCIPacket_PacketType>(packet_type);
if (!rootcanalId.has_value()) {
BtsLogWarn("hci_packet_transport: response with no device.");
return;
}
// Send response to transport dispatcher.
netsim::echip::HandleResponse(netsimChipId, data, hci_packet_type);
}
// Called by HCITransport (rootcanal)
void HciPacketTransport::RegisterCallbacks(
rootcanal::PacketCallback packetCallback,
rootcanal::CloseCallback closeCallback) {
BtsLogInfo("hci_packet_transport: registered");
mPacketCallback = packetCallback;
mCloseCallback = closeCallback;
}
// Called by HCITransport (rootcanal)
void HciPacketTransport::Tick() {}
void HciPacketTransport::Request(
packet::HCIPacket_PacketType packet_type,
const std::shared_ptr<std::vector<uint8_t>> &packet) {
assert(mPacketCallback);
// The packet types have standard values, converting from
// HCIPacket_PacketType to rootcanal::PacketType is safe.
rootcanal::PacketType rootcanal_packet_type =
static_cast<rootcanal::PacketType>(packet_type);
mAsyncManager->Synchronize([this, rootcanal_packet_type, packet]() {
mPacketCallback(rootcanal_packet_type, packet);
});
}
void HciPacketTransport::Add(
rootcanal::PhyDevice::Identifier rootcanal_id,
const std::shared_ptr<HciPacketTransport> &transport) {
transport->Connect(rootcanal_id);
rootcanal_id_to_transport_[rootcanal_id] = transport;
}
void HciPacketTransport::Remove(rootcanal::PhyDevice::Identifier rootcanal_id) {
BtsLogInfo("hci_packet_transport remove from netsim");
if (rootcanal_id_to_transport_.find(rootcanal_id) !=
rootcanal_id_to_transport_.end() &&
rootcanal_id_to_transport_[rootcanal_id]) {
// Calls HciDevice::Close, will disconnect AclHandles with
// CONNECTION_TIMEOUT, and call TestModel::CloseCallback.
rootcanal_id_to_transport_[rootcanal_id]->mCloseCallback();
}
}
// Called by HciDevice::Close
void HciPacketTransport::Close() {
if (rootcanalId.has_value()) {
rootcanal_id_to_transport_.erase(rootcanalId.value());
}
BtsLogInfo("hci_packet_transport close from rootcanal");
rootcanalId = std::nullopt;
}
// handle_request is the main entry for incoming packets called by
// netsim::packet_hub
//
// Transfer the request to the HciTransport to deliver to Rootcanal via the
// acl/sco/iso/command callback methods under synchronization.
void handle_bt_request(uint32_t rootcanal_id,
packet::HCIPacket_PacketType packet_type,
const std::shared_ptr<std::vector<uint8_t>> &packet) {
if (rootcanal_id_to_transport_.find(rootcanal_id) !=
rootcanal_id_to_transport_.end() &&
rootcanal_id_to_transport_[rootcanal_id]) {
auto transport = rootcanal_id_to_transport_[rootcanal_id];
transport->Request(packet_type, packet);
} else {
std::cout << "rootcanal_id_to_transport_ ids ";
for (auto [k, _] : rootcanal_id_to_transport_) std::cout << k << " ";
std::cout << std::endl;
BtsLogWarn(
"hci_packet_transport: handle_request with no transport for device "
"with rootcanal_id: %d",
rootcanal_id);
}
}
void HandleBtRequestCxx(uint32_t rootcanal_id, uint8_t packet_type,
const rust::Vec<uint8_t> &packet) {
std::vector<uint8_t> buffer(packet.begin(), packet.end());
auto packet_ptr = std::make_shared<std::vector<uint8_t>>(buffer);
handle_bt_request(rootcanal_id,
static_cast<packet::HCIPacket_PacketType>(packet_type),
packet_ptr);
}
} // namespace hci
} // namespace netsim