1 // Copyright 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "hci/hci_packet_transport.h"
16 
17 #include <limits>
18 #include <memory>
19 #include <optional>
20 
21 #include "model/hci/hci_transport.h"
22 #include "netsim-daemon/src/ffi.rs.h"
23 #include "netsim/hci_packet.pb.h"
24 #include "netsim/stats.pb.h"
25 #include "rust/cxx.h"
26 #include "util/log.h"
27 
28 using netsim::packet::HCIPacket;
29 
30 namespace netsim {
31 namespace hci {
32 
33 std::unordered_map<uint32_t, std::shared_ptr<HciPacketTransport>>
34     rootcanal_id_to_transport_;
35 
36 /**
37  * @class HciPacketTransport
38  *
39  * Connects hci packets between packet_hub and rootcanal.
40  *
41  */
HciPacketTransport(uint32_t chip_id,std::shared_ptr<rootcanal::AsyncManager> async_manager)42 HciPacketTransport::HciPacketTransport(
43     uint32_t chip_id, std::shared_ptr<rootcanal::AsyncManager> async_manager)
44     : rootcanalId(std::nullopt),
45       netsimChipId(chip_id),
46       mAsyncManager(std::move(async_manager)) {}
47 
48 /**
49  * @brief Connect the phy device to the transport
50  *
51  * @param - rootcanal_id identifier of the owning device
52  *
53  * @param - chip_id identifier generated from netsimd
54  */
Connect(rootcanal::PhyDevice::Identifier rootcanal_id)55 void HciPacketTransport::Connect(
56     rootcanal::PhyDevice::Identifier rootcanal_id) {
57   assert(!rootcanalId.has_value());
58   rootcanalId.emplace(rootcanal_id);
59 }
60 
61 // Called by HCITransport (rootcanal)
Send(rootcanal::PacketType packet_type,const std::vector<uint8_t> & data)62 void HciPacketTransport::Send(rootcanal::PacketType packet_type,
63                               const std::vector<uint8_t> &data) {
64   // The packet types have standard values, converting from
65   // rootcanal::PacketType to HCIPacket_PacketType is safe.
66   packet::HCIPacket_PacketType hci_packet_type =
67       static_cast<packet::HCIPacket_PacketType>(packet_type);
68   if (!rootcanalId.has_value()) {
69     BtsLogWarn("hci_packet_transport: response with no device.");
70     return;
71   }
72   // Send response to transport dispatcher.
73   netsim::wireless::HandleResponse(netsimChipId, data, hci_packet_type);
74 }
75 
76 // Called by HCITransport (rootcanal)
RegisterCallbacks(rootcanal::PacketCallback packetCallback,rootcanal::CloseCallback closeCallback)77 void HciPacketTransport::RegisterCallbacks(
78     rootcanal::PacketCallback packetCallback,
79     rootcanal::CloseCallback closeCallback) {
80   BtsLogInfo("hci_packet_transport: registered");
81   mPacketCallback = packetCallback;
82   mCloseCallback = closeCallback;
83 }
84 
85 // Called by HCITransport (rootcanal)
Tick()86 void HciPacketTransport::Tick() {}
87 
Request(packet::HCIPacket_PacketType packet_type,const std::shared_ptr<std::vector<uint8_t>> & packet)88 void HciPacketTransport::Request(
89     packet::HCIPacket_PacketType packet_type,
90     const std::shared_ptr<std::vector<uint8_t>> &packet) {
91   assert(mPacketCallback);
92   // The packet types have standard values, converting from
93   // HCIPacket_PacketType to rootcanal::PacketType is safe.
94   rootcanal::PacketType rootcanal_packet_type =
95       static_cast<rootcanal::PacketType>(packet_type);
96   auto beforeScheduleTime = std::chrono::steady_clock::now();
97   mAsyncManager->Synchronize(
98       [this, rootcanal_packet_type, packet, beforeScheduleTime]() {
99         auto elapsedTime =
100             std::chrono::duration_cast<std::chrono::milliseconds>(
101                 std::chrono::steady_clock::now() - beforeScheduleTime)
102                 .count();
103         // If the elapsed time of the packet delivery is greater than 5ms,
104         // report invalid packet with DELAYED reasoning.
105         if (elapsedTime > 5) {
106           netsim::hci::facade::ReportInvalidPacket(
107               this->rootcanalId.value(),
108               stats::InvalidPacket_Reason::InvalidPacket_Reason_DELAYED,
109               "Delayed packet with " + std::to_string(elapsedTime) +
110                   " milliseconds",
111               *packet);
112         }
113         mPacketCallback(rootcanal_packet_type, packet);
114       });
115 }
116 
Add(rootcanal::PhyDevice::Identifier rootcanal_id,const std::shared_ptr<HciPacketTransport> & transport)117 void HciPacketTransport::Add(
118     rootcanal::PhyDevice::Identifier rootcanal_id,
119     const std::shared_ptr<HciPacketTransport> &transport) {
120   transport->Connect(rootcanal_id);
121   rootcanal_id_to_transport_[rootcanal_id] = transport;
122 }
123 
Remove(rootcanal::PhyDevice::Identifier rootcanal_id)124 void HciPacketTransport::Remove(rootcanal::PhyDevice::Identifier rootcanal_id) {
125   BtsLogInfo("hci_packet_transport remove from netsim");
126   if (rootcanal_id_to_transport_.find(rootcanal_id) !=
127           rootcanal_id_to_transport_.end() &&
128       rootcanal_id_to_transport_[rootcanal_id]) {
129     // Calls HciDevice::Close, will disconnect AclHandles with
130     // CONNECTION_TIMEOUT, and call TestModel::CloseCallback.
131     rootcanal_id_to_transport_[rootcanal_id]->mCloseCallback();
132   }
133 }
134 
135 // Called by HciDevice::Close
Close()136 void HciPacketTransport::Close() {
137   if (rootcanalId.has_value()) {
138     rootcanal_id_to_transport_.erase(rootcanalId.value());
139   }
140   BtsLogInfo("hci_packet_transport close from rootcanal");
141   rootcanalId = std::nullopt;
142 }
143 
144 // handle_request is the main entry for incoming packets called by
145 // netsim::packet_hub
146 //
147 // Transfer the request to the HciTransport to deliver to Rootcanal via the
148 // acl/sco/iso/command callback methods under synchronization.
handle_bt_request(uint32_t rootcanal_id,packet::HCIPacket_PacketType packet_type,const std::shared_ptr<std::vector<uint8_t>> & packet)149 void handle_bt_request(uint32_t rootcanal_id,
150                        packet::HCIPacket_PacketType packet_type,
151                        const std::shared_ptr<std::vector<uint8_t>> &packet) {
152   if (rootcanal_id_to_transport_.find(rootcanal_id) !=
153           rootcanal_id_to_transport_.end() &&
154       rootcanal_id_to_transport_[rootcanal_id]) {
155     auto transport = rootcanal_id_to_transport_[rootcanal_id];
156     transport->Request(packet_type, packet);
157   } else {
158     std::cout << "rootcanal_id_to_transport_ ids ";
159     for (auto [k, _] : rootcanal_id_to_transport_) std::cout << k << " ";
160     std::cout << std::endl;
161     BtsLogWarn(
162         "hci_packet_transport: handle_request with no transport for device "
163         "with rootcanal_id: %d",
164         rootcanal_id);
165   }
166 }
167 
HandleBtRequestCxx(uint32_t rootcanal_id,uint8_t packet_type,const rust::Vec<uint8_t> & packet)168 void HandleBtRequestCxx(uint32_t rootcanal_id, uint8_t packet_type,
169                         const rust::Vec<uint8_t> &packet) {
170   std::vector<uint8_t> buffer(packet.begin(), packet.end());
171   auto packet_ptr = std::make_shared<std::vector<uint8_t>>(buffer);
172   handle_bt_request(rootcanal_id,
173                     static_cast<packet::HCIPacket_PacketType>(packet_type),
174                     packet_ptr);
175 }
176 
177 }  // namespace hci
178 }  // namespace netsim
179