xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_hs.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <assert.h>
21 #include <errno.h>
22 #include <string.h>
23 #include "sysinit/sysinit.h"
24 #include "syscfg/syscfg.h"
25 #include "stats/stats.h"
26 #include "nimble/ble_hci_trans.h"
27 #include "ble_hs_priv.h"
28 #include "ble_monitor_priv.h"
29 #include "nimble/nimble_npl.h"
30 #ifndef MYNEWT
31 #include "nimble/nimble_port.h"
32 #endif
33 
34 #define BLE_HS_HCI_EVT_COUNT                    \
35     (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) +     \
36      MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT))
37 
38 static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev);
39 static void ble_hs_event_tx_notify(struct ble_npl_event *ev);
40 static void ble_hs_event_reset(struct ble_npl_event *ev);
41 static void ble_hs_event_start_stage1(struct ble_npl_event *ev);
42 static void ble_hs_event_start_stage2(struct ble_npl_event *ev);
43 static void ble_hs_timer_sched(int32_t ticks_from_now);
44 
45 struct os_mempool ble_hs_hci_ev_pool;
46 static os_membuf_t ble_hs_hci_os_event_buf[
47     OS_MEMPOOL_SIZE(BLE_HS_HCI_EVT_COUNT, sizeof (struct ble_npl_event))
48 ];
49 
50 /** OS event - triggers tx of pending notifications and indications. */
51 static struct ble_npl_event ble_hs_ev_tx_notifications;
52 
53 /** OS event - triggers a full reset. */
54 static struct ble_npl_event ble_hs_ev_reset;
55 
56 static struct ble_npl_event ble_hs_ev_start_stage1;
57 static struct ble_npl_event ble_hs_ev_start_stage2;
58 
59 uint8_t ble_hs_sync_state;
60 uint8_t ble_hs_enabled_state;
61 static int ble_hs_reset_reason;
62 
63 #define BLE_HS_SYNC_RETRY_TIMEOUT_MS    100 /* ms */
64 
65 static void *ble_hs_parent_task;
66 
67 /**
68  * Handles unresponsive timeouts and periodic retries in case of resource
69  * shortage.
70  */
71 static struct ble_npl_callout ble_hs_timer;
72 
73 /* Shared queue that the host uses for work items. */
74 static struct ble_npl_eventq *ble_hs_evq;
75 
76 static struct ble_mqueue ble_hs_rx_q;
77 
78 static struct ble_npl_mutex ble_hs_mutex;
79 
80 /** These values keep track of required ATT and GATT resources counts.  They
81  * increase as services are added, and are read when the ATT server and GATT
82  * server are started.
83  */
84 uint16_t ble_hs_max_attrs;
85 uint16_t ble_hs_max_services;
86 uint16_t ble_hs_max_client_configs;
87 
88 #if MYNEWT_VAL(BLE_HS_DEBUG)
89 static uint8_t ble_hs_dbg_mutex_locked;
90 #endif
91 
92 STATS_SECT_DECL(ble_hs_stats) ble_hs_stats;
93 STATS_NAME_START(ble_hs_stats)
STATS_NAME(ble_hs_stats,conn_create)94     STATS_NAME(ble_hs_stats, conn_create)
95     STATS_NAME(ble_hs_stats, conn_delete)
96     STATS_NAME(ble_hs_stats, hci_cmd)
97     STATS_NAME(ble_hs_stats, hci_event)
98     STATS_NAME(ble_hs_stats, hci_invalid_ack)
99     STATS_NAME(ble_hs_stats, hci_unknown_event)
100     STATS_NAME(ble_hs_stats, hci_timeout)
101     STATS_NAME(ble_hs_stats, reset)
102     STATS_NAME(ble_hs_stats, sync)
103     STATS_NAME(ble_hs_stats, pvcy_add_entry)
104     STATS_NAME(ble_hs_stats, pvcy_add_entry_fail)
105 STATS_NAME_END(ble_hs_stats)
106 
107 struct ble_npl_eventq *
108 ble_hs_evq_get(void)
109 {
110     return ble_hs_evq;
111 }
112 
113 void
ble_hs_evq_set(struct ble_npl_eventq * evq)114 ble_hs_evq_set(struct ble_npl_eventq *evq)
115 {
116     ble_hs_evq = evq;
117 }
118 
119 #if MYNEWT_VAL(BLE_HS_DEBUG)
120 int
ble_hs_locked_by_cur_task(void)121 ble_hs_locked_by_cur_task(void)
122 {
123 #if MYNEWT
124     struct os_task *owner;
125 
126     if (!ble_npl_os_started()) {
127         return ble_hs_dbg_mutex_locked;
128     }
129 
130     owner = ble_hs_mutex.mu.mu_owner;
131     return owner != NULL && owner == os_sched_get_current_task();
132 #else
133     return 1;
134 #endif
135 }
136 #endif
137 
138 /**
139  * Indicates whether the host's parent task is currently running.
140  */
141 int
ble_hs_is_parent_task(void)142 ble_hs_is_parent_task(void)
143 {
144     return !ble_npl_os_started() ||
145            ble_npl_get_current_task_id() == ble_hs_parent_task;
146 }
147 
148 /**
149  * Locks the BLE host mutex.  Nested locks allowed.
150  */
151 void
ble_hs_lock_nested(void)152 ble_hs_lock_nested(void)
153 {
154     int rc;
155 
156 #if MYNEWT_VAL(BLE_HS_DEBUG)
157     if (!ble_npl_os_started()) {
158         ble_hs_dbg_mutex_locked = 1;
159         return;
160     }
161 #endif
162 
163     rc = ble_npl_mutex_pend(&ble_hs_mutex, 0xffffffff);
164     BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
165 }
166 
167 /**
168  * Unlocks the BLE host mutex.  Nested locks allowed.
169  */
170 void
ble_hs_unlock_nested(void)171 ble_hs_unlock_nested(void)
172 {
173     int rc;
174 
175 #if MYNEWT_VAL(BLE_HS_DEBUG)
176     if (!ble_npl_os_started()) {
177         ble_hs_dbg_mutex_locked = 0;
178         return;
179     }
180 #endif
181 
182     rc = ble_npl_mutex_release(&ble_hs_mutex);
183     BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
184 }
185 
186 /**
187  * Locks the BLE host mutex.  Nested locks not allowed.
188  */
189 void
ble_hs_lock(void)190 ble_hs_lock(void)
191 {
192     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
193 #if MYNEWT_VAL(BLE_HS_DEBUG)
194     if (!ble_npl_os_started()) {
195         BLE_HS_DBG_ASSERT(!ble_hs_dbg_mutex_locked);
196     }
197 #endif
198 
199     ble_hs_lock_nested();
200 }
201 
202 /**
203  * Unlocks the BLE host mutex.  Nested locks not allowed.
204  */
205 void
ble_hs_unlock(void)206 ble_hs_unlock(void)
207 {
208 #if MYNEWT_VAL(BLE_HS_DEBUG)
209     if (!ble_npl_os_started()) {
210         BLE_HS_DBG_ASSERT(ble_hs_dbg_mutex_locked);
211     }
212 #endif
213 
214     ble_hs_unlock_nested();
215 }
216 
217 void
ble_hs_process_rx_data_queue(void)218 ble_hs_process_rx_data_queue(void)
219 {
220     struct os_mbuf *om;
221 
222     while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) {
223 #if BLE_MONITOR
224         ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_RX_PKT, om);
225 #endif
226 
227         ble_hs_hci_evt_acl_process(om);
228     }
229 }
230 
231 static int
ble_hs_wakeup_tx_conn(struct ble_hs_conn * conn)232 ble_hs_wakeup_tx_conn(struct ble_hs_conn *conn)
233 {
234     struct os_mbuf_pkthdr *omp;
235     struct os_mbuf *om;
236     int rc;
237 
238     while ((omp = STAILQ_FIRST(&conn->bhc_tx_q)) != NULL) {
239         STAILQ_REMOVE_HEAD(&conn->bhc_tx_q, omp_next);
240 
241         om = OS_MBUF_PKTHDR_TO_MBUF(omp);
242         rc = ble_hs_hci_acl_tx_now(conn, &om);
243         if (rc == BLE_HS_EAGAIN) {
244             /* Controller is at capacity.  This packet will be the first to
245              * get transmitted next time around.
246              */
247             STAILQ_INSERT_HEAD(&conn->bhc_tx_q, OS_MBUF_PKTHDR(om), omp_next);
248             return BLE_HS_EAGAIN;
249         }
250     }
251 
252     return 0;
253 }
254 
255 /**
256  * Schedules the transmission of all queued ACL data packets to the controller.
257  */
258 void
ble_hs_wakeup_tx(void)259 ble_hs_wakeup_tx(void)
260 {
261     struct ble_hs_conn *conn;
262     int rc;
263 
264     ble_hs_lock();
265 
266     /* If there is a connection with a partially transmitted packet, it has to
267      * be serviced first.  The controller is waiting for the remainder so it
268      * can reassemble it.
269      */
270     for (conn = ble_hs_conn_first();
271          conn != NULL;
272          conn = SLIST_NEXT(conn, bhc_next)) {
273 
274         if (conn->bhc_flags & BLE_HS_CONN_F_TX_FRAG) {
275             rc = ble_hs_wakeup_tx_conn(conn);
276             if (rc != 0) {
277                 goto done;
278             }
279             break;
280         }
281     }
282 
283     /* For each connection, transmit queued packets until there are no more
284      * packets to send or the controller's buffers are exhausted.
285      */
286     for (conn = ble_hs_conn_first();
287          conn != NULL;
288          conn = SLIST_NEXT(conn, bhc_next)) {
289 
290         rc = ble_hs_wakeup_tx_conn(conn);
291         if (rc != 0) {
292             goto done;
293         }
294     }
295 
296 done:
297     ble_hs_unlock();
298 }
299 
300 static void
ble_hs_clear_rx_queue(void)301 ble_hs_clear_rx_queue(void)
302 {
303     struct os_mbuf *om;
304 
305     while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) {
306         os_mbuf_free_chain(om);
307     }
308 }
309 
310 int
ble_hs_is_enabled(void)311 ble_hs_is_enabled(void)
312 {
313     return ble_hs_enabled_state == BLE_HS_ENABLED_STATE_ON;
314 }
315 
316 int
ble_hs_synced(void)317 ble_hs_synced(void)
318 {
319     return ble_hs_sync_state == BLE_HS_SYNC_STATE_GOOD;
320 }
321 
322 static int
ble_hs_sync(void)323 ble_hs_sync(void)
324 {
325     ble_npl_time_t retry_tmo_ticks;
326     int rc;
327 
328     /* Set the sync state to "bringup."  This allows the parent task to send
329      * the startup sequence to the controller.  No other tasks are allowed to
330      * send any commands.
331      */
332     ble_hs_sync_state = BLE_HS_SYNC_STATE_BRINGUP;
333 
334     rc = ble_hs_startup_go();
335     if (rc == 0) {
336         ble_hs_sync_state = BLE_HS_SYNC_STATE_GOOD;
337     } else {
338         ble_hs_sync_state = BLE_HS_SYNC_STATE_BAD;
339     }
340 
341     retry_tmo_ticks = ble_npl_time_ms_to_ticks32(BLE_HS_SYNC_RETRY_TIMEOUT_MS);
342     ble_hs_timer_sched(retry_tmo_ticks);
343 
344     if (rc == 0) {
345         rc = ble_hs_misc_restore_irks();
346         if (rc != 0) {
347             BLE_HS_LOG(INFO, "Failed to restore IRKs from store; status=%d",
348                        rc);
349         }
350 
351         if (ble_hs_cfg.sync_cb != NULL) {
352             ble_hs_cfg.sync_cb();
353         }
354 
355         STATS_INC(ble_hs_stats, sync);
356     }
357 
358     return rc;
359 }
360 
361 static int
ble_hs_reset(void)362 ble_hs_reset(void)
363 {
364     uint16_t conn_handle;
365     int rc;
366 
367     STATS_INC(ble_hs_stats, reset);
368 
369     ble_hs_sync_state = 0;
370 
371     /* Reset transport.  Assume success; there is nothing we can do in case of
372      * failure.  If the transport failed to reset, the host will reset itself
373      * again when it fails to sync with the controller.
374      */
375     (void)ble_hci_trans_reset();
376 
377     ble_hs_clear_rx_queue();
378 
379     while (1) {
380         conn_handle = ble_hs_atomic_first_conn_handle();
381         if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
382             break;
383         }
384 
385         ble_gap_conn_broken(conn_handle, ble_hs_reset_reason);
386     }
387 
388     /* Clear configured addresses. */
389     ble_hs_id_reset();
390 
391     if (ble_hs_cfg.reset_cb != NULL && ble_hs_reset_reason != 0) {
392         ble_hs_cfg.reset_cb(ble_hs_reset_reason);
393     }
394     ble_hs_reset_reason = 0;
395 
396     rc = ble_hs_sync();
397     return rc;
398 }
399 
400 /**
401  * Called when the host timer expires.  Handles unresponsive timeouts and
402  * periodic retries in case of resource shortage.
403  */
404 static void
ble_hs_timer_exp(struct ble_npl_event * ev)405 ble_hs_timer_exp(struct ble_npl_event *ev)
406 {
407     int32_t ticks_until_next;
408 
409     switch (ble_hs_sync_state) {
410     case BLE_HS_SYNC_STATE_GOOD:
411         ticks_until_next = ble_gattc_timer();
412         ble_hs_timer_sched(ticks_until_next);
413 
414         ticks_until_next = ble_gap_timer();
415         ble_hs_timer_sched(ticks_until_next);
416 
417         ticks_until_next = ble_l2cap_sig_timer();
418         ble_hs_timer_sched(ticks_until_next);
419 
420         ticks_until_next = ble_sm_timer();
421         ble_hs_timer_sched(ticks_until_next);
422 
423         ticks_until_next = ble_hs_conn_timer();
424         ble_hs_timer_sched(ticks_until_next);
425         break;
426 
427     case BLE_HS_SYNC_STATE_BAD:
428         ble_hs_reset();
429         break;
430 
431     case BLE_HS_SYNC_STATE_BRINGUP:
432     default:
433         /* The timer should not be set in this state. */
434         assert(0);
435         break;
436     }
437 
438 }
439 
440 static void
ble_hs_timer_reset(uint32_t ticks)441 ble_hs_timer_reset(uint32_t ticks)
442 {
443     int rc;
444 
445     if (!ble_hs_is_enabled()) {
446         ble_npl_callout_stop(&ble_hs_timer);
447     } else {
448         rc = ble_npl_callout_reset(&ble_hs_timer, ticks);
449         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
450     }
451 }
452 
453 static void
ble_hs_timer_sched(int32_t ticks_from_now)454 ble_hs_timer_sched(int32_t ticks_from_now)
455 {
456     ble_npl_time_t abs_time;
457 
458     if (ticks_from_now == BLE_HS_FOREVER) {
459         return;
460     }
461 
462     /* Reset timer if it is not currently scheduled or if the specified time is
463      * sooner than the previous expiration time.
464      */
465     abs_time = ble_npl_time_get() + ticks_from_now;
466     if (!ble_npl_callout_is_active(&ble_hs_timer) ||
467             ((ble_npl_stime_t)(abs_time -
468                                ble_npl_callout_get_ticks(&ble_hs_timer))) < 0) {
469         ble_hs_timer_reset(ticks_from_now);
470     }
471 }
472 
473 void
ble_hs_timer_resched(void)474 ble_hs_timer_resched(void)
475 {
476     /* Reschedule the timer to run immediately.  The timer callback will query
477      * each module for an up-to-date expiration time.
478      */
479     ble_hs_timer_reset(0);
480 }
481 
482 static void
ble_hs_sched_start_stage2(void)483 ble_hs_sched_start_stage2(void)
484 {
485     ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(),
486                        &ble_hs_ev_start_stage2);
487 }
488 
489 void
ble_hs_sched_start(void)490 ble_hs_sched_start(void)
491 {
492 #ifdef MYNEWT
493     ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(),
494                        &ble_hs_ev_start_stage1);
495 #else
496     ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1);
497 #endif
498 }
499 
500 static void
ble_hs_event_rx_hci_ev(struct ble_npl_event * ev)501 ble_hs_event_rx_hci_ev(struct ble_npl_event *ev)
502 {
503     uint8_t *hci_evt;
504     int rc;
505 
506     hci_evt = ble_npl_event_get_arg(ev);
507 
508     rc = os_memblock_put(&ble_hs_hci_ev_pool, ev);
509     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
510 
511 #if BLE_MONITOR
512     ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, hci_evt,
513                      hci_evt[1] + BLE_HCI_EVENT_HDR_LEN);
514 #endif
515 
516     ble_hs_hci_evt_process(hci_evt);
517 }
518 
519 static void
ble_hs_event_tx_notify(struct ble_npl_event * ev)520 ble_hs_event_tx_notify(struct ble_npl_event *ev)
521 {
522     ble_gatts_tx_notifications();
523 }
524 
525 static void
ble_hs_event_rx_data(struct ble_npl_event * ev)526 ble_hs_event_rx_data(struct ble_npl_event *ev)
527 {
528     ble_hs_process_rx_data_queue();
529 }
530 
531 static void
ble_hs_event_reset(struct ble_npl_event * ev)532 ble_hs_event_reset(struct ble_npl_event *ev)
533 {
534     ble_hs_reset();
535 }
536 
537 /**
538  * Implements the first half of the start process.  This just enqueues another
539  * event on the host parent task's event queue.
540  *
541  * Starting is done in two stages to allow the application time to configure
542  * the event queue to use after system initialization but before the host
543  * starts.
544  */
545 static void
ble_hs_event_start_stage1(struct ble_npl_event * ev)546 ble_hs_event_start_stage1(struct ble_npl_event *ev)
547 {
548     ble_hs_sched_start_stage2();
549 }
550 
551 /**
552  * Implements the second half of the start process.  This actually starts the
553  * host.
554  *
555  * Starting is done in two stages to allow the application time to configure
556  * the event queue to use after system initialization but before the host
557  * starts.
558  */
559 static void
ble_hs_event_start_stage2(struct ble_npl_event * ev)560 ble_hs_event_start_stage2(struct ble_npl_event *ev)
561 {
562     int rc;
563 
564     rc = ble_hs_start();
565     assert(rc == 0);
566 }
567 
568 void
ble_hs_enqueue_hci_event(uint8_t * hci_evt)569 ble_hs_enqueue_hci_event(uint8_t *hci_evt)
570 {
571     struct ble_npl_event *ev;
572 
573     ev = os_memblock_get(&ble_hs_hci_ev_pool);
574     if (ev == NULL) {
575         ble_hci_trans_buf_free(hci_evt);
576     } else {
577         ble_npl_event_init(ev, ble_hs_event_rx_hci_ev, hci_evt);
578         ble_npl_eventq_put(ble_hs_evq, ev);
579     }
580 }
581 
582 /**
583  * Schedules for all pending notifications and indications to be sent in the
584  * host parent task.
585  */
586 void
ble_hs_notifications_sched(void)587 ble_hs_notifications_sched(void)
588 {
589 #if !MYNEWT_VAL(BLE_HS_REQUIRE_OS)
590     if (!ble_npl_os_started()) {
591         ble_gatts_tx_notifications();
592         return;
593     }
594 #endif
595 
596     ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_tx_notifications);
597 }
598 
599 void
ble_hs_sched_reset(int reason)600 ble_hs_sched_reset(int reason)
601 {
602     BLE_HS_DBG_ASSERT(ble_hs_reset_reason == 0);
603 
604     ble_hs_reset_reason = reason;
605     ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_reset);
606 }
607 
608 void
ble_hs_hw_error(uint8_t hw_code)609 ble_hs_hw_error(uint8_t hw_code)
610 {
611     ble_hs_sched_reset(BLE_HS_HW_ERR(hw_code));
612 }
613 
614 int
ble_hs_start(void)615 ble_hs_start(void)
616 {
617     int rc;
618 
619     ble_hs_lock();
620     switch (ble_hs_enabled_state) {
621     case BLE_HS_ENABLED_STATE_ON:
622         rc = BLE_HS_EALREADY;
623         break;
624 
625     case BLE_HS_ENABLED_STATE_STOPPING:
626         rc = BLE_HS_EBUSY;
627         break;
628 
629     case BLE_HS_ENABLED_STATE_OFF:
630         ble_hs_enabled_state = BLE_HS_ENABLED_STATE_ON;
631         rc = 0;
632         break;
633 
634     default:
635         assert(0);
636         rc = BLE_HS_EUNKNOWN;
637         break;
638     }
639     ble_hs_unlock();
640 
641     if (rc != 0) {
642         return rc;
643     }
644 
645     ble_hs_parent_task = ble_npl_get_current_task_id();
646 
647     /* Stop the timer just in case the host was already running (e.g., unit
648      * tests).
649      */
650     ble_npl_callout_stop(&ble_hs_timer);
651 
652     ble_npl_callout_init(&ble_hs_timer, ble_hs_evq, ble_hs_timer_exp, NULL);
653 
654     rc = ble_gatts_start();
655     if (rc != 0) {
656         return rc;
657     }
658 
659     ble_hs_sync();
660 
661     return 0;
662 }
663 
664 /**
665  * Called when a data packet is received from the controller.  This function
666  * consumes the supplied mbuf, regardless of the outcome.
667  *
668  * @param om                    The incoming data packet, beginning with the
669  *                                  HCI ACL data header.
670  *
671  * @return                      0 on success; nonzero on failure.
672  */
673 static int
ble_hs_rx_data(struct os_mbuf * om,void * arg)674 ble_hs_rx_data(struct os_mbuf *om, void *arg)
675 {
676     int rc;
677 
678     /* If flow control is enabled, mark this packet with its corresponding
679      * connection handle.
680      */
681     ble_hs_flow_fill_acl_usrhdr(om);
682 
683     rc = ble_mqueue_put(&ble_hs_rx_q, ble_hs_evq, om);
684     if (rc != 0) {
685         os_mbuf_free_chain(om);
686         return BLE_HS_EOS;
687     }
688 
689     return 0;
690 }
691 
692 /**
693  * Enqueues an ACL data packet for transmission.  This function consumes the
694  * supplied mbuf, regardless of the outcome.
695  *
696  * @param om                    The outgoing data packet, beginning with the
697  *                                  HCI ACL data header.
698  *
699  * @return                      0 on success; nonzero on failure.
700  */
701 int
ble_hs_tx_data(struct os_mbuf * om)702 ble_hs_tx_data(struct os_mbuf *om)
703 {
704 #if BLE_MONITOR
705     ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_TX_PKT, om);
706 #endif
707 
708     ble_hci_trans_hs_acl_tx(om);
709     return 0;
710 }
711 
712 void
ble_hs_init(void)713 ble_hs_init(void)
714 {
715     int rc;
716 
717     /* Ensure this function only gets called by sysinit. */
718     SYSINIT_ASSERT_ACTIVE();
719 
720     /* Create memory pool of OS events */
721     rc = os_mempool_init(&ble_hs_hci_ev_pool, BLE_HS_HCI_EVT_COUNT,
722                          sizeof (struct ble_npl_event), ble_hs_hci_os_event_buf,
723                          "ble_hs_hci_ev_pool");
724     SYSINIT_PANIC_ASSERT(rc == 0);
725 
726     /* These get initialized here to allow unit tests to run without a zeroed
727      * bss.
728      */
729     ble_hs_reset_reason = 0;
730     ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF;
731 
732     ble_npl_event_init(&ble_hs_ev_tx_notifications, ble_hs_event_tx_notify,
733                        NULL);
734     ble_npl_event_init(&ble_hs_ev_reset, ble_hs_event_reset, NULL);
735     ble_npl_event_init(&ble_hs_ev_start_stage1, ble_hs_event_start_stage1,
736                        NULL);
737     ble_npl_event_init(&ble_hs_ev_start_stage2, ble_hs_event_start_stage2,
738                        NULL);
739 
740     ble_hs_hci_init();
741 
742     rc = ble_hs_conn_init();
743     SYSINIT_PANIC_ASSERT(rc == 0);
744 
745     rc = ble_l2cap_init();
746     SYSINIT_PANIC_ASSERT(rc == 0);
747 
748     rc = ble_att_init();
749     SYSINIT_PANIC_ASSERT(rc == 0);
750 
751     rc = ble_att_svr_init();
752     SYSINIT_PANIC_ASSERT(rc == 0);
753 
754     rc = ble_gap_init();
755     SYSINIT_PANIC_ASSERT(rc == 0);
756 
757     rc = ble_gattc_init();
758     SYSINIT_PANIC_ASSERT(rc == 0);
759 
760     rc = ble_gatts_init();
761     SYSINIT_PANIC_ASSERT(rc == 0);
762 
763     ble_hs_stop_init();
764 
765     ble_mqueue_init(&ble_hs_rx_q, ble_hs_event_rx_data, NULL);
766 
767     rc = stats_init_and_reg(
768         STATS_HDR(ble_hs_stats), STATS_SIZE_INIT_PARMS(ble_hs_stats,
769         STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_hs_stats), "ble_hs");
770     SYSINIT_PANIC_ASSERT(rc == 0);
771 
772     rc = ble_npl_mutex_init(&ble_hs_mutex);
773     SYSINIT_PANIC_ASSERT(rc == 0);
774 
775 #if MYNEWT_VAL(BLE_HS_DEBUG)
776     ble_hs_dbg_mutex_locked = 0;
777 #endif
778 
779     /* Configure the HCI transport to communicate with a host. */
780     ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL);
781 
782 #ifdef MYNEWT
783     ble_hs_evq_set((struct ble_npl_eventq *)os_eventq_dflt_get());
784 #else
785     ble_hs_evq_set(nimble_port_get_dflt_eventq());
786 #endif
787 
788 #if BLE_MONITOR
789     rc = ble_monitor_init();
790     SYSINIT_PANIC_ASSERT(rc == 0);
791 #endif
792 
793     /* Enqueue the start event to the default event queue.  Using the default
794      * queue ensures the event won't run until the end of main().  This allows
795      * the application to configure this package in the meantime.
796      */
797 #if MYNEWT_VAL(BLE_HS_AUTO_START)
798 #ifdef MYNEWT
799     ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(),
800                        &ble_hs_ev_start_stage1);
801 #else
802     ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1);
803 #endif
804 #endif
805 
806 #if BLE_MONITOR
807     ble_monitor_new_index(0, (uint8_t[6]){ }, "nimble0");
808 #endif
809 }
810