• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
btsnoop_timestamp(void)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 
btsnoop_write(const void * data,size_t length)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 
btsnoop_write_packet(packet_type_t type,const uint8_t * packet,bool is_received)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 
btsnoop_open(const char * p_path,const bool save_existing)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 
btsnoop_close(void)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 
btsnoop_capture(const HC_BT_HDR * p_buf,bool is_rcvd)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