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 }