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