1 /******************************************************************************
2 *
3 * Copyright (C) 2015 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 #include <iostream>
20 #include <iomanip>
21 #include <fstream>
22 #include <sstream>
23 #include <string>
24 #include <string.h> // for memcpy
25 #include <vector>
26 #include <resolv.h>
27 #include <zlib.h>
28
29 extern "C" {
30 #include "btif/include/btif_debug_btsnoop.h"
31 #include "hci/include/bt_hci_bdroid.h"
32 #include "stack/include/bt_types.h"
33 #include "stack/include/hcidefs.h"
34 }
35
36 // Epoch in microseconds since 01/01/0000.
37 #define BTSNOOP_EPOCH_DELTA 0x00dcddb30f2f8000ULL
38
39 #define INITIAL_BUFFER_SIZE 131072
40 #define INFLATE_BUFFER 16384
41
42 #define LOG_PREFIX "--- BEGIN:BTSNOOP_LOG_SUMMARY"
43 #define LOG_POSTFIX "--- END:BTSNOOP_LOG_SUMMARY"
44
45 #define H4_DIRECTION_SENT 0
46 #define H4_DIRECTION_RECEIVED 1
47
packetTypeToFlags(const uint8_t type)48 static uint8_t packetTypeToFlags(const uint8_t type) {
49 switch (type << 8) {
50 case MSG_HC_TO_STACK_HCI_ERR:
51 case MSG_HC_TO_STACK_HCI_ACL:
52 case MSG_HC_TO_STACK_HCI_SCO:
53 case MSG_HC_TO_STACK_HCI_EVT:
54 case MSG_HC_TO_STACK_L2C_SEG_XMIT:
55 return H4_DIRECTION_RECEIVED;
56
57 case MSG_STACK_TO_HC_HCI_ACL:
58 case MSG_STACK_TO_HC_HCI_SCO:
59 case MSG_STACK_TO_HC_HCI_CMD:
60 return H4_DIRECTION_SENT;
61
62 default:
63 break;
64 }
65 return 0;
66 }
67
packetTypeToHciType(const uint8_t type)68 static uint8_t packetTypeToHciType(const uint8_t type) {
69 switch (type << 8 & 0xFF00) {
70 case MSG_STACK_TO_HC_HCI_CMD:
71 return HCIT_TYPE_COMMAND;
72
73 case MSG_HC_TO_STACK_HCI_EVT:
74 return HCIT_TYPE_EVENT;
75
76 case MSG_STACK_TO_HC_HCI_ACL:
77 case MSG_HC_TO_STACK_HCI_ACL:
78 return HCIT_TYPE_ACL_DATA;
79
80 case MSG_STACK_TO_HC_HCI_SCO:
81 case MSG_HC_TO_STACK_HCI_SCO:
82 return HCIT_TYPE_SCO_DATA;
83
84 default:
85 break;
86 }
87 return 0;
88 }
89
writeBtSnoop(std::ostream & out,std::vector<uint8_t> & in)90 size_t writeBtSnoop(std::ostream &out, std::vector<uint8_t> &in) {
91 if (in.size() < sizeof(btsnooz_preamble_t))
92 return 0;
93
94 // Get preamble
95
96 uint8_t *p = in.data();
97 btsnooz_preamble_t *preamble = reinterpret_cast<btsnooz_preamble_t*>(p);
98 if (preamble->version != BTSNOOZ_CURRENT_VERSION)
99 return 0;
100
101 // Write header
102
103 const uint8_t header[] = {
104 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00,
105 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xea
106 };
107
108 out.write(reinterpret_cast<const char*>(header), sizeof(header));
109
110 // Calculate first timestamp
111
112 uint64_t first_ts = preamble->last_timestamp_ms + BTSNOOP_EPOCH_DELTA;
113 size_t left = in.size() - sizeof(btsnooz_preamble_t);
114 p = in.data() + sizeof(btsnooz_preamble_t);
115
116 while (left > sizeof(btsnooz_header_t)) {
117 btsnooz_header_t *p_hdr = reinterpret_cast<btsnooz_header_t*>(p);
118 p += sizeof(btsnooz_header_t) + (p_hdr->length - 1);
119 left -= sizeof(btsnooz_header_t) + (p_hdr->length - 1);
120
121 first_ts -= p_hdr->delta_time_ms;
122 }
123
124 // Process packets
125
126 size_t packets = 0;
127 left = in.size() - sizeof(btsnooz_preamble_t);
128 p = in.data() + sizeof(btsnooz_preamble_t);
129
130 while (left > sizeof(btsnooz_header_t)) {
131 btsnooz_header_t *p_hdr = reinterpret_cast<btsnooz_header_t*>(p);
132 p += sizeof(btsnooz_header_t);
133 left -= sizeof(btsnooz_header_t);
134
135 const uint32_t h_length = htonl(p_hdr->length);
136 out.write(reinterpret_cast<const char*>(&h_length), 4);
137 out.write(reinterpret_cast<const char*>(&h_length), 4);
138
139 const uint32_t h_flags = htonl(packetTypeToFlags(p_hdr->type));
140 out.write(reinterpret_cast<const char*>(&h_flags), 4);
141
142 const uint32_t h_dropped = 0;
143 out.write(reinterpret_cast<const char*>(&h_dropped), 4);
144
145 first_ts += p_hdr->delta_time_ms;
146 const uint32_t h_time_hi = htonl(first_ts >> 32);
147 const uint32_t h_time_lo = htonl(first_ts & 0xFFFFFFFF);
148 out.write(reinterpret_cast<const char*>(&h_time_hi), 4);
149 out.write(reinterpret_cast<const char*>(&h_time_lo), 4);
150
151 const uint8_t type = packetTypeToHciType(p_hdr->type);
152 out.write(reinterpret_cast<const char*>(&type), 1);
153
154 out.write(reinterpret_cast<const char*>(p), p_hdr->length - 1);
155
156 p += p_hdr->length - 1;
157 left -= p_hdr->length - 1;
158
159 ++packets;
160 }
161
162 return packets;
163 }
164
readLog(std::istream & in,std::vector<char> & buffer)165 int readLog(std::istream &in, std::vector<char> &buffer) {
166 buffer.reserve(INITIAL_BUFFER_SIZE);
167
168 std::string line;
169
170 const std::string log_prefix(LOG_PREFIX);
171 const std::string log_postfix(LOG_POSTFIX);
172
173 bool in_block = false;
174
175 while (std::getline(in, line)) {
176 // Ensure line endings aren't wonky...
177
178 if (!line.empty() && line[line.size() - 1] == '\r')
179 line.erase(line.end() - 1);
180
181 // Detect block
182
183 if (!in_block) {
184 if (line.compare(0, log_prefix.length(), log_prefix) == 0)
185 in_block = true;
186 continue;
187 }
188
189 if (line.compare(0, log_postfix.length(), log_postfix) == 0)
190 break;
191
192 // Process data
193
194 buffer.insert(buffer.end(), line.begin(), line.end());
195 }
196
197 if (buffer.size() != 0)
198 buffer.push_back(0);
199
200 return buffer.size();
201 }
202
base64Decode(std::vector<char> & buffer)203 int base64Decode(std::vector<char> &buffer) {
204 char *p = buffer.data();
205 return b64_pton(p, reinterpret_cast<uint8_t*>(p), buffer.size());
206 }
207
inflate(std::vector<char> & in,std::vector<uint8_t> & out)208 int inflate(std::vector<char> &in, std::vector<uint8_t> &out) {
209 out.reserve(in.size());
210
211 uint8_t buffer[INFLATE_BUFFER];
212 z_stream zs;
213
214 int ret = inflateInit(&zs);
215 if (Z_OK != ret)
216 return -1;
217
218 // Copy preamble as-is
219
220 for (size_t i = 0; i != sizeof(btsnooz_preamble_t); ++i) {
221 out.push_back(in[i]);
222 }
223
224 // De-compress data
225
226 zs.avail_in = in.size() - sizeof(btsnooz_preamble_t);;
227 zs.next_in = reinterpret_cast<uint8_t*>(in.data()) + sizeof(btsnooz_preamble_t);
228
229 do {
230 zs.avail_out = INFLATE_BUFFER;
231 zs.next_out = buffer;
232
233 ret = inflate(&zs, Z_NO_FLUSH);
234
235 size_t read = INFLATE_BUFFER - zs.avail_out;
236 uint8_t *p = buffer;
237 while (read--)
238 out.push_back(*p++);
239 } while (zs.avail_out == 0);
240
241 inflateEnd(&zs);
242
243 return out.size();
244 }
245