1/*
2 * Copyright (C) 2021-2022 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 "hci.h"
17
18#include "btm/btm_thread.h"
19#include "btstack.h"
20#include "log.h"
21#include "packet.h"
22#include "platform/include/allocator.h"
23#include "platform/include/event.h"
24#include "platform/include/module.h"
25#include "platform/include/queue.h"
26#include "platform/include/reactor.h"
27#include "platform/include/semaphore.h"
28#include "platform/include/thread.h"
29
30#include "alarm.h"
31#include "acl/hci_acl.h"
32#include "cmd/hci_cmd.h"
33#include "evt/hci_evt.h"
34#include "hdi_wrapper.h"
35#include "hci_def.h"
36#include "hci_failure.h"
37#include "hci_internal.h"
38#include "hci_vendor_if.h"
39
40#include <unistd.h>
41#include <sys/wait.h>
42#include "securec.h"
43
44#define HCI_TX_QUEUE_SIZE INT32_MAX
45#define HCI_RX_QUEUE_SIZE INT32_MAX
46#define HCI_WAIT_HDI_INIT_TIME 5000
47
48static BtHciCallbacks g_hdiCallacks;
49
50static Queue *g_hciTxQueue = NULL;
51static Queue *g_hciRxQueue = NULL;
52
53static ReactorItem *g_hciTxReactorItem = NULL;
54static ReactorItem *g_hciRxReactorItem = NULL;
55
56static Semaphore *g_waitHdiInit;
57static BtInitStatus g_hdiInitStatus = UNKNOWN;
58static Alarm *g_waitHdiInitAlarm = NULL;
59
60static HDILib *g_hdiLib = NULL;
61
62static bool g_transmissionCapture = false;
63static void (*g_transmissionCallback)(uint8_t type, const uint8_t *data, uint16_t length) = NULL;
64
65static Thread *g_hciTxThread = NULL;
66
67// Function Declare
68static void HciSendPacketCallback(void *param);
69static void HciRecvPacketCallback(void *param);
70
71static void HciFreePacket(void *packet)
72{
73    HciPacket *hciPacket = packet;
74    if (hciPacket != NULL) {
75        PacketFree(hciPacket->packet);
76    }
77    MEM_MALLOC.free(packet);
78}
79
80static void HciOnHDIInitedTimerTimeout(void *param)
81{
82    pid_t pid = getpid();
83    LOG_DEBUG("%{public}s pid:%{public}d", __FUNCTION__, pid);
84    if (kill(pid, SIGTERM) == -1) {
85        if (ESRCH == errno) {
86            LOG_INFO("kill [%{public}d] success, pid no exist", pid);
87        }
88        LOG_ERROR("kill [%{public}d] failed", pid);
89    }
90}
91
92static int HciInitQueue()
93{
94    int result = BT_SUCCESS;
95
96    do {
97        g_hciTxQueue = QueueCreate(HCI_TX_QUEUE_SIZE);
98        if (g_hciTxQueue != NULL) {
99            Reactor *reactor = ThreadGetReactor(g_hciTxThread);
100            g_hciTxReactorItem =
101                ReactorRegister(reactor, QueueGetDequeueFd(g_hciTxQueue), NULL, HciSendPacketCallback, NULL);
102        } else {
103            result = BT_OPERATION_FAILED;
104            break;
105        }
106        g_hciRxQueue = QueueCreate(HCI_RX_QUEUE_SIZE);
107        if (g_hciRxQueue != NULL) {
108            Reactor *reactor = ThreadGetReactor(BTM_GetProcessingThread());
109            g_hciRxReactorItem =
110                ReactorRegister(reactor, QueueGetDequeueFd(g_hciRxQueue), NULL, HciRecvPacketCallback, NULL);
111        } else {
112            result = BT_OPERATION_FAILED;
113            break;
114        }
115    } while (0);
116
117    return result;
118}
119
120NO_SANITIZE("cfi") static int HciInitHal()
121{
122    int result = BT_SUCCESS;
123
124    g_waitHdiInit = SemaphoreCreate(0);
125    int ret = g_hdiLib->hdiInit(&g_hdiCallacks);
126    if (ret == SUCCESS) {
127        g_waitHdiInitAlarm = AlarmCreate(NULL, false);
128        if (g_waitHdiInitAlarm == NULL) {
129            LOG_ERROR("HdiInited alarm create failed");
130        } else {
131            AlarmSet(g_waitHdiInitAlarm, HCI_WAIT_HDI_INIT_TIME, HciOnHDIInitedTimerTimeout, NULL);
132        }
133        SemaphoreWait(g_waitHdiInit);
134        if (g_hdiInitStatus != SUCCESS) {
135            LOG_ERROR("HdiInited failed: %{public}d", g_hdiInitStatus);
136            result = BT_OPERATION_FAILED;
137        }
138    } else {
139        LOG_ERROR("hdiInit failed: %{public}d", ret);
140        result = BT_OPERATION_FAILED;
141    }
142    SemaphoreDelete(g_waitHdiInit);
143    g_waitHdiInit = NULL;
144
145    return result;
146}
147
148static void HciCloseQueue()
149{
150    if (g_hciTxReactorItem != NULL) {
151        ReactorUnregister(g_hciTxReactorItem);
152        g_hciTxReactorItem = NULL;
153    }
154
155    if (g_hciRxReactorItem != NULL) {
156        ReactorUnregister(g_hciRxReactorItem);
157        g_hciRxReactorItem = NULL;
158    }
159
160    if (g_hciTxQueue != NULL) {
161        QueueDelete(g_hciTxQueue, HciFreePacket);
162        g_hciTxQueue = NULL;
163    }
164
165    if (g_hciRxQueue != NULL) {
166        QueueDelete(g_hciRxQueue, HciFreePacket);
167        g_hciRxQueue = NULL;
168    }
169}
170
171int HCI_Initialize()
172{
173    LOG_DEBUG("%{public}s start", __FUNCTION__);
174    int result;
175
176    do {
177        g_hdiLib = LoadHdiLib();
178        if (g_hdiLib == NULL) {
179            result = BT_OPERATION_FAILED;
180            break;
181        }
182
183        HciInitFailure();
184        HciInitCmd();
185        HciInitEvent();
186        HciInitAcl();
187        HciVendorInit();
188
189        g_hciTxThread = ThreadCreate("HciTx");
190        if (g_hciTxThread == NULL) {
191            result = BT_OPERATION_FAILED;
192            break;
193        }
194
195        result = HciInitQueue();
196        if (result != BT_SUCCESS) {
197            break;
198        }
199
200        result = HciInitHal();
201    } while (0);
202
203    if (result != BT_SUCCESS) {
204        if (g_hdiLib != NULL) {
205            if (g_hdiLib->hdiClose != NULL) {
206                g_hdiLib->hdiClose();
207            }
208            UnloadHdiLib(g_hdiLib);
209            g_hdiLib = NULL;
210        }
211
212        HciCloseQueue();
213
214        if (g_hciTxThread != NULL) {
215            ThreadDelete(g_hciTxThread);
216            g_hciTxThread = NULL;
217        }
218    }
219    LOG_DEBUG("%{public}s end", __FUNCTION__);
220    return result;
221}
222
223static void CleanTxPacket()
224{
225    if (g_hciTxQueue != NULL) {
226        HciPacket *packet = QueueTryDequeue(g_hciTxQueue);
227        while (packet != NULL) {
228            HciFreePacket(packet);
229            packet = QueueTryDequeue(g_hciTxQueue);
230        }
231    }
232}
233
234static void CleanRxPacket()
235{
236    if (g_hciRxQueue != NULL) {
237        HciPacket *packet = QueueTryDequeue(g_hciRxQueue);
238        while (packet != NULL) {
239            HciFreePacket(packet);
240            packet = QueueTryDequeue(g_hciTxQueue);
241        }
242    }
243}
244
245static void WaitRxTaskCompleteTask(void *context)
246{
247    Event *taskCompleteEvent = (Event *)context;
248    if (taskCompleteEvent != NULL) {
249        EventSet(taskCompleteEvent);
250    }
251}
252
253static void WaitRxTaskComplete()
254{
255    const int taskTimeout = 1000;
256
257    Event *taskCompleteEvent = EventCreate(true);
258    if (taskCompleteEvent != NULL) {
259        ThreadPostTask(BTM_GetProcessingThread(), WaitRxTaskCompleteTask, taskCompleteEvent);
260        EventWait(taskCompleteEvent, taskTimeout);
261        EventDelete(taskCompleteEvent);
262    }
263}
264
265NO_SANITIZE("cfi") void HCI_Close()
266{
267    LOG_DEBUG("%{public}s start", __FUNCTION__);
268
269    CleanTxPacket();
270
271    if (g_waitHdiInitAlarm != NULL) {
272        AlarmCancel(g_waitHdiInitAlarm);
273        AlarmDelete(g_waitHdiInitAlarm);
274        g_waitHdiInitAlarm = NULL;
275    }
276
277    if (g_hciTxReactorItem != NULL) {
278        ReactorUnregister(g_hciTxReactorItem);
279        g_hciTxReactorItem = NULL;
280    }
281
282    if (g_hciTxThread != NULL) {
283        ThreadDelete(g_hciTxThread);
284        g_hciTxThread = NULL;
285    }
286
287    if (g_hdiLib != NULL && g_hdiLib->hdiClose != NULL) {
288        g_hdiLib->hdiClose();
289    }
290
291    CleanRxPacket();
292
293    if (g_hciRxReactorItem != NULL) {
294        ReactorUnregister(g_hciRxReactorItem);
295        g_hciRxReactorItem = NULL;
296    }
297
298    WaitRxTaskComplete();
299
300    if (g_hciTxQueue != NULL) {
301        QueueDelete(g_hciTxQueue, HciFreePacket);
302        g_hciTxQueue = NULL;
303    }
304
305    if (g_hciRxQueue != NULL) {
306        QueueDelete(g_hciRxQueue, HciFreePacket);
307        g_hciRxQueue = NULL;
308    }
309
310    HciCloseCmd();
311    HciCloseEvent();
312    HciCloseAcl();
313    HciCloseFailure();
314    HciVendorClose();
315
316    if (g_hdiLib != NULL) {
317        UnloadHdiLib(g_hdiLib);
318        g_hdiLib = NULL;
319    }
320
321    LOG_DEBUG("%{public}s end", __FUNCTION__);
322}
323
324static void HciOnHDIInited(BtInitStatus status)
325{
326    if (g_waitHdiInitAlarm != NULL) {
327        AlarmCancel(g_waitHdiInitAlarm);
328        AlarmDelete(g_waitHdiInitAlarm);
329        g_waitHdiInitAlarm = NULL;
330    }
331    g_hdiInitStatus = status;
332    SemaphorePost(g_waitHdiInit);
333}
334
335static void HciOnReceivedHciPacket(BtPacketType type, const BtPacket *btPacket)
336{
337    if (g_transmissionCapture && g_transmissionCallback != NULL) {
338        uint8_t transType = (type == PACKET_TYPE_EVENT) ? TRANSMISSON_TYPE_C2H_EVENT : TRANSMISSON_TYPE_C2H_DATA;
339        g_transmissionCallback(transType, btPacket->data, btPacket->size);
340    }
341
342    HciPacket *hciPacket = MEM_MALLOC.alloc(sizeof(HciPacket));
343    if (hciPacket != NULL) {
344        switch (type) {
345            case PACKET_TYPE_ACL:
346                hciPacket->type = C2H_ACLDATA;
347                break;
348            case PACKET_TYPE_EVENT:
349                hciPacket->type = C2H_EVENT;
350                break;
351            default:
352                break;
353        }
354
355        hciPacket->packet = PacketMalloc(0, 0, btPacket->size);
356        PacketPayloadWrite(hciPacket->packet, btPacket->data, 0, btPacket->size);
357
358        QueueEnqueue(g_hciRxQueue, hciPacket);
359    }
360}
361
362NO_SANITIZE("cfi") static void HciSendPacketCallback(void *param)
363{
364    HciPacket *packet = QueueTryDequeue(g_hciTxQueue);
365    if (packet != NULL) {
366        BtPacket btPacket;
367        btPacket.size = PacketSize(packet->packet);
368        btPacket.data = MEM_MALLOC.alloc(btPacket.size);
369        PacketRead(packet->packet, btPacket.data, 0, btPacket.size);
370
371        int result;
372
373        if (g_hdiLib == NULL) {
374            LOG_ERROR("HDI is invalid.");
375            return;
376        }
377
378        switch (packet->type) {
379            case H2C_CMD:
380                result = g_hdiLib->hdiSendHciPacket(PACKET_TYPE_CMD, &btPacket);
381                break;
382            case H2C_ACLDATA:
383                result = g_hdiLib->hdiSendHciPacket(PACKET_TYPE_ACL, &btPacket);
384                break;
385            case H2C_SCODATA:
386                result = g_hdiLib->hdiSendHciPacket(PACKET_TYPE_SCO, &btPacket);
387                break;
388            default:
389                result = UNKNOWN;
390                break;
391        }
392
393        if (result != SUCCESS) {
394            LOG_ERROR("Send packet to HDI failed: %{public}d", result);
395        } else {
396            if (g_transmissionCapture && g_transmissionCallback != NULL) {
397                uint8_t type = (packet->type == H2C_CMD) ? TRANSMISSON_TYPE_H2C_CMD : TRANSMISSON_TYPE_H2C_DATA;
398                g_transmissionCallback(type, btPacket.data, btPacket.size);
399            }
400        }
401
402        MEM_MALLOC.free(btPacket.data);
403        HciFreePacket(packet);
404    }
405}
406
407static void HciRecvPacketCallback(void *param)
408{
409    HciPacket *packet = QueueTryDequeue(g_hciRxQueue);
410    if (packet != NULL) {
411        switch (packet->type) {
412            case C2H_ACLDATA:
413                HciOnAclData(packet->packet);
414                break;
415            case C2H_EVENT:
416                HciOnEvent(packet->packet);
417                break;
418            case C2H_SCODATA:
419                // NOT IMPLETEMENTED
420                break;
421            default:
422                break;
423        }
424        HciFreePacket(packet);
425    }
426}
427
428void HciPushToTxQueue(HciPacket *packet)
429{
430    QueueEnqueue(g_hciTxQueue, packet);
431}
432
433int HCI_SetTransmissionCaptureCallback(void (*onTransmission)(uint8_t type, const uint8_t *data, uint16_t length))
434{
435    g_transmissionCallback = onTransmission;
436    return BT_SUCCESS;
437}
438
439int HCI_EnableTransmissionCapture()
440{
441    g_transmissionCapture = true;
442    return BT_SUCCESS;
443}
444
445int HCI_DisableTransmissionCapture()
446{
447    g_transmissionCapture = false;
448    return BT_SUCCESS;
449}
450
451static BtHciCallbacks g_hdiCallacks = {
452    .OnInited = HciOnHDIInited,
453    .OnReceivedHciPacket = HciOnReceivedHciPacket,
454};
455