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 }