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