• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "hci/hci_debug.h"
22 #include "hci_packet.pb.h"
23 #include "model/hci/hci_transport.h"
24 #include "packet_hub/packet_hub.h"
25 #include "util/log.h"
26 
27 using netsim::packet::HCIPacket;
28 
29 namespace netsim {
30 namespace hci {
31 
32 std::unordered_map<uint32_t, std::shared_ptr<HciPacketTransport>>
33     device_to_transport_;
34 
35 /**
36  * @class HciPacketTransport
37  *
38  * Connects hci packets between packet_hub and rootcanal.
39  *
40  */
HciPacketTransport(std::shared_ptr<rootcanal::AsyncManager> async_manager)41 HciPacketTransport::HciPacketTransport(
42     std::shared_ptr<rootcanal::AsyncManager> async_manager)
43     : mDeviceId(std::nullopt), mAsyncManager(std::move(async_manager)) {}
44 
45 /**
46  * @brief Connect the phy device to the transport
47  *
48  * @param - device_id identifier of the owning device
49  */
Connect(rootcanal::PhyDevice::Identifier device_id)50 void HciPacketTransport::Connect(rootcanal::PhyDevice::Identifier device_id) {
51   assert(!mDeviceId.has_value());
52   mDeviceId.emplace(device_id);
53 }
54 
55 // Called by HCITransport (rootcanal)
SendEvent(const std::vector<uint8_t> & data)56 void HciPacketTransport::SendEvent(const std::vector<uint8_t> &data) {
57   this->Response(HCIPacket::EVENT, data);
58 }
59 
60 // Called by HCITransport (rootcanal)
SendAcl(const std::vector<uint8_t> & data)61 void HciPacketTransport::SendAcl(const std::vector<uint8_t> &data) {
62   this->Response(HCIPacket::ACL, data);
63 }
64 
65 // Called by HCITransport (rootcanal)
SendSco(const std::vector<uint8_t> & data)66 void HciPacketTransport::SendSco(const std::vector<uint8_t> &data) {
67   this->Response(HCIPacket::SCO, data);
68 }
69 
70 // Called by HCITransport (rootcanal)
SendIso(const std::vector<uint8_t> & data)71 void HciPacketTransport::SendIso(const std::vector<uint8_t> &data) {
72   this->Response(HCIPacket::ISO, data);
73 }
74 
75 // Called by HCITransport (rootcanal)
RegisterCallbacks(rootcanal::PacketCallback commandCallback,rootcanal::PacketCallback aclCallback,rootcanal::PacketCallback scoCallback,rootcanal::PacketCallback isoCallback,rootcanal::CloseCallback closeCallback)76 void HciPacketTransport::RegisterCallbacks(
77     rootcanal::PacketCallback commandCallback,
78     rootcanal::PacketCallback aclCallback,
79     rootcanal::PacketCallback scoCallback,
80     rootcanal::PacketCallback isoCallback,
81     rootcanal::CloseCallback closeCallback) {
82   BtsLog("hci_packet_transport: registered");
83   mCommandCallback = commandCallback;
84   mAclCallback = aclCallback;
85   mScoCallback = scoCallback;
86   mIsoCallback = isoCallback;
87   mCloseCallback = closeCallback;
88 }
89 
90 // Called by HCITransport (rootcanal)
Tick()91 void HciPacketTransport::Tick() {}
92 
Request(packet::HCIPacket_PacketType packet_type,const std::shared_ptr<std::vector<uint8_t>> & packet)93 void HciPacketTransport::Request(
94     packet::HCIPacket_PacketType packet_type,
95     const std::shared_ptr<std::vector<uint8_t>> &packet) {
96   auto packet_callback = PacketTypeCallback(packet_type);
97   if (!packet_callback) {
98     BtsLog("hci_transport: unknown packet_callback");
99     return;
100   }
101   if (packet_type == HCIPacket::COMMAND) {
102     auto cmd = HciCommandToString(packet->at(0), packet->at(1));
103   }
104   // Copy the packet bytes for rootcanal.
105   mAsyncManager->Synchronize(
106       [packet_callback, packet]() { packet_callback(packet); });
107 }
108 
Add(rootcanal::PhyDevice::Identifier device_id,const std::shared_ptr<HciPacketTransport> & transport)109 void HciPacketTransport::Add(
110     rootcanal::PhyDevice::Identifier device_id,
111     const std::shared_ptr<HciPacketTransport> &transport) {
112   transport->Connect(device_id);
113   device_to_transport_[device_id] = transport;
114 }
115 
Close()116 void HciPacketTransport::Close() {
117   if (mDeviceId.has_value()) {
118     device_to_transport_.erase(mDeviceId.value());
119   }
120 
121   BtsLog("hci_packet_transport close from rootcanal");
122   mDeviceId = std::nullopt;
123 }
124 
125 // Send response to packet_hub.
126 // TODO: future optimization by having rootcanal send shared_ptr.
Response(packet::HCIPacket_PacketType packet_type,const std::vector<uint8_t> & packet)127 void HciPacketTransport::Response(packet::HCIPacket_PacketType packet_type,
128                                   const std::vector<uint8_t> &packet) {
129   if (!mDeviceId.has_value()) {
130     BtsLog("hci_packet_transport: response with no device.");
131     return;
132   }
133   auto shared_packet = std::make_shared<std::vector<uint8_t>>(packet);
134   netsim::packet_hub::HandleBtResponse(mDeviceId.value(), packet_type,
135                                        shared_packet);
136 }
137 
PacketTypeCallback(packet::HCIPacket_PacketType packet_type)138 rootcanal::PacketCallback HciPacketTransport::PacketTypeCallback(
139     packet::HCIPacket_PacketType packet_type) {
140   switch (packet_type) {
141     case HCIPacket::COMMAND:
142       assert(mCommandCallback);
143       return mCommandCallback;
144     case HCIPacket::ACL:
145       return mAclCallback;
146     case HCIPacket::SCO:
147       return mScoCallback;
148     case HCIPacket::ISO:
149       return mIsoCallback;
150     default:
151       BtsLog("hci_transport Ignoring unknown packet.");
152       return nullptr;
153   }
154 }
155 
156 // handle_request is the main entry for incoming packets called by
157 // netsim::packet_hub
158 //
159 // Transfer the request to the HciTransport to deliver to Rootcanal via the
160 // acl/sco/iso/command callback methods under synchronization.
handle_bt_request(uint32_t facade_id,packet::HCIPacket_PacketType packet_type,const std::shared_ptr<std::vector<uint8_t>> & packet)161 void handle_bt_request(uint32_t facade_id,
162                        packet::HCIPacket_PacketType packet_type,
163                        const std::shared_ptr<std::vector<uint8_t>> &packet) {
164   if (device_to_transport_.find(facade_id) != device_to_transport_.end() &&
165       device_to_transport_[facade_id]) {
166     auto transport = device_to_transport_[facade_id];
167     transport->Request(packet_type, packet);
168   } else {
169     std::cout << "device_to_transport_ ids ";
170     for (auto [k, _] : device_to_transport_) std::cout << k << " ";
171     std::cout << std::endl;
172     BtsLog(
173         "hci_packet_transport: handle_request with no transport for device %d",
174         facade_id);
175   }
176 }
177 
178 }  // namespace hci
179 }  // namespace netsim
180