• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <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 <unistd.h>
36 
37 #include "bt_types.h"
38 #include "hci/include/btsnoop.h"
39 #include "hci/include/btsnoop_mem.h"
40 #include "hci_layer.h"
41 #include "osi/include/log.h"
42 #include "osi/include/properties.h"
43 #include "osi/include/time.h"
44 #include "stack_config.h"
45 
46 // The number of of packets per btsnoop file before we rotate to the next
47 // file. As of right now there are two snoop files that are rotated through.
48 // The size can be dynamically configured by seting the relevant system
49 // property
50 #define DEFAULT_BTSNOOP_SIZE 0xffff
51 
52 #define BTSNOOP_ENABLE_PROPERTY "persist.bluetooth.btsnoopenable"
53 #define BTSNOOP_PATH_PROPERTY "persist.bluetooth.btsnooppath"
54 #define DEFAULT_BTSNOOP_PATH "/data/misc/bluetooth/logs/btsnoop_hci.log"
55 #define BTSNOOP_MAX_PACKETS_PROPERTY "persist.bluetooth.btsnoopsize"
56 
57 typedef enum {
58   kCommandPacket = 1,
59   kAclPacket = 2,
60   kScoPacket = 3,
61   kEventPacket = 4
62 } packet_type_t;
63 
64 // Epoch in microseconds since 01/01/0000.
65 static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
66 
67 static int logfile_fd = INVALID_FD;
68 static std::mutex btsnoop_mutex;
69 
70 static int32_t packets_per_file;
71 static int32_t packet_counter;
72 
73 // TODO(zachoverflow): merge btsnoop and btsnoop_net together
74 void btsnoop_net_open();
75 void btsnoop_net_close();
76 void btsnoop_net_write(const void* data, size_t length);
77 
78 static void delete_btsnoop_files();
79 static bool is_btsnoop_enabled();
80 static char* get_btsnoop_log_path(char* log_path);
81 static char* get_btsnoop_last_log_path(char* last_log_path, char* log_path);
82 static void open_next_snoop_file();
83 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
84                                  bool is_received, uint64_t timestamp_us);
85 
86 // Module lifecycle functions
87 
start_up(void)88 static future_t* start_up(void) {
89   std::lock_guard<std::mutex> lock(btsnoop_mutex);
90 
91   if (!is_btsnoop_enabled()) {
92     delete_btsnoop_files();
93   } else {
94     open_next_snoop_file();
95     packets_per_file = osi_property_get_int32(BTSNOOP_MAX_PACKETS_PROPERTY,
96                                               DEFAULT_BTSNOOP_SIZE);
97     btsnoop_net_open();
98   }
99 
100   return NULL;
101 }
102 
shut_down(void)103 static future_t* shut_down(void) {
104   std::lock_guard<std::mutex> lock(btsnoop_mutex);
105 
106   if (!is_btsnoop_enabled()) {
107     delete_btsnoop_files();
108   }
109 
110   if (logfile_fd != INVALID_FD) close(logfile_fd);
111   logfile_fd = INVALID_FD;
112 
113   btsnoop_net_close();
114 
115   return NULL;
116 }
117 
118 EXPORT_SYMBOL extern const module_t btsnoop_module = {
119     .name = BTSNOOP_MODULE,
120     .init = NULL,
121     .start_up = start_up,
122     .shut_down = shut_down,
123     .clean_up = NULL,
124     .dependencies = {STACK_CONFIG_MODULE, NULL}};
125 
126 // Interface functions
capture(const BT_HDR * buffer,bool is_received)127 static void capture(const BT_HDR* buffer, bool is_received) {
128   uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
129 
130   std::lock_guard<std::mutex> lock(btsnoop_mutex);
131   uint64_t timestamp_us = time_gettimeofday_us();
132   btsnoop_mem_capture(buffer, timestamp_us);
133 
134   if (logfile_fd == INVALID_FD) return;
135 
136   switch (buffer->event & MSG_EVT_MASK) {
137     case MSG_HC_TO_STACK_HCI_EVT:
138       btsnoop_write_packet(kEventPacket, p, false, timestamp_us);
139       break;
140     case MSG_HC_TO_STACK_HCI_ACL:
141     case MSG_STACK_TO_HC_HCI_ACL:
142       btsnoop_write_packet(kAclPacket, p, is_received, timestamp_us);
143       break;
144     case MSG_HC_TO_STACK_HCI_SCO:
145     case MSG_STACK_TO_HC_HCI_SCO:
146       btsnoop_write_packet(kScoPacket, p, is_received, timestamp_us);
147       break;
148     case MSG_STACK_TO_HC_HCI_CMD:
149       btsnoop_write_packet(kCommandPacket, p, true, timestamp_us);
150       break;
151   }
152 }
153 
154 static const btsnoop_t interface = {capture};
155 
btsnoop_get_interface()156 const btsnoop_t* btsnoop_get_interface() {
157   return &interface;
158 }
159 
160 // Internal functions
delete_btsnoop_files()161 static void delete_btsnoop_files() {
162   LOG_VERBOSE(LOG_TAG, "Deleting snoop log if it exists");
163   char log_path[PROPERTY_VALUE_MAX];
164   char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
165   get_btsnoop_log_path(log_path);
166   get_btsnoop_last_log_path(last_log_path, log_path);
167   remove(log_path);
168   remove(last_log_path);
169 }
170 
is_btsnoop_enabled()171 static bool is_btsnoop_enabled() {
172   char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0};
173   osi_property_get(BTSNOOP_ENABLE_PROPERTY, btsnoop_enabled, "false");
174   return strncmp(btsnoop_enabled, "true", 4) == 0;
175 }
176 
get_btsnoop_log_path(char * btsnoop_path)177 static char* get_btsnoop_log_path(char* btsnoop_path) {
178   osi_property_get(BTSNOOP_PATH_PROPERTY, btsnoop_path, DEFAULT_BTSNOOP_PATH);
179   return btsnoop_path;
180 }
181 
get_btsnoop_last_log_path(char * last_log_path,char * btsnoop_path)182 static char* get_btsnoop_last_log_path(char* last_log_path,
183                                        char* btsnoop_path) {
184   snprintf(last_log_path, PROPERTY_VALUE_MAX + sizeof(".last"), "%s.last",
185            btsnoop_path);
186   return last_log_path;
187 }
188 
open_next_snoop_file()189 static void open_next_snoop_file() {
190   packet_counter = 0;
191 
192   if (logfile_fd != INVALID_FD) {
193     close(logfile_fd);
194     logfile_fd = INVALID_FD;
195   }
196 
197   char log_path[PROPERTY_VALUE_MAX];
198   char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
199   get_btsnoop_log_path(log_path);
200   get_btsnoop_last_log_path(last_log_path, log_path);
201 
202   if (!rename(log_path, last_log_path) && errno != ENOENT)
203     LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
204               log_path, last_log_path, strerror(errno));
205 
206   mode_t prevmask = umask(0);
207   logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC,
208                     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
209   umask(prevmask);
210   if (logfile_fd == INVALID_FD) {
211     LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path,
212               strerror(errno));
213     return;
214   }
215 
216   write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
217 }
218 
219 typedef struct {
220   uint32_t length_original;
221   uint32_t length_captured;
222   uint32_t flags;
223   uint32_t dropped_packets;
224   uint64_t timestamp;
225   uint8_t type;
226 } __attribute__((__packed__)) btsnoop_header_t;
227 
htonll(uint64_t ll)228 static uint64_t htonll(uint64_t ll) {
229   const uint32_t l = 1;
230   if (*(reinterpret_cast<const uint8_t*>(&l)) == 1)
231     return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 |
232            htonl(ll >> 32);
233 
234   return ll;
235 }
236 
btsnoop_write_packet(packet_type_t type,uint8_t * packet,bool is_received,uint64_t timestamp_us)237 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
238                                  bool is_received, uint64_t timestamp_us) {
239   uint32_t length_he = 0;
240   uint32_t flags = 0;
241 
242   switch (type) {
243     case kCommandPacket:
244       length_he = packet[2] + 4;
245       flags = 2;
246       break;
247     case kAclPacket:
248       length_he = (packet[3] << 8) + packet[2] + 5;
249       flags = is_received;
250       break;
251     case kScoPacket:
252       length_he = packet[2] + 4;
253       flags = is_received;
254       break;
255     case kEventPacket:
256       length_he = packet[1] + 3;
257       flags = 3;
258       break;
259   }
260 
261   btsnoop_header_t header;
262   header.length_original = htonl(length_he);
263   header.length_captured = header.length_original;
264   header.flags = htonl(flags);
265   header.dropped_packets = 0;
266   header.timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA);
267   header.type = type;
268 
269   btsnoop_net_write(&header, sizeof(btsnoop_header_t));
270   btsnoop_net_write(packet, length_he - 1);
271 
272   if (logfile_fd != INVALID_FD) {
273     packet_counter++;
274     if (packet_counter > packets_per_file) {
275       open_next_snoop_file();
276     }
277 
278     iovec iov[] = {{&header, sizeof(btsnoop_header_t)},
279                    {reinterpret_cast<void*>(packet), length_he - 1}};
280     TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2));
281   }
282 }
283