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