• 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 /// Connect HCI file descriptors to root canal.
16 
17 #include "fd_startup.h"
18 
19 #include <google/protobuf/util/json_util.h>
20 #include <sys/uio.h>
21 #include <unistd.h>
22 
23 #include <memory>
24 #include <thread>
25 
26 #include "common.pb.h"
27 #include "controller/scene_controller.h"
28 #include "hci/bluetooth_facade.h"
29 #include "model/hci/h4_parser.h"
30 #include "model/hci/hci_transport.h"
31 #include "startup.pb.h"
32 #include "util/log.h"
33 
34 namespace netsim {
35 namespace hci {
36 namespace {
37 
38 enum HCIPacket : int {
39   PACKET_TYPE_UNSPECIFIED = 0,
40   PACKET_TYPE_HCI_COMMAND = 1,
41   PACKET_TYPE_ACL = 2,
42   PACKET_TYPE_SCO = 3,
43   PACKET_TYPE_EVENT = 4,
44   PACKET_TYPE_ISO = 5
45 };
46 
47 // Class to move packets between root canal and file descriptor.
48 
49 class FdHciForwarder : public rootcanal::HciTransport {
50  public:
~FdHciForwarder()51   ~FdHciForwarder() {}
52 
FdHciForwarder(std::string name,int fd_in,int fd_out)53   FdHciForwarder(std::string name, int fd_in, int fd_out)
54       : fd_in_(fd_in), fd_out_(fd_out), name_(std::move(name)) {}
55 
56   // Called by HCITransport (rootcanal)
SendEvent(const std::vector<uint8_t> & data)57   void SendEvent(const std::vector<uint8_t> &data) override {
58     this->Write(HCIPacket::PACKET_TYPE_EVENT, data.data(), data.size());
59   }
60 
61   // Called by HCITransport (rootcanal)
SendAcl(const std::vector<uint8_t> & data)62   void SendAcl(const std::vector<uint8_t> &data) override {
63     this->Write(HCIPacket::PACKET_TYPE_ACL, data.data(), data.size());
64   }
65 
66   // Called by HCITransport (rootcanal)
SendSco(const std::vector<uint8_t> & data)67   void SendSco(const std::vector<uint8_t> &data) override {
68     this->Write(HCIPacket::PACKET_TYPE_SCO, data.data(), data.size());
69   }
70 
71   // Called by HCITransport (rootcanal)
SendIso(const std::vector<uint8_t> & data)72   void SendIso(const std::vector<uint8_t> &data) override {
73     this->Write(HCIPacket::PACKET_TYPE_ISO, data.data(), data.size());
74   }
75 
76   // A wrapper for the HCITransport that uses shared ptrs.
77 
SharedPacketCallback(const rootcanal::PacketCallback & cb,const std::vector<uint8_t> & raw_packet)78   static void SharedPacketCallback(const rootcanal::PacketCallback &cb,
79                                    const std::vector<uint8_t> &raw_packet) {
80     std::shared_ptr<std::vector<uint8_t>> packet_copy =
81         std::make_shared<std::vector<uint8_t>>(raw_packet);
82     cb(packet_copy);
83   }
84   // Called by HCITransport (rootcanal)
85   // This case is simular to hci_socket_transport.cc
RegisterCallbacks(rootcanal::PacketCallback command_cb,rootcanal::PacketCallback acl_cb,rootcanal::PacketCallback sco_cb,rootcanal::PacketCallback iso_cb,rootcanal::CloseCallback close_cb)86   void RegisterCallbacks(rootcanal::PacketCallback command_cb,
87                          rootcanal::PacketCallback acl_cb,
88                          rootcanal::PacketCallback sco_cb,
89                          rootcanal::PacketCallback iso_cb,
90                          rootcanal::CloseCallback close_cb) override {
91     h4_parser_ = std::make_unique<rootcanal::H4Parser>(
92         [command_cb](const std::vector<uint8_t> &raw_command) {
93           SharedPacketCallback(command_cb, raw_command);
94         },
95         [](const std::vector<uint8_t> &) {
96           BtsLog("Unexpected Event in FdTransport!");
97         },
98         [acl_cb](const std::vector<uint8_t> &raw_acl) {
99           SharedPacketCallback(acl_cb, raw_acl);
100         },
101         [sco_cb](const std::vector<uint8_t> &raw_sco) {
102           SharedPacketCallback(sco_cb, raw_sco);
103         },
104         [iso_cb](const std::vector<uint8_t> &raw_iso) {
105           SharedPacketCallback(iso_cb, raw_iso);
106         });
107     this->close_cb_ = close_cb;
108     // start the reader thread
109     this->reader_ = std::move(std::thread([&] { StartReader(); }));
110   }
111 
112   // Called by HCITransport (rootcanal)
Close()113   void Close() override {
114     BtsLog("netsim - Close called for %s", name_.c_str());
115     close(fd_in_);
116     close(fd_out_);
117   }
118 
119   // Called by HCITransport (rootcanal)
Tick()120   void Tick() override {}
121 
122  private:
123   const int fd_in_, fd_out_;
124   std::thread reader_;
125   bool disconnected_ = false;
126   rootcanal::CloseCallback close_cb_;
127   std::unique_ptr<rootcanal::H4Parser> h4_parser_;
128   const std::string name_;
129 
130   // Write packets from rootcanal back to guest os
Write(uint8_t type,const uint8_t * data,size_t length)131   int Write(uint8_t type, const uint8_t *data, size_t length) {
132     struct iovec iov[] = {{&type, sizeof(type)},
133                           {const_cast<uint8_t *>(data), length}};
134     ssize_t ret = 0;
135     do {
136       ret = writev(fd_in_, iov, sizeof(iov) / sizeof(iov[0]));
137     } while (-1 == ret && EAGAIN == errno);
138     if (ret == -1) {
139       BtsLog("Netsim: Error writing (%s)", strerror(errno));
140     } else if (ret < static_cast<ssize_t>(length + 1)) {
141       BtsLog("Netsim: %d / %d bytes written - something went wrong...",
142              static_cast<int>(ret), static_cast<int>(length + 1));
143     }
144     return ret;
145   }
146 
147   // Start reading packets from guest os fd and sending to root canal.
StartReader()148   void StartReader() {
149     while (!disconnected_) {
150       ssize_t bytes_to_read = h4_parser_->BytesRequested();
151       std::vector<uint8_t> buffer(bytes_to_read);
152       ssize_t bytes_read;
153       bytes_read = read(fd_out_, buffer.data(), bytes_to_read);
154       if (bytes_read == 0) {
155         BtsLog("remote disconnected -- %s", name_.c_str());
156         disconnected_ = true;
157         close_cb_();
158         break;
159       } else if (bytes_read < 0) {
160         if (errno == EAGAIN) {
161           // No data, try again later.
162           continue;
163         } else if (errno == ECONNRESET) {
164           // They probably rejected our packet
165           disconnected_ = true;
166           close_cb_();
167           break;
168         } else {
169           BtsLog("Read error in %d %s", h4_parser_->CurrentState(),
170                  strerror(errno));
171         }
172       } else {
173         h4_parser_->Consume(buffer.data(), bytes_read);
174       }
175     }
176   }
177 };
178 
179 // Private implementation
180 
181 class FdStartupImpl : public FdStartup {
182  public:
183   // Disallow copy and assign
184   FdStartupImpl(const FdStartupImpl &) = delete;
185   FdStartupImpl &operator=(const FdStartupImpl &) = delete;
186 
FdStartupImpl()187   FdStartupImpl() {}
188 
189   // Connect multiple fd endpoints
190 
Connect(const std::string & startup_str)191   bool Connect(const std::string &startup_str) override {
192     netsim::startup::StartupInfo info;
193     google::protobuf::util::JsonParseOptions options;
194     auto status = JsonStringToMessage(startup_str, &info, options);
195 
196     if (!status.ok()) {
197       BtsLog("FdStartup failed to parse json '%s' - %s", startup_str.c_str(),
198              status.ToString().c_str());
199       return false;
200     }
201 
202     for (const auto &device : info.devices()) {
203       auto name = device.name();
204       for (const auto &chip : device.chips()) {
205         if (chip.kind() == common::ChipKind::BLUETOOTH) {
206           auto fd_in = chip.fd_in();
207           auto fd_out = chip.fd_out();
208 
209           BtsLog("Connecting %s on fd_in:%d, fd_out:%d", name.c_str(), fd_in,
210                  fd_out);
211 
212           std::shared_ptr<rootcanal::HciTransport> transport =
213               std::make_shared<FdHciForwarder>(name, fd_in, fd_out);
214           auto guid =
215               name + ":" + std::to_string(fd_in) + ":" + std::to_string(fd_out);
216           netsim::controller::SceneController::Singleton().AddChip(
217               guid, name, common::ChipKind::BLUETOOTH);
218 
219           BtsLog("FdHciForwarder is not supported");
220         }
221       }
222     }
223     return true;
224   }
225 };
226 
227 }  // namespace
228 
~FdStartup()229 FdStartup::~FdStartup(){};
230 
231 // Public constructor for FdStartup that returns private implementation.
232 
Create()233 std::unique_ptr<FdStartup> FdStartup::Create() {
234   std::cerr << "Creating FdStartup\n";
235   return std::make_unique<FdStartupImpl>();
236 }
237 
238 }  // namespace hci
239 }  // namespace netsim
240