1 /****************************************************************************** 2 * 3 * Copyright (C) 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 <arpa/inet.h> 22 #include <assert.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <inttypes.h> 26 #include <limits.h> 27 #include <netinet/in.h> 28 #include <stdbool.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <sys/stat.h> 33 #include <sys/time.h> 34 #include <unistd.h> 35 36 #include "bt_types.h" 37 #include "hci/include/btsnoop.h" 38 #include "hci/include/btsnoop_mem.h" 39 #include "hci_layer.h" 40 #include "osi/include/log.h" 41 #include "stack_config.h" 42 43 typedef enum { 44 kCommandPacket = 1, 45 kAclPacket = 2, 46 kScoPacket = 3, 47 kEventPacket = 4 48 } packet_type_t; 49 50 // Epoch in microseconds since 01/01/0000. 51 static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL; 52 53 static const stack_config_t *stack_config; 54 55 static int logfile_fd = INVALID_FD; 56 static bool module_started; 57 static bool is_logging; 58 static bool logging_enabled_via_api; 59 60 // TODO(zachoverflow): merge btsnoop and btsnoop_net together 61 void btsnoop_net_open(); 62 void btsnoop_net_close(); 63 void btsnoop_net_write(const void *data, size_t length); 64 65 static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received); 66 static void update_logging(); 67 68 // Module lifecycle functions 69 70 static future_t *start_up(void) { 71 module_started = true; 72 update_logging(); 73 74 return NULL; 75 } 76 77 static future_t *shut_down(void) { 78 module_started = false; 79 update_logging(); 80 81 return NULL; 82 } 83 84 EXPORT_SYMBOL const module_t btsnoop_module = { 85 .name = BTSNOOP_MODULE, 86 .init = NULL, 87 .start_up = start_up, 88 .shut_down = shut_down, 89 .clean_up = NULL, 90 .dependencies = { 91 STACK_CONFIG_MODULE, 92 NULL 93 } 94 }; 95 96 // Interface functions 97 98 static void set_api_wants_to_log(bool value) { 99 logging_enabled_via_api = value; 100 update_logging(); 101 } 102 103 static void capture(const BT_HDR *buffer, bool is_received) { 104 const uint8_t *p = buffer->data + buffer->offset; 105 106 btsnoop_mem_capture(buffer); 107 108 if (logfile_fd == INVALID_FD) 109 return; 110 111 switch (buffer->event & MSG_EVT_MASK) { 112 case MSG_HC_TO_STACK_HCI_EVT: 113 btsnoop_write_packet(kEventPacket, p, false); 114 break; 115 case MSG_HC_TO_STACK_HCI_ACL: 116 case MSG_STACK_TO_HC_HCI_ACL: 117 btsnoop_write_packet(kAclPacket, p, is_received); 118 break; 119 case MSG_HC_TO_STACK_HCI_SCO: 120 case MSG_STACK_TO_HC_HCI_SCO: 121 btsnoop_write_packet(kScoPacket, p, is_received); 122 break; 123 case MSG_STACK_TO_HC_HCI_CMD: 124 btsnoop_write_packet(kCommandPacket, p, true); 125 break; 126 } 127 } 128 129 static const btsnoop_t interface = { 130 set_api_wants_to_log, 131 capture 132 }; 133 134 const btsnoop_t *btsnoop_get_interface() { 135 stack_config = stack_config_get_interface(); 136 return &interface; 137 } 138 139 // Internal functions 140 141 static uint64_t btsnoop_timestamp(void) { 142 struct timeval tv; 143 gettimeofday(&tv, NULL); 144 145 // Timestamp is in microseconds. 146 uint64_t timestamp = tv.tv_sec * 1000 * 1000LL; 147 timestamp += tv.tv_usec; 148 timestamp += BTSNOOP_EPOCH_DELTA; 149 return timestamp; 150 } 151 152 static void update_logging() { 153 bool should_log = module_started && 154 (logging_enabled_via_api || stack_config->get_btsnoop_turned_on()); 155 156 if (should_log == is_logging) 157 return; 158 159 is_logging = should_log; 160 if (should_log) { 161 btsnoop_net_open(); 162 163 const char *log_path = stack_config->get_btsnoop_log_path(); 164 165 // Save the old log if configured to do so 166 if (stack_config->get_btsnoop_should_save_last()) { 167 char last_log_path[PATH_MAX]; 168 snprintf(last_log_path, PATH_MAX, "%s.%" PRIu64, log_path, 169 btsnoop_timestamp()); 170 if (!rename(log_path, last_log_path) && errno != ENOENT) 171 LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, log_path, last_log_path, strerror(errno)); 172 } 173 174 logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 175 if (logfile_fd == INVALID_FD) { 176 LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path, strerror(errno)); 177 is_logging = false; 178 return; 179 } 180 181 write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16); 182 } else { 183 if (logfile_fd != INVALID_FD) 184 close(logfile_fd); 185 186 logfile_fd = INVALID_FD; 187 btsnoop_net_close(); 188 } 189 } 190 191 static void btsnoop_write(const void *data, size_t length) { 192 if (logfile_fd != INVALID_FD) 193 write(logfile_fd, data, length); 194 195 btsnoop_net_write(data, length); 196 } 197 198 static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) { 199 int length_he = 0; 200 int length; 201 int flags; 202 int drops = 0; 203 switch (type) { 204 case kCommandPacket: 205 length_he = packet[2] + 4; 206 flags = 2; 207 break; 208 case kAclPacket: 209 length_he = (packet[3] << 8) + packet[2] + 5; 210 flags = is_received; 211 break; 212 case kScoPacket: 213 length_he = packet[2] + 4; 214 flags = is_received; 215 break; 216 case kEventPacket: 217 length_he = packet[1] + 3; 218 flags = 3; 219 break; 220 } 221 222 uint64_t timestamp = btsnoop_timestamp(); 223 uint32_t time_hi = timestamp >> 32; 224 uint32_t time_lo = timestamp & 0xFFFFFFFF; 225 226 length = htonl(length_he); 227 flags = htonl(flags); 228 drops = htonl(drops); 229 time_hi = htonl(time_hi); 230 time_lo = htonl(time_lo); 231 232 btsnoop_write(&length, 4); 233 btsnoop_write(&length, 4); 234 btsnoop_write(&flags, 4); 235 btsnoop_write(&drops, 4); 236 btsnoop_write(&time_hi, 4); 237 btsnoop_write(&time_lo, 4); 238 btsnoop_write(&type, 1); 239 btsnoop_write(packet, length_he - 1); 240 } 241