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