1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hal/hci_hal_host_rootcanal.h"
18
19 #include <netdb.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <chrono>
25 #include <csignal>
26 #include <mutex>
27 #include <queue>
28
29 #include "hal/hci_hal.h"
30 #include "hal/snoop_logger.h"
31 #include "os/log.h"
32 #include "os/reactor.h"
33 #include "os/thread.h"
34
35 namespace {
36 constexpr int INVALID_FD = -1;
37
38 constexpr uint8_t kH4Command = 0x01;
39 constexpr uint8_t kH4Acl = 0x02;
40 constexpr uint8_t kH4Sco = 0x03;
41 constexpr uint8_t kH4Event = 0x04;
42
43 constexpr uint8_t kH4HeaderSize = 1;
44 constexpr uint8_t kHciAclHeaderSize = 4;
45 constexpr uint8_t kHciScoHeaderSize = 3;
46 constexpr uint8_t kHciEvtHeaderSize = 2;
47 constexpr int kBufSize = 1024 + 4 + 1; // DeviceProperties::acl_data_packet_size_ + ACL header + H4 header
48
ConnectToRootCanal(const std::string & server,int port)49 int ConnectToRootCanal(const std::string& server, int port) {
50 int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
51 if (socket_fd < 1) {
52 LOG_ERROR("can't create socket: %s", strerror(errno));
53 return INVALID_FD;
54 }
55
56 struct hostent* host;
57 host = gethostbyname(server.c_str());
58 if (host == nullptr) {
59 LOG_ERROR("can't get server name");
60 return INVALID_FD;
61 }
62
63 struct sockaddr_in serv_addr;
64 memset((void*)&serv_addr, 0, sizeof(serv_addr));
65 serv_addr.sin_family = AF_INET;
66 serv_addr.sin_addr.s_addr = INADDR_ANY;
67 serv_addr.sin_port = htons(port);
68
69 int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
70 if (result < 0) {
71 LOG_ERROR("can't connect: %s", strerror(errno));
72 return INVALID_FD;
73 }
74
75 timeval socket_timeout{
76 .tv_sec = 3,
77 .tv_usec = 0,
78 };
79 int ret = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, sizeof(socket_timeout));
80 if (ret == -1) {
81 LOG_ERROR("can't control socket fd: %s", strerror(errno));
82 return INVALID_FD;
83 }
84 return socket_fd;
85 }
86 } // namespace
87
88 namespace bluetooth {
89 namespace hal {
90
91 const std::string SnoopLogger::DefaultFilePath = "/tmp/btsnoop_hci.log";
92 const bool SnoopLogger::AlwaysFlush = true;
93
94 class HciHalHostRootcanal : public HciHal {
95 public:
registerIncomingPacketCallback(HciHalCallbacks * callback)96 void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
97 std::lock_guard<std::mutex> lock(api_mutex_);
98 LOG_INFO("%s before", __func__);
99 {
100 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
101 ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
102 incoming_packet_callback_ = callback;
103 }
104 LOG_INFO("%s after", __func__);
105 }
106
unregisterIncomingPacketCallback()107 void unregisterIncomingPacketCallback() override {
108 std::lock_guard<std::mutex> lock(api_mutex_);
109 LOG_INFO("%s before", __func__);
110 {
111 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
112 incoming_packet_callback_ = nullptr;
113 }
114 LOG_INFO("%s after", __func__);
115 }
116
sendHciCommand(HciPacket command)117 void sendHciCommand(HciPacket command) override {
118 std::lock_guard<std::mutex> lock(api_mutex_);
119 ASSERT(sock_fd_ != INVALID_FD);
120 std::vector<uint8_t> packet = std::move(command);
121 btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
122 packet.insert(packet.cbegin(), kH4Command);
123 write_to_rootcanal_fd(packet);
124 }
125
sendAclData(HciPacket data)126 void sendAclData(HciPacket data) override {
127 std::lock_guard<std::mutex> lock(api_mutex_);
128 ASSERT(sock_fd_ != INVALID_FD);
129 std::vector<uint8_t> packet = std::move(data);
130 btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
131 packet.insert(packet.cbegin(), kH4Acl);
132 write_to_rootcanal_fd(packet);
133 }
134
sendScoData(HciPacket data)135 void sendScoData(HciPacket data) override {
136 std::lock_guard<std::mutex> lock(api_mutex_);
137 ASSERT(sock_fd_ != INVALID_FD);
138 std::vector<uint8_t> packet = std::move(data);
139 btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
140 packet.insert(packet.cbegin(), kH4Sco);
141 write_to_rootcanal_fd(packet);
142 }
143
144 protected:
ListDependencies(ModuleList * list)145 void ListDependencies(ModuleList* list) override {
146 list->add<SnoopLogger>();
147 }
148
Start()149 void Start() override {
150 std::lock_guard<std::mutex> lock(api_mutex_);
151 ASSERT(sock_fd_ == INVALID_FD);
152 sock_fd_ = ConnectToRootCanal(config_->GetServerAddress(), config_->GetPort());
153 ASSERT(sock_fd_ != INVALID_FD);
154 reactable_ = hci_incoming_thread_.GetReactor()->Register(
155 sock_fd_,
156 common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
157 common::Closure());
158 btsnoop_logger_ = GetDependency<SnoopLogger>();
159 LOG_INFO("Rootcanal HAL opened successfully");
160 }
161
Stop()162 void Stop() override {
163 std::lock_guard<std::mutex> lock(api_mutex_);
164 LOG_INFO("Rootcanal HAL is closing");
165 if (reactable_ != nullptr) {
166 hci_incoming_thread_.GetReactor()->Unregister(reactable_);
167 LOG_INFO("Rootcanal HAL is stopping, start waiting for last callback");
168 // Wait up to 1 second for the last incoming packet callback to finish
169 hci_incoming_thread_.GetReactor()->WaitForUnregisteredReactable(std::chrono::milliseconds(1000));
170 LOG_INFO("Rootcanal HAL is stopping, finished waiting for last callback");
171 ASSERT(sock_fd_ != INVALID_FD);
172 }
173 reactable_ = nullptr;
174 {
175 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
176 incoming_packet_callback_ = nullptr;
177 }
178 ::close(sock_fd_);
179 sock_fd_ = INVALID_FD;
180 LOG_INFO("Rootcanal HAL is closed");
181 }
182
183 private:
184 // Held when APIs are called, NOT to be held during callbacks
185 std::mutex api_mutex_;
186 HciHalHostRootcanalConfig* config_ = HciHalHostRootcanalConfig::Get();
187 HciHalCallbacks* incoming_packet_callback_ = nullptr;
188 std::mutex incoming_packet_callback_mutex_;
189 int sock_fd_ = INVALID_FD;
190 bluetooth::os::Thread hci_incoming_thread_ =
191 bluetooth::os::Thread("hci_incoming_thread", bluetooth::os::Thread::Priority::NORMAL);
192 bluetooth::os::Reactor::Reactable* reactable_ = nullptr;
193 std::queue<std::vector<uint8_t>> hci_outgoing_queue_;
194 SnoopLogger* btsnoop_logger_ = nullptr;
195
write_to_rootcanal_fd(HciPacket packet)196 void write_to_rootcanal_fd(HciPacket packet) {
197 // TODO: replace this with new queue when it's ready
198 hci_outgoing_queue_.emplace(packet);
199 if (hci_outgoing_queue_.size() == 1) {
200 hci_incoming_thread_.GetReactor()->ModifyRegistration(
201 reactable_,
202 common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
203 common::Bind(&HciHalHostRootcanal::send_packet_ready, common::Unretained(this)));
204 }
205 }
206
send_packet_ready()207 void send_packet_ready() {
208 std::lock_guard<std::mutex> lock(this->api_mutex_);
209 auto packet_to_send = this->hci_outgoing_queue_.front();
210 auto bytes_written = write(this->sock_fd_, (void*)packet_to_send.data(), packet_to_send.size());
211 this->hci_outgoing_queue_.pop();
212 if (bytes_written == -1) {
213 abort();
214 }
215 if (hci_outgoing_queue_.empty()) {
216 this->hci_incoming_thread_.GetReactor()->ModifyRegistration(
217 this->reactable_,
218 common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
219 common::Closure());
220 }
221 }
222
incoming_packet_received()223 void incoming_packet_received() {
224 {
225 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
226 if (incoming_packet_callback_ == nullptr) {
227 LOG_INFO("Dropping a packet");
228 return;
229 }
230 }
231 uint8_t buf[kBufSize] = {};
232
233 ssize_t received_size;
234 RUN_NO_INTR(received_size = recv(sock_fd_, buf, kH4HeaderSize, 0));
235 ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
236 if (received_size == 0) {
237 LOG_WARN("Can't read H4 header. EOF received");
238 raise(SIGINT);
239 return;
240 }
241
242 if (buf[0] == kH4Event) {
243 RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciEvtHeaderSize, 0));
244 ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
245 ASSERT_LOG(received_size == kHciEvtHeaderSize, "malformed HCI event header received");
246
247 uint8_t hci_evt_parameter_total_length = buf[2];
248 ssize_t payload_size;
249 RUN_NO_INTR(
250 payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciEvtHeaderSize, hci_evt_parameter_total_length, 0));
251 ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
252 ASSERT_LOG(
253 payload_size == hci_evt_parameter_total_length,
254 "malformed HCI event total parameter size received: %zu != %d",
255 payload_size,
256 hci_evt_parameter_total_length);
257
258 HciPacket receivedHciPacket;
259 receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size);
260 btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::EVT);
261 {
262 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
263 if (incoming_packet_callback_ == nullptr) {
264 LOG_INFO("Dropping an event after processing");
265 return;
266 }
267 incoming_packet_callback_->hciEventReceived(receivedHciPacket);
268 }
269 }
270
271 if (buf[0] == kH4Acl) {
272 RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciAclHeaderSize, 0));
273 ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
274 ASSERT_LOG(received_size == kHciAclHeaderSize, "malformed ACL header received");
275
276 uint16_t hci_acl_data_total_length = (buf[4] << 8) + buf[3];
277 int payload_size;
278 RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciAclHeaderSize, hci_acl_data_total_length, 0));
279 ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
280 ASSERT_LOG(
281 payload_size == hci_acl_data_total_length,
282 "malformed ACL length received: %d != %d",
283 payload_size,
284 hci_acl_data_total_length);
285 ASSERT_LOG(hci_acl_data_total_length <= kBufSize - kH4HeaderSize - kHciAclHeaderSize, "packet too long");
286
287 HciPacket receivedHciPacket;
288 receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciAclHeaderSize + payload_size);
289 btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ACL);
290 {
291 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
292 if (incoming_packet_callback_ == nullptr) {
293 LOG_INFO("Dropping an ACL packet after processing");
294 return;
295 }
296 incoming_packet_callback_->aclDataReceived(receivedHciPacket);
297 }
298 }
299
300 if (buf[0] == kH4Sco) {
301 RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciScoHeaderSize, 0));
302 ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
303 ASSERT_LOG(received_size == kHciScoHeaderSize, "malformed SCO header received");
304
305 uint8_t hci_sco_data_total_length = buf[3];
306 int payload_size;
307 RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciScoHeaderSize, hci_sco_data_total_length, 0));
308 ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
309 ASSERT_LOG(payload_size == hci_sco_data_total_length, "malformed SCO packet received: size mismatch");
310
311 HciPacket receivedHciPacket;
312 receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
313 btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::SCO);
314 {
315 std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
316 if (incoming_packet_callback_ == nullptr) {
317 LOG_INFO("Dropping a SCO packet after processing");
318 return;
319 }
320 incoming_packet_callback_->scoDataReceived(receivedHciPacket);
321 }
322 }
323 memset(buf, 0, kBufSize);
324 }
325 };
326
__anon29c672f10202() 327 const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHostRootcanal(); });
328
329 } // namespace hal
330 } // namespace bluetooth
331