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