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