1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "btm_snoop.h"
17
18 #include <stdio.h>
19
20 #include <securec.h>
21 #include <sys/time.h>
22
23 #include "hci/hci.h"
24 #include "platform/include/allocator.h"
25 #include "platform/include/bt_endian.h"
26 #include "platform/include/mutex.h"
27 #include "platform/include/queue.h"
28 #include "platform/include/reactor.h"
29 #include "platform/include/thread.h"
30
31 #include "btm.h"
32 #include "btm/btm_snoop_filter.h"
33 #include "log.h"
34
35 #define SNOOP_INDENTIFICATION_PATTERN \
36 { \
37 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 \
38 }
39 #define SNOOP_VERSION_NUMBER 1
40 #define SNOOP_DATALINK_TYPE_H4 1002
41
42 #define MICROSECOND_1970BASE 62168256000000000
43
44 #define H4_HEADER_CMD 0x01
45 #define H4_HEADER_ACLDATA 0x02
46 #define H4_HEADER_EVENT 0x04
47
48 #define SNOOP_PACKET_FLAG_SENT 0x00
49 #define SNOOP_PACKET_FLAG_RECEIVED 0x01
50 #define SNOOP_PACKET_FLAG_DATA 0x00
51 #define SNOOP_PACKET_FLAG_CMD_EVENT 0x02
52
53 #define SNOOP_LAST_FILE_TAIL ".last"
54
55 #define MICROSECOND 1000000
56
57 #define SNOOP_BLOCK_IOV_COUNT 3
58
59 #define HCI_LOG_PATH "./hci.log"
60
61 #define HCI_H4_HEADER_LEN 1
62
63 #define KILOBYTES 1024
64
65 #pragma pack(1)
66 typedef struct {
67 uint8_t identificationPattern[8]; // { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 }
68 uint32_t versionNumber; // 1
69 uint32_t datalinkType; // 1002
70 } BtmSnoopFileHeader;
71
72 typedef struct {
73 uint32_t originalLength;
74 uint32_t includedLength;
75 uint32_t packetFlags;
76 uint32_t cumulativeDrops;
77 uint64_t timestamp; // microseconds
78 } BtmSnoopPacketHeader;
79 #pragma pack()
80
81 static bool g_output = false;
82 static char *g_outputPath = NULL;
83 static FILE *g_outputFile = NULL;
84 static bool g_hciLogOuput = false;
85 static Mutex *g_outputMutex = NULL;
86 static long int g_outputMaxsize = 0;
87
GetH4HeaderAndPacketFlags(uint8_t type,uint8_t * h4Header,uint32_t * packetFlags)88 static void GetH4HeaderAndPacketFlags(uint8_t type, uint8_t *h4Header, uint32_t *packetFlags)
89 {
90 switch (type) {
91 case TRANSMISSON_TYPE_H2C_CMD:
92 *h4Header = H4_HEADER_CMD;
93 *packetFlags = SNOOP_PACKET_FLAG_SENT | SNOOP_PACKET_FLAG_CMD_EVENT;
94 break;
95 case TRANSMISSON_TYPE_C2H_EVENT:
96 *h4Header = H4_HEADER_EVENT;
97 *packetFlags = SNOOP_PACKET_FLAG_RECEIVED | SNOOP_PACKET_FLAG_CMD_EVENT;
98 break;
99 case TRANSMISSON_TYPE_H2C_DATA:
100 *h4Header = H4_HEADER_ACLDATA;
101 *packetFlags = SNOOP_PACKET_FLAG_SENT | SNOOP_PACKET_FLAG_DATA;
102 break;
103 case TRANSMISSON_TYPE_C2H_DATA:
104 *h4Header = H4_HEADER_ACLDATA;
105 *packetFlags = SNOOP_PACKET_FLAG_RECEIVED | SNOOP_PACKET_FLAG_DATA;
106 break;
107 default:
108 break;
109 }
110 }
111
BtmSnoopOutput(uint8_t type,const uint8_t * data,uint16_t length)112 static void BtmSnoopOutput(uint8_t type, const uint8_t *data, uint16_t length)
113 {
114 struct timeval tv;
115 gettimeofday(&tv, NULL);
116
117 const uint64_t timestamp = MICROSECOND_1970BASE + tv.tv_sec * MICROSECOND + tv.tv_usec;
118
119 uint8_t h4Header = 0;
120 uint32_t packetFlags = 0;
121
122 GetH4HeaderAndPacketFlags(type, &h4Header, &packetFlags);
123
124 uint16_t originalLength = length + 1;
125 uint16_t includedLength = length + 1;
126 const uint8_t *outputData = data;
127
128 BtmHciFilter(type, &outputData, originalLength, &includedLength);
129
130 BtmSnoopPacketHeader header = {
131 .originalLength = H2BE_32(originalLength),
132 .includedLength = H2BE_32(includedLength),
133 .cumulativeDrops = H2BE_32(0),
134 .packetFlags = H2BE_32(packetFlags),
135 .timestamp = H2BE_64(timestamp),
136 };
137
138 if (g_outputFile == NULL) {
139 LOG_ERROR("%{public}s, g_outputFile is NULL", __FUNCTION__);
140 return;
141 }
142 MutexLock(g_outputMutex);
143
144 (void)fwrite(&header, 1, sizeof(BtmSnoopPacketHeader), g_outputFile);
145 (void)fwrite(&h4Header, 1, HCI_H4_HEADER_LEN, g_outputFile);
146 (void)fwrite(outputData, 1, includedLength - HCI_H4_HEADER_LEN, g_outputFile);
147
148 fflush(g_outputFile);
149
150 long int position = ftell(g_outputFile);
151 if (position >= g_outputMaxsize) {
152 LOG_ERROR("%{public}s, snooplog %{public}ld larger than maxsize %{public}ld",
153 __FUNCTION__, position, g_outputMaxsize);
154 fseek(g_outputFile, 0, SEEK_SET);
155 }
156
157 if (outputData != data) {
158 MEM_MALLOC.free((void *)outputData);
159 }
160
161 MutexUnlock(g_outputMutex);
162 }
163
BtmOnHciTransmission(uint8_t type,const uint8_t * data,uint16_t length)164 static void BtmOnHciTransmission(uint8_t type, const uint8_t *data, uint16_t length)
165 {
166 BtmSnoopOutput(type, data, length);
167 }
168
BtmWriteSnoopFileHeader(void)169 static void BtmWriteSnoopFileHeader(void)
170 {
171 BtmSnoopFileHeader header = {
172 .identificationPattern = SNOOP_INDENTIFICATION_PATTERN,
173 .versionNumber = H2BE_32(SNOOP_VERSION_NUMBER),
174 .datalinkType = H2BE_32(SNOOP_DATALINK_TYPE_H4),
175 };
176
177 if (g_outputFile == NULL) {
178 LOG_ERROR("%{public}s, g_outputFile is NULL", __FUNCTION__);
179 return;
180 }
181 MutexLock(g_outputMutex);
182
183 (void)fwrite(&header, 1, sizeof(BtmSnoopFileHeader), g_outputFile);
184
185 fflush(g_outputFile);
186
187 MutexUnlock(g_outputMutex);
188 }
189
BtmIsFileExists(const char * path)190 static bool BtmIsFileExists(const char *path)
191 {
192 bool exists = false;
193 FILE *file = fopen(path, "r");
194 if (file != NULL) {
195 exists = true;
196 fclose(file);
197 }
198 return exists;
199 }
200
BtmPrepareSnoopFile(void)201 static void BtmPrepareSnoopFile(void)
202 {
203 if (g_hciLogOuput) {
204 bool exists = BtmIsFileExists(HCI_LOG_PATH);
205 if (exists) {
206 g_outputFile = fopen(HCI_LOG_PATH, "a");
207 if (g_outputFile == NULL) {
208 return;
209 }
210 } else {
211 g_outputFile = fopen(HCI_LOG_PATH, "w");
212 if (g_outputFile == NULL) {
213 return;
214 }
215
216 BtmWriteSnoopFileHeader();
217 }
218 } else {
219 bool exists = BtmIsFileExists(g_outputPath);
220 if (exists) {
221 const int length = strlen(g_outputPath) + strlen(SNOOP_LAST_FILE_TAIL) + 1;
222 char *bakPath = MEM_CALLOC.alloc(length);
223 if (bakPath == NULL) {
224 return;
225 }
226 if (strcpy_s(bakPath, length, g_outputPath) != EOK) {
227 return;
228 }
229 (void)strcat_s(bakPath, length, SNOOP_LAST_FILE_TAIL);
230 rename(g_outputPath, bakPath);
231
232 MEM_CALLOC.free(bakPath);
233 }
234
235 g_outputFile = fopen(g_outputPath, "w");
236 if (g_outputFile == NULL) {
237 LOG_ERROR("%{public}s, g_outputFile is NULL:%{public}s", __FUNCTION__, strerror(errno));
238 return;
239 }
240
241 BtmWriteSnoopFileHeader();
242 }
243 }
244
BTM_SetSnoopOutputMaxsize(uint16_t maxSize)245 int BTM_SetSnoopOutputMaxsize(uint16_t maxSize)
246 {
247 g_outputMaxsize = maxSize * KILOBYTES * KILOBYTES;
248 return BT_SUCCESS;
249 }
250
BtmCloseSnoopFile(void)251 static void BtmCloseSnoopFile(void)
252 {
253 if (g_outputFile != NULL) {
254 fclose(g_outputFile);
255 g_outputFile = NULL;
256 }
257 }
258
BTM_SetSnoopFilePath(const char * path,uint16_t length)259 int BTM_SetSnoopFilePath(const char *path, uint16_t length)
260 {
261 g_outputPath = (char *)MEM_MALLOC.alloc(length + 1);
262 if (g_outputPath == NULL) {
263 return BT_NO_MEMORY;
264 }
265
266 (void)memcpy_s(g_outputPath, length + 1, path, length);
267 g_outputPath[length] = '\0';
268 return BT_SUCCESS;
269 }
270
BTM_EnableSnoopFileOutput(bool filter)271 int BTM_EnableSnoopFileOutput(bool filter)
272 {
273 g_output = true;
274 if (filter) {
275 BtmEnableSnoopFilter();
276 } else {
277 BtmDisableSnoopFilter();
278 }
279 return BT_SUCCESS;
280 }
281
BTM_DisableSnoopFileOutput(void)282 int BTM_DisableSnoopFileOutput(void)
283 {
284 if (g_output) {
285 BtmDisableSnoopFilter();
286 }
287 g_output = false;
288 return BT_SUCCESS;
289 }
290
BtmStartSnoopOutput(void)291 void BtmStartSnoopOutput(void)
292 {
293 if (g_hciLogOuput || (g_output && g_outputPath != NULL)) {
294 BtmPrepareSnoopFile();
295
296 HCI_SetTransmissionCaptureCallback(BtmOnHciTransmission);
297 HCI_EnableTransmissionCapture();
298 }
299 }
300
BtmStopSnoopOutput(void)301 void BtmStopSnoopOutput(void)
302 {
303 HCI_DisableTransmissionCapture();
304
305 BtmCloseSnoopFile();
306 }
307
BtmInitSnoop(void)308 void BtmInitSnoop(void)
309 {
310 g_outputMutex = MutexCreate();
311 BtmInitSnoopFilter();
312 }
313
BtmCloseSnoop(void)314 void BtmCloseSnoop(void)
315 {
316 g_output = false;
317 g_hciLogOuput = false;
318
319 BtmCloseSnoopFilter();
320
321 if (g_outputMutex != NULL) {
322 MutexDelete(g_outputMutex);
323 g_outputMutex = NULL;
324 }
325
326 if (g_outputPath != NULL) {
327 MEM_MALLOC.free(g_outputPath);
328 g_outputPath = NULL;
329 }
330 }
331
BTM_EnableHciLogOutput(bool filter)332 int BTM_EnableHciLogOutput(bool filter)
333 {
334 g_hciLogOuput = true;
335 if (filter) {
336 BtmEnableSnoopFilter();
337 } else {
338 BtmDisableSnoopFilter();
339 }
340 return BT_SUCCESS;
341 }
342
BTM_DisableHciLogOutput(void)343 int BTM_DisableHciLogOutput(void)
344 {
345 if (g_hciLogOuput) {
346 BtmDisableSnoopFilter();
347 }
348 g_hciLogOuput = false;
349 return BT_SUCCESS;
350 }