Home | History | Annotate | Download | only in src
      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