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 100ms,
104 // report invalid packet with DELAYED reasoning.
105 if (elapsedTime > 100) {
106 // Create a new vector to hold the combined data
107 std::vector<uint8_t> combinedPacket;
108
109 // Prepend rootcanal_packet_type
110 combinedPacket.push_back(static_cast<uint8_t>(rootcanal_packet_type));
111
112 // Append the original packet data
113 combinedPacket.insert(combinedPacket.end(), packet->begin(),
114 packet->end());
115
116 // Report Invalid Packet
117 netsim::hci::facade::ReportInvalidPacket(
118 this->rootcanalId.value(),
119 stats::InvalidPacket_Reason::InvalidPacket_Reason_DELAYED,
120 "Delayed packet with " + std::to_string(elapsedTime) +
121 " milliseconds",
122 combinedPacket);
123 }
124 mPacketCallback(rootcanal_packet_type, packet);
125 });
126 }
127
Add(rootcanal::PhyDevice::Identifier rootcanal_id,const std::shared_ptr<HciPacketTransport> & transport)128 void HciPacketTransport::Add(
129 rootcanal::PhyDevice::Identifier rootcanal_id,
130 const std::shared_ptr<HciPacketTransport> &transport) {
131 transport->Connect(rootcanal_id);
132 rootcanal_id_to_transport_[rootcanal_id] = transport;
133 }
134
Remove(rootcanal::PhyDevice::Identifier rootcanal_id)135 void HciPacketTransport::Remove(rootcanal::PhyDevice::Identifier rootcanal_id) {
136 BtsLogInfo("hci_packet_transport remove from netsim");
137 if (rootcanal_id_to_transport_.find(rootcanal_id) !=
138 rootcanal_id_to_transport_.end() &&
139 rootcanal_id_to_transport_[rootcanal_id]) {
140 // Calls HciDevice::Close, will disconnect AclHandles with
141 // CONNECTION_TIMEOUT, and call TestModel::CloseCallback.
142 rootcanal_id_to_transport_[rootcanal_id]->mCloseCallback();
143 }
144 }
145
146 // Called by HciDevice::Close
Close()147 void HciPacketTransport::Close() {
148 if (rootcanalId.has_value()) {
149 rootcanal_id_to_transport_.erase(rootcanalId.value());
150 }
151 BtsLogInfo("hci_packet_transport close from rootcanal");
152 rootcanalId = std::nullopt;
153 }
154
155 // handle_request is the main entry for incoming packets called by
156 // netsim::packet_hub
157 //
158 // Transfer the request to the HciTransport to deliver to Rootcanal via the
159 // 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)160 void handle_bt_request(uint32_t rootcanal_id,
161 packet::HCIPacket_PacketType packet_type,
162 const std::shared_ptr<std::vector<uint8_t>> &packet) {
163 if (rootcanal_id_to_transport_.find(rootcanal_id) !=
164 rootcanal_id_to_transport_.end() &&
165 rootcanal_id_to_transport_[rootcanal_id]) {
166 auto transport = rootcanal_id_to_transport_[rootcanal_id];
167 transport->Request(packet_type, packet);
168 } else {
169 std::cout << "rootcanal_id_to_transport_ ids ";
170 for (auto [k, _] : rootcanal_id_to_transport_) std::cout << k << " ";
171 std::cout << std::endl;
172 BtsLogWarn(
173 "hci_packet_transport: handle_request with no transport for device "
174 "with rootcanal_id: %d",
175 rootcanal_id);
176 }
177 }
178
HandleBtRequestCxx(uint32_t rootcanal_id,uint8_t packet_type,const rust::Vec<uint8_t> & packet)179 void HandleBtRequestCxx(uint32_t rootcanal_id, uint8_t packet_type,
180 const rust::Vec<uint8_t> &packet) {
181 std::vector<uint8_t> buffer(packet.begin(), packet.end());
182 auto packet_ptr = std::make_shared<std::vector<uint8_t>>(buffer);
183 handle_bt_request(rootcanal_id,
184 static_cast<packet::HCIPacket_PacketType>(packet_type),
185 packet_ptr);
186 }
187
188 } // namespace hci
189 } // namespace netsim
190