• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma pack(1)
64 typedef struct {
65     uint8_t identificationPattern[8];  // { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 }
66     uint32_t versionNumber;            // 1
67     uint32_t datalinkType;             // 1002
68 } BtmSnoopFileHeader;
69 
70 typedef struct {
71     uint32_t originalLength;
72     uint32_t includedLength;
73     uint32_t packetFlags;
74     uint32_t cumulativeDrops;
75     uint64_t timestamp;  // microseconds
76 } BtmSnoopPacketHeader;
77 #pragma pack()
78 
79 static bool g_output = false;
80 static char *g_outputPath = NULL;
81 static FILE *g_outputFile = NULL;
82 static bool g_hciLogOuput = false;
83 static Mutex *g_outputMutex = NULL;
84 
GetH4HeaderAndPacketFlags(uint8_t type,uint8_t * h4Header,uint32_t * packetFlags)85 static void GetH4HeaderAndPacketFlags(uint8_t type, uint8_t *h4Header, uint32_t *packetFlags)
86 {
87     switch (type) {
88         case TRANSMISSON_TYPE_H2C_CMD:
89             *h4Header = H4_HEADER_CMD;
90             *packetFlags = SNOOP_PACKET_FLAG_SENT | SNOOP_PACKET_FLAG_CMD_EVENT;
91             break;
92         case TRANSMISSON_TYPE_C2H_EVENT:
93             *h4Header = H4_HEADER_EVENT;
94             *packetFlags = SNOOP_PACKET_FLAG_RECEIVED | SNOOP_PACKET_FLAG_CMD_EVENT;
95             break;
96         case TRANSMISSON_TYPE_H2C_DATA:
97             *h4Header = H4_HEADER_ACLDATA;
98             *packetFlags = SNOOP_PACKET_FLAG_SENT | SNOOP_PACKET_FLAG_DATA;
99             break;
100         case TRANSMISSON_TYPE_C2H_DATA:
101             *h4Header = H4_HEADER_ACLDATA;
102             *packetFlags = SNOOP_PACKET_FLAG_RECEIVED | SNOOP_PACKET_FLAG_DATA;
103             break;
104         default:
105             break;
106     }
107 }
108 
BtmSnoopOutput(uint8_t type,const uint8_t * data,uint16_t length)109 static void BtmSnoopOutput(uint8_t type, const uint8_t *data, uint16_t length)
110 {
111     struct timeval tv;
112     gettimeofday(&tv, NULL);
113 
114     const uint64_t timestamp = MICROSECOND_1970BASE + tv.tv_sec * MICROSECOND + tv.tv_usec;
115 
116     uint8_t h4Header = 0;
117     uint32_t packetFlags = 0;
118 
119     GetH4HeaderAndPacketFlags(type, &h4Header, &packetFlags);
120 
121     uint16_t originalLength = length + 1;
122     uint16_t includedLength = length + 1;
123     const uint8_t *outputData = data;
124 
125     BtmHciFilter(type, &outputData, originalLength, &includedLength);
126 
127     BtmSnoopPacketHeader header = {
128         .originalLength = H2BE_32(originalLength),
129         .includedLength = H2BE_32(includedLength),
130         .cumulativeDrops = H2BE_32(0),
131         .packetFlags = H2BE_32(packetFlags),
132         .timestamp = H2BE_64(timestamp),
133     };
134 
135     if (g_outputFile == NULL) {
136         LOG_ERROR("%{public}s, g_outputFile is NULL", __FUNCTION__);
137         return;
138     }
139     MutexLock(g_outputMutex);
140 
141     (void)fwrite(&header, 1, sizeof(BtmSnoopPacketHeader), g_outputFile);
142     (void)fwrite(&h4Header, 1, HCI_H4_HEADER_LEN, g_outputFile);
143     (void)fwrite(outputData, 1, includedLength - HCI_H4_HEADER_LEN, g_outputFile);
144 
145     fflush(g_outputFile);
146 
147     if (outputData != data) {
148         MEM_MALLOC.free((void *)outputData);
149     }
150 
151     MutexUnlock(g_outputMutex);
152 }
153 
BtmOnHciTransmission(uint8_t type,const uint8_t * data,uint16_t length)154 static void BtmOnHciTransmission(uint8_t type, const uint8_t *data, uint16_t length)
155 {
156     BtmSnoopOutput(type, data, length);
157 }
158 
BtmWriteSnoopFileHeader(void)159 static void BtmWriteSnoopFileHeader(void)
160 {
161     BtmSnoopFileHeader header = {
162         .identificationPattern = SNOOP_INDENTIFICATION_PATTERN,
163         .versionNumber = H2BE_32(SNOOP_VERSION_NUMBER),
164         .datalinkType = H2BE_32(SNOOP_DATALINK_TYPE_H4),
165     };
166 
167     if (g_outputFile == NULL) {
168         LOG_ERROR("%{public}s, g_outputFile is NULL", __FUNCTION__);
169         return;
170     }
171     MutexLock(g_outputMutex);
172 
173     (void)fwrite(&header, 1, sizeof(BtmSnoopFileHeader), g_outputFile);
174 
175     fflush(g_outputFile);
176 
177     MutexUnlock(g_outputMutex);
178 }
179 
BtmIsFileExists(const char * path)180 static bool BtmIsFileExists(const char *path)
181 {
182     bool exists = false;
183     FILE *file = fopen(path, "r");
184     if (file != NULL) {
185         exists = true;
186         fclose(file);
187     }
188     return exists;
189 }
190 
BtmPrepareSnoopFile(void)191 static void BtmPrepareSnoopFile(void)
192 {
193     if (g_hciLogOuput) {
194         bool exists = BtmIsFileExists(HCI_LOG_PATH);
195         if (exists) {
196             g_outputFile = fopen(HCI_LOG_PATH, "a");
197             if (g_outputFile == NULL) {
198                 return;
199             }
200         } else {
201             g_outputFile = fopen(HCI_LOG_PATH, "w");
202             if (g_outputFile == NULL) {
203                 return;
204             }
205 
206             BtmWriteSnoopFileHeader();
207         }
208     } else {
209         bool exists = BtmIsFileExists(g_outputPath);
210         if (exists) {
211             const int length = strlen(g_outputPath) + strlen(SNOOP_LAST_FILE_TAIL) + 1;
212             char *bakPath = MEM_CALLOC.alloc(length);
213             if (bakPath == NULL) {
214                 return;
215             }
216             if (strcpy_s(bakPath, length, g_outputPath) != EOK) {
217                 return;
218             }
219             (void)strcat_s(bakPath, length, SNOOP_LAST_FILE_TAIL);
220             rename(g_outputPath, bakPath);
221 
222             MEM_CALLOC.free(bakPath);
223         }
224 
225         g_outputFile = fopen(g_outputPath, "w");
226         if (g_outputFile == NULL) {
227             LOG_ERROR("%{public}s, g_outputFile is NULL:%{public}s", __FUNCTION__, strerror(errno));
228             return;
229         }
230 
231         BtmWriteSnoopFileHeader();
232     }
233 }
234 
BtmCloseSnoopFile(void)235 static void BtmCloseSnoopFile(void)
236 {
237     if (g_outputFile != NULL) {
238         fclose(g_outputFile);
239         g_outputFile = NULL;
240     }
241 }
242 
BTM_SetSnoopFilePath(const char * path,uint16_t length)243 int BTM_SetSnoopFilePath(const char *path, uint16_t length)
244 {
245     g_outputPath = (char *)MEM_MALLOC.alloc(length + 1);
246     if (g_outputPath == NULL) {
247         return BT_NO_MEMORY;
248     }
249 
250     (void)memcpy_s(g_outputPath, length + 1, path, length);
251     g_outputPath[length] = '\0';
252     return BT_SUCCESS;
253 }
254 
BTM_EnableSnoopFileOutput(bool filter)255 int BTM_EnableSnoopFileOutput(bool filter)
256 {
257     g_output = true;
258     if (filter) {
259         BtmEnableSnoopFilter();
260     } else {
261         BtmDisableSnoopFilter();
262     }
263     return BT_SUCCESS;
264 }
265 
BTM_DisableSnoopFileOutput(void)266 int BTM_DisableSnoopFileOutput(void)
267 {
268     if (g_output) {
269         BtmDisableSnoopFilter();
270     }
271     g_output = false;
272     return BT_SUCCESS;
273 }
274 
BtmStartSnoopOutput(void)275 void BtmStartSnoopOutput(void)
276 {
277     if (g_hciLogOuput || (g_output && g_outputPath != NULL)) {
278         BtmPrepareSnoopFile();
279 
280         HCI_SetTransmissionCaptureCallback(BtmOnHciTransmission);
281         HCI_EnableTransmissionCapture();
282     }
283 }
284 
BtmStopSnoopOutput(void)285 void BtmStopSnoopOutput(void)
286 {
287     HCI_DisableTransmissionCapture();
288 
289     BtmCloseSnoopFile();
290 }
291 
BtmInitSnoop(void)292 void BtmInitSnoop(void)
293 {
294     g_outputMutex = MutexCreate();
295     BtmInitSnoopFilter();
296 }
297 
BtmCloseSnoop(void)298 void BtmCloseSnoop(void)
299 {
300     g_output = false;
301     g_hciLogOuput = false;
302 
303     BtmCloseSnoopFilter();
304 
305     if (g_outputMutex != NULL) {
306         MutexDelete(g_outputMutex);
307         g_outputMutex = NULL;
308     }
309 
310     if (g_outputPath != NULL) {
311         MEM_MALLOC.free(g_outputPath);
312         g_outputPath = NULL;
313     }
314 }
315 
BTM_EnableHciLogOutput(bool filter)316 int BTM_EnableHciLogOutput(bool filter)
317 {
318     g_hciLogOuput = true;
319     if (filter) {
320         BtmEnableSnoopFilter();
321     } else {
322         BtmDisableSnoopFilter();
323     }
324     return BT_SUCCESS;
325 }
326 
BTM_DisableHciLogOutput(void)327 int BTM_DisableHciLogOutput(void)
328 {
329     if (g_hciLogOuput) {
330         BtmDisableSnoopFilter();
331     }
332     g_hciLogOuput = false;
333     return BT_SUCCESS;
334 }