• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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