Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2012 Broadcom Corporation
      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 "btsnoop"
     20 
     21 #include <arpa/inet.h>
     22 #include <assert.h>
     23 #include <ctype.h>
     24 #include <cutils/log.h>
     25 #include <errno.h>
     26 #include <fcntl.h>
     27 #include <stdbool.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <sys/stat.h>
     32 #include <sys/time.h>
     33 #include <unistd.h>
     34 
     35 #include "bt_hci_bdroid.h"
     36 #include "bt_utils.h"
     37 #include "utils.h"
     38 
     39 typedef enum {
     40   kCommandPacket = 1,
     41   kAclPacket = 2,
     42   kScoPacket = 3,
     43   kEventPacket = 4
     44 } packet_type_t;
     45 
     46 // Epoch in microseconds since 01/01/0000.
     47 static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
     48 
     49 // File descriptor for btsnoop file.
     50 static int hci_btsnoop_fd = -1;
     51 
     52 void btsnoop_net_open();
     53 void btsnoop_net_close();
     54 void btsnoop_net_write(const void *data, size_t length);
     55 
     56 static uint64_t btsnoop_timestamp(void) {
     57   struct timeval tv;
     58   gettimeofday(&tv, NULL);
     59 
     60   // Timestamp is in microseconds.
     61   uint64_t timestamp = tv.tv_sec * 1000 * 1000LL;
     62   timestamp += tv.tv_usec;
     63   timestamp += BTSNOOP_EPOCH_DELTA;
     64   return timestamp;
     65 }
     66 
     67 static void btsnoop_write(const void *data, size_t length) {
     68   if (hci_btsnoop_fd != -1)
     69     write(hci_btsnoop_fd, data, length);
     70 
     71   btsnoop_net_write(data, length);
     72 }
     73 
     74 static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) {
     75   int length_he = 0;
     76   int length;
     77   int flags;
     78   int drops = 0;
     79   switch (type) {
     80     case kCommandPacket:
     81       length_he = packet[2] + 4;
     82       flags = 2;
     83       break;
     84     case kAclPacket:
     85       length_he = (packet[3] << 8) + packet[2] + 5;
     86       flags = is_received;
     87       break;
     88     case kScoPacket:
     89       length_he = packet[2] + 4;
     90       flags = is_received;
     91       break;
     92     case kEventPacket:
     93       length_he = packet[1] + 3;
     94       flags = 3;
     95       break;
     96   }
     97 
     98   uint64_t timestamp = btsnoop_timestamp();
     99   uint32_t time_hi = timestamp >> 32;
    100   uint32_t time_lo = timestamp & 0xFFFFFFFF;
    101 
    102   length = htonl(length_he);
    103   flags = htonl(flags);
    104   drops = htonl(drops);
    105   time_hi = htonl(time_hi);
    106   time_lo = htonl(time_lo);
    107 
    108   // This function is called from different contexts.
    109   utils_lock();
    110 
    111   btsnoop_write(&length, 4);
    112   btsnoop_write(&length, 4);
    113   btsnoop_write(&flags, 4);
    114   btsnoop_write(&drops, 4);
    115   btsnoop_write(&time_hi, 4);
    116   btsnoop_write(&time_lo, 4);
    117   btsnoop_write(&type, 1);
    118   btsnoop_write(packet, length_he - 1);
    119 
    120   utils_unlock();
    121 }
    122 
    123 void btsnoop_open(const char *p_path, const bool save_existing) {
    124   assert(p_path != NULL);
    125   assert(*p_path != '\0');
    126 
    127   btsnoop_net_open();
    128 
    129   if (hci_btsnoop_fd != -1) {
    130     ALOGE("%s btsnoop log file is already open.", __func__);
    131     return;
    132   }
    133 
    134   if (save_existing)
    135   {
    136     char fname_backup[266] = {0};
    137     strncat(fname_backup, p_path, 255);
    138     strcat(fname_backup, ".last");
    139     rename(p_path, fname_backup);
    140   }
    141 
    142   hci_btsnoop_fd = open(p_path,
    143                         O_WRONLY | O_CREAT | O_TRUNC,
    144                         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
    145 
    146   if (hci_btsnoop_fd == -1) {
    147     ALOGE("%s unable to open '%s': %s", __func__, p_path, strerror(errno));
    148     return;
    149   }
    150 
    151   write(hci_btsnoop_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
    152 }
    153 
    154 void btsnoop_close(void) {
    155   if (hci_btsnoop_fd != -1)
    156     close(hci_btsnoop_fd);
    157   hci_btsnoop_fd = -1;
    158 
    159   btsnoop_net_close();
    160 }
    161 
    162 void btsnoop_capture(const HC_BT_HDR *p_buf, bool is_rcvd) {
    163   const uint8_t *p = (const uint8_t *)(p_buf + 1) + p_buf->offset;
    164 
    165   if (hci_btsnoop_fd == -1)
    166     return;
    167 
    168   switch (p_buf->event & MSG_EVT_MASK) {
    169     case MSG_HC_TO_STACK_HCI_EVT:
    170       btsnoop_write_packet(kEventPacket, p, false);
    171       break;
    172     case MSG_HC_TO_STACK_HCI_ACL:
    173     case MSG_STACK_TO_HC_HCI_ACL:
    174       btsnoop_write_packet(kAclPacket, p, is_rcvd);
    175       break;
    176     case MSG_HC_TO_STACK_HCI_SCO:
    177     case MSG_STACK_TO_HC_HCI_SCO:
    178       btsnoop_write_packet(kScoPacket, p, is_rcvd);
    179       break;
    180     case MSG_STACK_TO_HC_HCI_CMD:
    181       btsnoop_write_packet(kCommandPacket, p, true);
    182       break;
    183   }
    184 }
    185