xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_hs_hci.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero #include <stdint.h>
20*042d53a7SEvalZero #include <string.h>
21*042d53a7SEvalZero #include <errno.h>
22*042d53a7SEvalZero #include <stdio.h>
23*042d53a7SEvalZero #include "os/os.h"
24*042d53a7SEvalZero #include "mem/mem.h"
25*042d53a7SEvalZero #include "nimble/ble_hci_trans.h"
26*042d53a7SEvalZero #include "host/ble_monitor.h"
27*042d53a7SEvalZero #include "ble_hs_priv.h"
28*042d53a7SEvalZero #include "ble_hs_dbg_priv.h"
29*042d53a7SEvalZero #include "ble_monitor_priv.h"
30*042d53a7SEvalZero 
31*042d53a7SEvalZero #define BLE_HCI_CMD_TIMEOUT_MS  2000
32*042d53a7SEvalZero 
33*042d53a7SEvalZero static struct ble_npl_mutex ble_hs_hci_mutex;
34*042d53a7SEvalZero static struct ble_npl_sem ble_hs_hci_sem;
35*042d53a7SEvalZero 
36*042d53a7SEvalZero static uint8_t *ble_hs_hci_ack;
37*042d53a7SEvalZero static uint16_t ble_hs_hci_buf_sz;
38*042d53a7SEvalZero static uint8_t ble_hs_hci_max_pkts;
39*042d53a7SEvalZero static uint32_t ble_hs_hci_sup_feat;
40*042d53a7SEvalZero static uint8_t ble_hs_hci_version;
41*042d53a7SEvalZero 
42*042d53a7SEvalZero /**
43*042d53a7SEvalZero  * The number of available ACL transmit buffers on the controller.  This
44*042d53a7SEvalZero  * variable must only be accessed while the host mutex is locked.
45*042d53a7SEvalZero  */
46*042d53a7SEvalZero uint16_t ble_hs_hci_avail_pkts;
47*042d53a7SEvalZero 
48*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_PHONY_HCI_ACKS)
49*042d53a7SEvalZero static ble_hs_hci_phony_ack_fn *ble_hs_hci_phony_ack_cb;
50*042d53a7SEvalZero #endif
51*042d53a7SEvalZero 
52*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_PHONY_HCI_ACKS)
53*042d53a7SEvalZero void
ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn * cb)54*042d53a7SEvalZero ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb)
55*042d53a7SEvalZero {
56*042d53a7SEvalZero     ble_hs_hci_phony_ack_cb = cb;
57*042d53a7SEvalZero }
58*042d53a7SEvalZero #endif
59*042d53a7SEvalZero 
60*042d53a7SEvalZero static void
ble_hs_hci_lock(void)61*042d53a7SEvalZero ble_hs_hci_lock(void)
62*042d53a7SEvalZero {
63*042d53a7SEvalZero     int rc;
64*042d53a7SEvalZero 
65*042d53a7SEvalZero     rc = ble_npl_mutex_pend(&ble_hs_hci_mutex, BLE_NPL_TIME_FOREVER);
66*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
67*042d53a7SEvalZero }
68*042d53a7SEvalZero 
69*042d53a7SEvalZero static void
ble_hs_hci_unlock(void)70*042d53a7SEvalZero ble_hs_hci_unlock(void)
71*042d53a7SEvalZero {
72*042d53a7SEvalZero     int rc;
73*042d53a7SEvalZero 
74*042d53a7SEvalZero     rc = ble_npl_mutex_release(&ble_hs_hci_mutex);
75*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
76*042d53a7SEvalZero }
77*042d53a7SEvalZero 
78*042d53a7SEvalZero int
ble_hs_hci_set_buf_sz(uint16_t pktlen,uint16_t max_pkts)79*042d53a7SEvalZero ble_hs_hci_set_buf_sz(uint16_t pktlen, uint16_t max_pkts)
80*042d53a7SEvalZero {
81*042d53a7SEvalZero     if (pktlen == 0 || max_pkts == 0) {
82*042d53a7SEvalZero         return BLE_HS_EINVAL;
83*042d53a7SEvalZero     }
84*042d53a7SEvalZero 
85*042d53a7SEvalZero     ble_hs_hci_buf_sz = pktlen;
86*042d53a7SEvalZero     ble_hs_hci_max_pkts = max_pkts;
87*042d53a7SEvalZero     ble_hs_hci_avail_pkts = max_pkts;
88*042d53a7SEvalZero 
89*042d53a7SEvalZero     return 0;
90*042d53a7SEvalZero }
91*042d53a7SEvalZero 
92*042d53a7SEvalZero /**
93*042d53a7SEvalZero  * Increases the count of available controller ACL buffers.
94*042d53a7SEvalZero  */
95*042d53a7SEvalZero void
ble_hs_hci_add_avail_pkts(uint16_t delta)96*042d53a7SEvalZero ble_hs_hci_add_avail_pkts(uint16_t delta)
97*042d53a7SEvalZero {
98*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
99*042d53a7SEvalZero 
100*042d53a7SEvalZero     if (ble_hs_hci_avail_pkts + delta > UINT16_MAX) {
101*042d53a7SEvalZero         ble_hs_sched_reset(BLE_HS_ECONTROLLER);
102*042d53a7SEvalZero     } else {
103*042d53a7SEvalZero         ble_hs_hci_avail_pkts += delta;
104*042d53a7SEvalZero     }
105*042d53a7SEvalZero }
106*042d53a7SEvalZero 
107*042d53a7SEvalZero static int
ble_hs_hci_rx_cmd_complete(uint8_t event_code,uint8_t * data,int len,struct ble_hs_hci_ack * out_ack)108*042d53a7SEvalZero ble_hs_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len,
109*042d53a7SEvalZero                            struct ble_hs_hci_ack *out_ack)
110*042d53a7SEvalZero {
111*042d53a7SEvalZero     uint16_t opcode;
112*042d53a7SEvalZero     uint8_t *params;
113*042d53a7SEvalZero     uint8_t params_len;
114*042d53a7SEvalZero     uint8_t num_pkts;
115*042d53a7SEvalZero 
116*042d53a7SEvalZero     if (len < BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN) {
117*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
118*042d53a7SEvalZero     }
119*042d53a7SEvalZero 
120*042d53a7SEvalZero     num_pkts = data[2];
121*042d53a7SEvalZero     opcode = get_le16(data + 3);
122*042d53a7SEvalZero     params = data + 5;
123*042d53a7SEvalZero 
124*042d53a7SEvalZero     /* XXX: Process num_pkts field. */
125*042d53a7SEvalZero     (void)num_pkts;
126*042d53a7SEvalZero 
127*042d53a7SEvalZero     out_ack->bha_opcode = opcode;
128*042d53a7SEvalZero 
129*042d53a7SEvalZero     params_len = len - BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN;
130*042d53a7SEvalZero     if (params_len > 0) {
131*042d53a7SEvalZero         out_ack->bha_status = BLE_HS_HCI_ERR(params[0]);
132*042d53a7SEvalZero     } else if (opcode == BLE_HCI_OPCODE_NOP) {
133*042d53a7SEvalZero         out_ack->bha_status = 0;
134*042d53a7SEvalZero     } else {
135*042d53a7SEvalZero         out_ack->bha_status = BLE_HS_ECONTROLLER;
136*042d53a7SEvalZero     }
137*042d53a7SEvalZero 
138*042d53a7SEvalZero     /* Don't include the status byte in the parameters blob. */
139*042d53a7SEvalZero     if (params_len > 1) {
140*042d53a7SEvalZero         out_ack->bha_params = params + 1;
141*042d53a7SEvalZero         out_ack->bha_params_len = params_len - 1;
142*042d53a7SEvalZero     } else {
143*042d53a7SEvalZero         out_ack->bha_params = NULL;
144*042d53a7SEvalZero         out_ack->bha_params_len = 0;
145*042d53a7SEvalZero     }
146*042d53a7SEvalZero 
147*042d53a7SEvalZero     return 0;
148*042d53a7SEvalZero }
149*042d53a7SEvalZero 
150*042d53a7SEvalZero static int
ble_hs_hci_rx_cmd_status(uint8_t event_code,uint8_t * data,int len,struct ble_hs_hci_ack * out_ack)151*042d53a7SEvalZero ble_hs_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len,
152*042d53a7SEvalZero                          struct ble_hs_hci_ack *out_ack)
153*042d53a7SEvalZero {
154*042d53a7SEvalZero     uint16_t opcode;
155*042d53a7SEvalZero     uint8_t num_pkts;
156*042d53a7SEvalZero     uint8_t status;
157*042d53a7SEvalZero 
158*042d53a7SEvalZero     if (len < BLE_HCI_EVENT_CMD_STATUS_LEN) {
159*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
160*042d53a7SEvalZero     }
161*042d53a7SEvalZero 
162*042d53a7SEvalZero     status = data[2];
163*042d53a7SEvalZero     num_pkts = data[3];
164*042d53a7SEvalZero     opcode = get_le16(data + 4);
165*042d53a7SEvalZero 
166*042d53a7SEvalZero     /* XXX: Process num_pkts field. */
167*042d53a7SEvalZero     (void)num_pkts;
168*042d53a7SEvalZero 
169*042d53a7SEvalZero     out_ack->bha_opcode = opcode;
170*042d53a7SEvalZero     out_ack->bha_params = NULL;
171*042d53a7SEvalZero     out_ack->bha_params_len = 0;
172*042d53a7SEvalZero     out_ack->bha_status = BLE_HS_HCI_ERR(status);
173*042d53a7SEvalZero 
174*042d53a7SEvalZero     return 0;
175*042d53a7SEvalZero }
176*042d53a7SEvalZero 
177*042d53a7SEvalZero static int
ble_hs_hci_process_ack(uint16_t expected_opcode,uint8_t * params_buf,uint8_t params_buf_len,struct ble_hs_hci_ack * out_ack)178*042d53a7SEvalZero ble_hs_hci_process_ack(uint16_t expected_opcode,
179*042d53a7SEvalZero                        uint8_t *params_buf, uint8_t params_buf_len,
180*042d53a7SEvalZero                        struct ble_hs_hci_ack *out_ack)
181*042d53a7SEvalZero {
182*042d53a7SEvalZero     uint8_t event_code;
183*042d53a7SEvalZero     uint8_t param_len;
184*042d53a7SEvalZero     uint8_t event_len;
185*042d53a7SEvalZero     int rc;
186*042d53a7SEvalZero 
187*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL);
188*042d53a7SEvalZero 
189*042d53a7SEvalZero     /* Count events received */
190*042d53a7SEvalZero     STATS_INC(ble_hs_stats, hci_event);
191*042d53a7SEvalZero 
192*042d53a7SEvalZero     /* Display to console */
193*042d53a7SEvalZero     ble_hs_dbg_event_disp(ble_hs_hci_ack);
194*042d53a7SEvalZero 
195*042d53a7SEvalZero     event_code = ble_hs_hci_ack[0];
196*042d53a7SEvalZero     param_len = ble_hs_hci_ack[1];
197*042d53a7SEvalZero     event_len = param_len + 2;
198*042d53a7SEvalZero 
199*042d53a7SEvalZero     /* Clear ack fields up front to silence spurious gcc warnings. */
200*042d53a7SEvalZero     memset(out_ack, 0, sizeof *out_ack);
201*042d53a7SEvalZero 
202*042d53a7SEvalZero     switch (event_code) {
203*042d53a7SEvalZero     case BLE_HCI_EVCODE_COMMAND_COMPLETE:
204*042d53a7SEvalZero         rc = ble_hs_hci_rx_cmd_complete(event_code, ble_hs_hci_ack,
205*042d53a7SEvalZero                                          event_len, out_ack);
206*042d53a7SEvalZero         break;
207*042d53a7SEvalZero 
208*042d53a7SEvalZero     case BLE_HCI_EVCODE_COMMAND_STATUS:
209*042d53a7SEvalZero         rc = ble_hs_hci_rx_cmd_status(event_code, ble_hs_hci_ack,
210*042d53a7SEvalZero                                        event_len, out_ack);
211*042d53a7SEvalZero         break;
212*042d53a7SEvalZero 
213*042d53a7SEvalZero     default:
214*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
215*042d53a7SEvalZero         rc = BLE_HS_EUNKNOWN;
216*042d53a7SEvalZero         break;
217*042d53a7SEvalZero     }
218*042d53a7SEvalZero 
219*042d53a7SEvalZero     if (rc == 0) {
220*042d53a7SEvalZero         if (params_buf == NULL) {
221*042d53a7SEvalZero             out_ack->bha_params_len = 0;
222*042d53a7SEvalZero         } else {
223*042d53a7SEvalZero             if (out_ack->bha_params_len > params_buf_len) {
224*042d53a7SEvalZero                 out_ack->bha_params_len = params_buf_len;
225*042d53a7SEvalZero                 rc = BLE_HS_ECONTROLLER;
226*042d53a7SEvalZero             }
227*042d53a7SEvalZero             memcpy(params_buf, out_ack->bha_params, out_ack->bha_params_len);
228*042d53a7SEvalZero         }
229*042d53a7SEvalZero         out_ack->bha_params = params_buf;
230*042d53a7SEvalZero 
231*042d53a7SEvalZero         if (out_ack->bha_opcode != expected_opcode) {
232*042d53a7SEvalZero             rc = BLE_HS_ECONTROLLER;
233*042d53a7SEvalZero         }
234*042d53a7SEvalZero     }
235*042d53a7SEvalZero 
236*042d53a7SEvalZero     if (rc != 0) {
237*042d53a7SEvalZero         STATS_INC(ble_hs_stats, hci_invalid_ack);
238*042d53a7SEvalZero     }
239*042d53a7SEvalZero 
240*042d53a7SEvalZero     return rc;
241*042d53a7SEvalZero }
242*042d53a7SEvalZero 
243*042d53a7SEvalZero static int
ble_hs_hci_wait_for_ack(void)244*042d53a7SEvalZero ble_hs_hci_wait_for_ack(void)
245*042d53a7SEvalZero {
246*042d53a7SEvalZero     int rc;
247*042d53a7SEvalZero 
248*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_PHONY_HCI_ACKS)
249*042d53a7SEvalZero     if (ble_hs_hci_phony_ack_cb == NULL) {
250*042d53a7SEvalZero         rc = BLE_HS_ETIMEOUT_HCI;
251*042d53a7SEvalZero     } else {
252*042d53a7SEvalZero         ble_hs_hci_ack =
253*042d53a7SEvalZero             ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
254*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL);
255*042d53a7SEvalZero         rc = ble_hs_hci_phony_ack_cb(ble_hs_hci_ack, 260);
256*042d53a7SEvalZero     }
257*042d53a7SEvalZero #else
258*042d53a7SEvalZero     rc = ble_npl_sem_pend(&ble_hs_hci_sem,
259*042d53a7SEvalZero                      ble_npl_time_ms_to_ticks32(BLE_HCI_CMD_TIMEOUT_MS));
260*042d53a7SEvalZero     switch (rc) {
261*042d53a7SEvalZero     case 0:
262*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL);
263*042d53a7SEvalZero 
264*042d53a7SEvalZero #if BLE_MONITOR
265*042d53a7SEvalZero         ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, ble_hs_hci_ack,
266*042d53a7SEvalZero                          ble_hs_hci_ack[1] + BLE_HCI_EVENT_HDR_LEN);
267*042d53a7SEvalZero #endif
268*042d53a7SEvalZero 
269*042d53a7SEvalZero         break;
270*042d53a7SEvalZero     case OS_TIMEOUT:
271*042d53a7SEvalZero         rc = BLE_HS_ETIMEOUT_HCI;
272*042d53a7SEvalZero         STATS_INC(ble_hs_stats, hci_timeout);
273*042d53a7SEvalZero         break;
274*042d53a7SEvalZero     default:
275*042d53a7SEvalZero         rc = BLE_HS_EOS;
276*042d53a7SEvalZero         break;
277*042d53a7SEvalZero     }
278*042d53a7SEvalZero #endif
279*042d53a7SEvalZero 
280*042d53a7SEvalZero     return rc;
281*042d53a7SEvalZero }
282*042d53a7SEvalZero 
283*042d53a7SEvalZero int
ble_hs_hci_cmd_tx(uint16_t opcode,void * cmd,uint8_t cmd_len,void * evt_buf,uint8_t evt_buf_len,uint8_t * out_evt_buf_len)284*042d53a7SEvalZero ble_hs_hci_cmd_tx(uint16_t opcode, void *cmd, uint8_t cmd_len,
285*042d53a7SEvalZero                   void *evt_buf, uint8_t evt_buf_len,
286*042d53a7SEvalZero                   uint8_t *out_evt_buf_len)
287*042d53a7SEvalZero {
288*042d53a7SEvalZero     struct ble_hs_hci_ack ack;
289*042d53a7SEvalZero     int rc;
290*042d53a7SEvalZero 
291*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL);
292*042d53a7SEvalZero     ble_hs_hci_lock();
293*042d53a7SEvalZero 
294*042d53a7SEvalZero     rc = ble_hs_hci_cmd_send_buf(opcode, cmd, cmd_len);
295*042d53a7SEvalZero     if (rc != 0) {
296*042d53a7SEvalZero         goto done;
297*042d53a7SEvalZero     }
298*042d53a7SEvalZero 
299*042d53a7SEvalZero     rc = ble_hs_hci_wait_for_ack();
300*042d53a7SEvalZero     if (rc != 0) {
301*042d53a7SEvalZero         ble_hs_sched_reset(rc);
302*042d53a7SEvalZero         goto done;
303*042d53a7SEvalZero     }
304*042d53a7SEvalZero 
305*042d53a7SEvalZero     rc = ble_hs_hci_process_ack(opcode, evt_buf, evt_buf_len, &ack);
306*042d53a7SEvalZero     if (rc != 0) {
307*042d53a7SEvalZero         ble_hs_sched_reset(rc);
308*042d53a7SEvalZero         goto done;
309*042d53a7SEvalZero     }
310*042d53a7SEvalZero 
311*042d53a7SEvalZero     if (out_evt_buf_len != NULL) {
312*042d53a7SEvalZero         *out_evt_buf_len = ack.bha_params_len;
313*042d53a7SEvalZero     }
314*042d53a7SEvalZero 
315*042d53a7SEvalZero     rc = ack.bha_status;
316*042d53a7SEvalZero 
317*042d53a7SEvalZero done:
318*042d53a7SEvalZero     if (ble_hs_hci_ack != NULL) {
319*042d53a7SEvalZero         ble_hci_trans_buf_free(ble_hs_hci_ack);
320*042d53a7SEvalZero         ble_hs_hci_ack = NULL;
321*042d53a7SEvalZero     }
322*042d53a7SEvalZero 
323*042d53a7SEvalZero     ble_hs_hci_unlock();
324*042d53a7SEvalZero     return rc;
325*042d53a7SEvalZero }
326*042d53a7SEvalZero 
327*042d53a7SEvalZero int
ble_hs_hci_cmd_tx_empty_ack(uint16_t opcode,void * cmd,uint8_t cmd_len)328*042d53a7SEvalZero ble_hs_hci_cmd_tx_empty_ack(uint16_t opcode, void *cmd, uint8_t cmd_len)
329*042d53a7SEvalZero {
330*042d53a7SEvalZero     int rc;
331*042d53a7SEvalZero 
332*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx(opcode, cmd, cmd_len, NULL, 0, NULL);
333*042d53a7SEvalZero     if (rc != 0) {
334*042d53a7SEvalZero         return rc;
335*042d53a7SEvalZero     }
336*042d53a7SEvalZero 
337*042d53a7SEvalZero     return 0;
338*042d53a7SEvalZero }
339*042d53a7SEvalZero 
340*042d53a7SEvalZero void
ble_hs_hci_rx_ack(uint8_t * ack_ev)341*042d53a7SEvalZero ble_hs_hci_rx_ack(uint8_t *ack_ev)
342*042d53a7SEvalZero {
343*042d53a7SEvalZero     if (ble_npl_sem_get_count(&ble_hs_hci_sem) > 0) {
344*042d53a7SEvalZero         /* This ack is unexpected; ignore it. */
345*042d53a7SEvalZero         ble_hci_trans_buf_free(ack_ev);
346*042d53a7SEvalZero         return;
347*042d53a7SEvalZero     }
348*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL);
349*042d53a7SEvalZero 
350*042d53a7SEvalZero     /* Unblock the application now that the HCI command buffer is populated
351*042d53a7SEvalZero      * with the acknowledgement.
352*042d53a7SEvalZero      */
353*042d53a7SEvalZero     ble_hs_hci_ack = ack_ev;
354*042d53a7SEvalZero     ble_npl_sem_release(&ble_hs_hci_sem);
355*042d53a7SEvalZero }
356*042d53a7SEvalZero 
357*042d53a7SEvalZero int
ble_hs_hci_rx_evt(uint8_t * hci_ev,void * arg)358*042d53a7SEvalZero ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg)
359*042d53a7SEvalZero {
360*042d53a7SEvalZero     int enqueue;
361*042d53a7SEvalZero 
362*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(hci_ev != NULL);
363*042d53a7SEvalZero 
364*042d53a7SEvalZero     switch (hci_ev[0]) {
365*042d53a7SEvalZero     case BLE_HCI_EVCODE_COMMAND_COMPLETE:
366*042d53a7SEvalZero     case BLE_HCI_EVCODE_COMMAND_STATUS:
367*042d53a7SEvalZero         if (hci_ev[3] == 0 && hci_ev[4] == 0) {
368*042d53a7SEvalZero             enqueue = 1;
369*042d53a7SEvalZero         } else {
370*042d53a7SEvalZero             ble_hs_hci_rx_ack(hci_ev);
371*042d53a7SEvalZero             enqueue = 0;
372*042d53a7SEvalZero         }
373*042d53a7SEvalZero         break;
374*042d53a7SEvalZero 
375*042d53a7SEvalZero     default:
376*042d53a7SEvalZero         enqueue = 1;
377*042d53a7SEvalZero         break;
378*042d53a7SEvalZero     }
379*042d53a7SEvalZero 
380*042d53a7SEvalZero     if (enqueue) {
381*042d53a7SEvalZero         ble_hs_enqueue_hci_event(hci_ev);
382*042d53a7SEvalZero     }
383*042d53a7SEvalZero 
384*042d53a7SEvalZero     return 0;
385*042d53a7SEvalZero }
386*042d53a7SEvalZero 
387*042d53a7SEvalZero /**
388*042d53a7SEvalZero  * Calculates the largest ACL payload that the controller can accept.  This is
389*042d53a7SEvalZero  * everything in an ACL data packet except for the ACL header.
390*042d53a7SEvalZero  */
391*042d53a7SEvalZero static uint16_t
ble_hs_hci_max_acl_payload_sz(void)392*042d53a7SEvalZero ble_hs_hci_max_acl_payload_sz(void)
393*042d53a7SEvalZero {
394*042d53a7SEvalZero     return ble_hs_hci_buf_sz - BLE_HCI_DATA_HDR_SZ;
395*042d53a7SEvalZero }
396*042d53a7SEvalZero 
397*042d53a7SEvalZero /**
398*042d53a7SEvalZero  * Allocates an mbuf to contain an outgoing ACL data fragment.
399*042d53a7SEvalZero  */
400*042d53a7SEvalZero static struct os_mbuf *
ble_hs_hci_frag_alloc(uint16_t frag_size,void * arg)401*042d53a7SEvalZero ble_hs_hci_frag_alloc(uint16_t frag_size, void *arg)
402*042d53a7SEvalZero {
403*042d53a7SEvalZero     return ble_hs_mbuf_acl_pkt();
404*042d53a7SEvalZero }
405*042d53a7SEvalZero 
406*042d53a7SEvalZero static struct os_mbuf *
ble_hs_hci_acl_hdr_prepend(struct os_mbuf * om,uint16_t handle,uint8_t pb_flag)407*042d53a7SEvalZero ble_hs_hci_acl_hdr_prepend(struct os_mbuf *om, uint16_t handle,
408*042d53a7SEvalZero                            uint8_t pb_flag)
409*042d53a7SEvalZero {
410*042d53a7SEvalZero     struct hci_data_hdr hci_hdr;
411*042d53a7SEvalZero     struct os_mbuf *om2;
412*042d53a7SEvalZero 
413*042d53a7SEvalZero     hci_hdr.hdh_handle_pb_bc =
414*042d53a7SEvalZero         ble_hs_hci_util_handle_pb_bc_join(handle, pb_flag, 0);
415*042d53a7SEvalZero     put_le16(&hci_hdr.hdh_len, OS_MBUF_PKTHDR(om)->omp_len);
416*042d53a7SEvalZero 
417*042d53a7SEvalZero     om2 = os_mbuf_prepend(om, sizeof hci_hdr);
418*042d53a7SEvalZero     if (om2 == NULL) {
419*042d53a7SEvalZero         return NULL;
420*042d53a7SEvalZero     }
421*042d53a7SEvalZero 
422*042d53a7SEvalZero     om = om2;
423*042d53a7SEvalZero     om = os_mbuf_pullup(om, sizeof hci_hdr);
424*042d53a7SEvalZero     if (om == NULL) {
425*042d53a7SEvalZero         return NULL;
426*042d53a7SEvalZero     }
427*042d53a7SEvalZero 
428*042d53a7SEvalZero     memcpy(om->om_data, &hci_hdr, sizeof hci_hdr);
429*042d53a7SEvalZero 
430*042d53a7SEvalZero #if !BLE_MONITOR
431*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "host tx hci data; handle=%d length=%d\n", handle,
432*042d53a7SEvalZero                get_le16(&hci_hdr.hdh_len));
433*042d53a7SEvalZero #endif
434*042d53a7SEvalZero 
435*042d53a7SEvalZero     return om;
436*042d53a7SEvalZero }
437*042d53a7SEvalZero 
438*042d53a7SEvalZero int
ble_hs_hci_acl_tx_now(struct ble_hs_conn * conn,struct os_mbuf ** om)439*042d53a7SEvalZero ble_hs_hci_acl_tx_now(struct ble_hs_conn *conn, struct os_mbuf **om)
440*042d53a7SEvalZero {
441*042d53a7SEvalZero     struct os_mbuf *txom;
442*042d53a7SEvalZero     struct os_mbuf *frag;
443*042d53a7SEvalZero     uint8_t pb;
444*042d53a7SEvalZero     int rc;
445*042d53a7SEvalZero 
446*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
447*042d53a7SEvalZero 
448*042d53a7SEvalZero     txom = *om;
449*042d53a7SEvalZero     *om = NULL;
450*042d53a7SEvalZero 
451*042d53a7SEvalZero     if (!(conn->bhc_flags & BLE_HS_CONN_F_TX_FRAG)) {
452*042d53a7SEvalZero         /* The first fragment uses the first-non-flush packet boundary value.
453*042d53a7SEvalZero          * After sending the first fragment, pb gets set appropriately for all
454*042d53a7SEvalZero          * subsequent fragments in this packet.
455*042d53a7SEvalZero          */
456*042d53a7SEvalZero         pb = BLE_HCI_PB_FIRST_NON_FLUSH;
457*042d53a7SEvalZero     } else {
458*042d53a7SEvalZero         pb = BLE_HCI_PB_MIDDLE;
459*042d53a7SEvalZero     }
460*042d53a7SEvalZero 
461*042d53a7SEvalZero     /* Send fragments until the entire packet has been sent. */
462*042d53a7SEvalZero     while (txom != NULL && ble_hs_hci_avail_pkts > 0) {
463*042d53a7SEvalZero         frag = mem_split_frag(&txom, ble_hs_hci_max_acl_payload_sz(),
464*042d53a7SEvalZero                               ble_hs_hci_frag_alloc, NULL);
465*042d53a7SEvalZero 
466*042d53a7SEvalZero         frag = ble_hs_hci_acl_hdr_prepend(frag, conn->bhc_handle, pb);
467*042d53a7SEvalZero         if (frag == NULL) {
468*042d53a7SEvalZero             rc = BLE_HS_ENOMEM;
469*042d53a7SEvalZero             goto err;
470*042d53a7SEvalZero         }
471*042d53a7SEvalZero 
472*042d53a7SEvalZero #if !BLE_MONITOR
473*042d53a7SEvalZero         BLE_HS_LOG(DEBUG, "ble_hs_hci_acl_tx(): ");
474*042d53a7SEvalZero         ble_hs_log_mbuf(frag);
475*042d53a7SEvalZero         BLE_HS_LOG(DEBUG, "\n");
476*042d53a7SEvalZero #endif
477*042d53a7SEvalZero 
478*042d53a7SEvalZero         rc = ble_hs_tx_data(frag);
479*042d53a7SEvalZero         if (rc != 0) {
480*042d53a7SEvalZero             goto err;
481*042d53a7SEvalZero         }
482*042d53a7SEvalZero 
483*042d53a7SEvalZero         /* If any fragments remain, they should be marked as 'middle'
484*042d53a7SEvalZero          * fragments.
485*042d53a7SEvalZero          */
486*042d53a7SEvalZero         conn->bhc_flags |= BLE_HS_CONN_F_TX_FRAG;
487*042d53a7SEvalZero         pb = BLE_HCI_PB_MIDDLE;
488*042d53a7SEvalZero 
489*042d53a7SEvalZero         /* Account for the controller buf that will hold the txed fragment. */
490*042d53a7SEvalZero         conn->bhc_outstanding_pkts++;
491*042d53a7SEvalZero         ble_hs_hci_avail_pkts--;
492*042d53a7SEvalZero     }
493*042d53a7SEvalZero 
494*042d53a7SEvalZero     if (txom != NULL) {
495*042d53a7SEvalZero         /* The controller couldn't accommodate some or all of the packet. */
496*042d53a7SEvalZero         *om = txom;
497*042d53a7SEvalZero         return BLE_HS_EAGAIN;
498*042d53a7SEvalZero     }
499*042d53a7SEvalZero 
500*042d53a7SEvalZero     /* The entire packet was transmitted. */
501*042d53a7SEvalZero     conn->bhc_flags &= ~BLE_HS_CONN_F_TX_FRAG;
502*042d53a7SEvalZero 
503*042d53a7SEvalZero     return 0;
504*042d53a7SEvalZero 
505*042d53a7SEvalZero err:
506*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(rc != 0);
507*042d53a7SEvalZero 
508*042d53a7SEvalZero     conn->bhc_flags &= ~BLE_HS_CONN_F_TX_FRAG;
509*042d53a7SEvalZero     os_mbuf_free_chain(txom);
510*042d53a7SEvalZero     return rc;
511*042d53a7SEvalZero }
512*042d53a7SEvalZero 
513*042d53a7SEvalZero /**
514*042d53a7SEvalZero  * Transmits an HCI ACL data packet.  This function consumes the supplied mbuf,
515*042d53a7SEvalZero  * regardless of the outcome.
516*042d53a7SEvalZero  *
517*042d53a7SEvalZero  * @return                      0 on success;
518*042d53a7SEvalZero  *                              BLE_HS_EAGAIN if the packet could not be sent
519*042d53a7SEvalZero  *                                  in its entirety due to controller buffer
520*042d53a7SEvalZero  *                                  exhaustion.  The unsent data is pointed to
521*042d53a7SEvalZero  *                                  by the `om` parameter.
522*042d53a7SEvalZero  *                              A BLE host core return code on unexpected
523*042d53a7SEvalZero  *                                  error.
524*042d53a7SEvalZero  *
525*042d53a7SEvalZero  */
526*042d53a7SEvalZero int
ble_hs_hci_acl_tx(struct ble_hs_conn * conn,struct os_mbuf ** om)527*042d53a7SEvalZero ble_hs_hci_acl_tx(struct ble_hs_conn *conn, struct os_mbuf **om)
528*042d53a7SEvalZero {
529*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
530*042d53a7SEvalZero 
531*042d53a7SEvalZero     /* If this conn is already backed up, don't even try to send. */
532*042d53a7SEvalZero     if (STAILQ_FIRST(&conn->bhc_tx_q) != NULL) {
533*042d53a7SEvalZero         return BLE_HS_EAGAIN;
534*042d53a7SEvalZero     }
535*042d53a7SEvalZero 
536*042d53a7SEvalZero     return ble_hs_hci_acl_tx_now(conn, om);
537*042d53a7SEvalZero }
538*042d53a7SEvalZero 
539*042d53a7SEvalZero void
ble_hs_hci_set_le_supported_feat(uint32_t feat)540*042d53a7SEvalZero ble_hs_hci_set_le_supported_feat(uint32_t feat)
541*042d53a7SEvalZero {
542*042d53a7SEvalZero     ble_hs_hci_sup_feat = feat;
543*042d53a7SEvalZero }
544*042d53a7SEvalZero 
545*042d53a7SEvalZero uint32_t
ble_hs_hci_get_le_supported_feat(void)546*042d53a7SEvalZero ble_hs_hci_get_le_supported_feat(void)
547*042d53a7SEvalZero {
548*042d53a7SEvalZero     return ble_hs_hci_sup_feat;
549*042d53a7SEvalZero }
550*042d53a7SEvalZero 
551*042d53a7SEvalZero void
ble_hs_hci_set_hci_version(uint8_t hci_version)552*042d53a7SEvalZero ble_hs_hci_set_hci_version(uint8_t hci_version)
553*042d53a7SEvalZero {
554*042d53a7SEvalZero     ble_hs_hci_version = hci_version;
555*042d53a7SEvalZero }
556*042d53a7SEvalZero 
557*042d53a7SEvalZero uint8_t
ble_hs_hci_get_hci_version(void)558*042d53a7SEvalZero ble_hs_hci_get_hci_version(void)
559*042d53a7SEvalZero {
560*042d53a7SEvalZero     return ble_hs_hci_version;
561*042d53a7SEvalZero }
562*042d53a7SEvalZero 
563*042d53a7SEvalZero void
ble_hs_hci_init(void)564*042d53a7SEvalZero ble_hs_hci_init(void)
565*042d53a7SEvalZero {
566*042d53a7SEvalZero     int rc;
567*042d53a7SEvalZero 
568*042d53a7SEvalZero     rc = ble_npl_sem_init(&ble_hs_hci_sem, 0);
569*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
570*042d53a7SEvalZero 
571*042d53a7SEvalZero     rc = ble_npl_mutex_init(&ble_hs_hci_mutex);
572*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
573*042d53a7SEvalZero }
574