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