1 /****************************************************************************** 2 * 3 * Copyright 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #define LOG_TAG "bt_snoop" 20 21 #include <mutex> 22 23 #include <arpa/inet.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <inttypes.h> 27 #include <limits.h> 28 #include <netinet/in.h> 29 #include <stdbool.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/stat.h> 34 #include <sys/time.h> 35 #include <sys/uio.h> 36 #include <unistd.h> 37 38 #include "bt_types.h" 39 #include "hci/include/btsnoop.h" 40 #include "hci/include/btsnoop_mem.h" 41 #include "hci_layer.h" 42 #include "osi/include/log.h" 43 #include "osi/include/properties.h" 44 #include "osi/include/time.h" 45 #include "stack_config.h" 46 47 // The number of of packets per btsnoop file before we rotate to the next 48 // file. As of right now there are two snoop files that are rotated through. 49 // The size can be dynamically configured by seting the relevant system 50 // property 51 #define DEFAULT_BTSNOOP_SIZE 0xffff 52 53 #define BTSNOOP_ENABLE_PROPERTY "persist.bluetooth.btsnoopenable" 54 #define BTSNOOP_PATH_PROPERTY "persist.bluetooth.btsnooppath" 55 #define DEFAULT_BTSNOOP_PATH "/data/misc/bluetooth/logs/btsnoop_hci.log" 56 #define BTSNOOP_MAX_PACKETS_PROPERTY "persist.bluetooth.btsnoopsize" 57 58 typedef enum { 59 kCommandPacket = 1, 60 kAclPacket = 2, 61 kScoPacket = 3, 62 kEventPacket = 4 63 } packet_type_t; 64 65 // Epoch in microseconds since 01/01/0000. 66 static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL; 67 68 static int logfile_fd = INVALID_FD; 69 static std::mutex btsnoop_mutex; 70 71 static int32_t packets_per_file; 72 static int32_t packet_counter; 73 74 // TODO(zachoverflow): merge btsnoop and btsnoop_net together 75 void btsnoop_net_open(); 76 void btsnoop_net_close(); 77 void btsnoop_net_write(const void* data, size_t length); 78 79 static void delete_btsnoop_files(); 80 static bool is_btsnoop_enabled(); 81 static char* get_btsnoop_log_path(char* log_path); 82 static char* get_btsnoop_last_log_path(char* last_log_path, char* log_path); 83 static void open_next_snoop_file(); 84 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet, 85 bool is_received, uint64_t timestamp_us); 86 87 // Module lifecycle functions 88 89 static future_t* start_up(void) { 90 std::lock_guard<std::mutex> lock(btsnoop_mutex); 91 92 if (!is_btsnoop_enabled()) { 93 delete_btsnoop_files(); 94 } else { 95 open_next_snoop_file(); 96 packets_per_file = osi_property_get_int32(BTSNOOP_MAX_PACKETS_PROPERTY, 97 DEFAULT_BTSNOOP_SIZE); 98 btsnoop_net_open(); 99 } 100 101 return NULL; 102 } 103 104 static future_t* shut_down(void) { 105 std::lock_guard<std::mutex> lock(btsnoop_mutex); 106 107 if (!is_btsnoop_enabled()) { 108 delete_btsnoop_files(); 109 } 110 111 if (logfile_fd != INVALID_FD) close(logfile_fd); 112 logfile_fd = INVALID_FD; 113 114 btsnoop_net_close(); 115 116 return NULL; 117 } 118 119 EXPORT_SYMBOL extern const module_t btsnoop_module = { 120 .name = BTSNOOP_MODULE, 121 .init = NULL, 122 .start_up = start_up, 123 .shut_down = shut_down, 124 .clean_up = NULL, 125 .dependencies = {STACK_CONFIG_MODULE, NULL}}; 126 127 // Interface functions 128 static void capture(const BT_HDR* buffer, bool is_received) { 129 uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset); 130 131 std::lock_guard<std::mutex> lock(btsnoop_mutex); 132 uint64_t timestamp_us = time_gettimeofday_us(); 133 btsnoop_mem_capture(buffer, timestamp_us); 134 135 if (logfile_fd == INVALID_FD) return; 136 137 switch (buffer->event & MSG_EVT_MASK) { 138 case MSG_HC_TO_STACK_HCI_EVT: 139 btsnoop_write_packet(kEventPacket, p, false, timestamp_us); 140 break; 141 case MSG_HC_TO_STACK_HCI_ACL: 142 case MSG_STACK_TO_HC_HCI_ACL: 143 btsnoop_write_packet(kAclPacket, p, is_received, timestamp_us); 144 break; 145 case MSG_HC_TO_STACK_HCI_SCO: 146 case MSG_STACK_TO_HC_HCI_SCO: 147 btsnoop_write_packet(kScoPacket, p, is_received, timestamp_us); 148 break; 149 case MSG_STACK_TO_HC_HCI_CMD: 150 btsnoop_write_packet(kCommandPacket, p, true, timestamp_us); 151 break; 152 } 153 } 154 155 static const btsnoop_t interface = {capture}; 156 157 const btsnoop_t* btsnoop_get_interface() { 158 return &interface; 159 } 160 161 // Internal functions 162 static void delete_btsnoop_files() { 163 LOG_VERBOSE(LOG_TAG, "Deleting snoop log if it exists"); 164 char log_path[PROPERTY_VALUE_MAX]; 165 char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")]; 166 get_btsnoop_log_path(log_path); 167 get_btsnoop_last_log_path(last_log_path, log_path); 168 remove(log_path); 169 remove(last_log_path); 170 } 171 172 static bool is_btsnoop_enabled() { 173 char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0}; 174 osi_property_get(BTSNOOP_ENABLE_PROPERTY, btsnoop_enabled, "false"); 175 return strncmp(btsnoop_enabled, "true", 4) == 0; 176 } 177 178 static char* get_btsnoop_log_path(char* btsnoop_path) { 179 osi_property_get(BTSNOOP_PATH_PROPERTY, btsnoop_path, DEFAULT_BTSNOOP_PATH); 180 return btsnoop_path; 181 } 182 183 static char* get_btsnoop_last_log_path(char* last_log_path, 184 char* btsnoop_path) { 185 snprintf(last_log_path, PROPERTY_VALUE_MAX + sizeof(".last"), "%s.last", 186 btsnoop_path); 187 return last_log_path; 188 } 189 190 static void open_next_snoop_file() { 191 packet_counter = 0; 192 193 if (logfile_fd != INVALID_FD) { 194 close(logfile_fd); 195 logfile_fd = INVALID_FD; 196 } 197 198 char log_path[PROPERTY_VALUE_MAX]; 199 char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")]; 200 get_btsnoop_log_path(log_path); 201 get_btsnoop_last_log_path(last_log_path, log_path); 202 203 if (rename(log_path, last_log_path) != 0 && errno != ENOENT) 204 LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, 205 log_path, last_log_path, strerror(errno)); 206 207 mode_t prevmask = umask(0); 208 logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC, 209 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 210 umask(prevmask); 211 if (logfile_fd == INVALID_FD) { 212 LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path, 213 strerror(errno)); 214 return; 215 } 216 217 write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16); 218 } 219 220 typedef struct { 221 uint32_t length_original; 222 uint32_t length_captured; 223 uint32_t flags; 224 uint32_t dropped_packets; 225 uint64_t timestamp; 226 uint8_t type; 227 } __attribute__((__packed__)) btsnoop_header_t; 228 229 static uint64_t htonll(uint64_t ll) { 230 const uint32_t l = 1; 231 if (*(reinterpret_cast<const uint8_t*>(&l)) == 1) 232 return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | 233 htonl(ll >> 32); 234 235 return ll; 236 } 237 238 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet, 239 bool is_received, uint64_t timestamp_us) { 240 uint32_t length_he = 0; 241 uint32_t flags = 0; 242 243 switch (type) { 244 case kCommandPacket: 245 length_he = packet[2] + 4; 246 flags = 2; 247 break; 248 case kAclPacket: 249 length_he = (packet[3] << 8) + packet[2] + 5; 250 flags = is_received; 251 break; 252 case kScoPacket: 253 length_he = packet[2] + 4; 254 flags = is_received; 255 break; 256 case kEventPacket: 257 length_he = packet[1] + 3; 258 flags = 3; 259 break; 260 } 261 262 btsnoop_header_t header; 263 header.length_original = htonl(length_he); 264 header.length_captured = header.length_original; 265 header.flags = htonl(flags); 266 header.dropped_packets = 0; 267 header.timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA); 268 header.type = type; 269 270 btsnoop_net_write(&header, sizeof(btsnoop_header_t)); 271 btsnoop_net_write(packet, length_he - 1); 272 273 if (logfile_fd != INVALID_FD) { 274 packet_counter++; 275 if (packet_counter > packets_per_file) { 276 open_next_snoop_file(); 277 } 278 279 iovec iov[] = {{&header, sizeof(btsnoop_header_t)}, 280 {reinterpret_cast<void*>(packet), length_he - 1}}; 281 TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2)); 282 } 283 } 284