• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *ble_hs_evq_get(void)
108 {
109     return ble_hs_evq;
110 }
111 
ble_hs_evq_set(struct ble_npl_eventq * evq)112 void ble_hs_evq_set(struct ble_npl_eventq *evq)
113 {
114     ble_hs_evq = evq;
115 }
116 
117 #if MYNEWT_VAL(BLE_HS_DEBUG)
ble_hs_locked_by_cur_task(void)118 int ble_hs_locked_by_cur_task(void)
119 {
120 #if MYNEWT
121     struct os_task *owner;
122 
123     if (!ble_npl_os_started()) {
124         return ble_hs_dbg_mutex_locked;
125     }
126 
127     owner = ble_hs_mutex.mu.mu_owner;
128     return owner != NULL && owner == os_sched_get_current_task();
129 #else
130     return 1;
131 #endif
132 }
133 #endif
134 
135 /**
136  * Indicates whether the host's parent task is currently running.
137  */
ble_hs_is_parent_task(void)138 int ble_hs_is_parent_task(void)
139 {
140     return !ble_npl_os_started() ||
141            ble_npl_get_current_task_id() == ble_hs_parent_task;
142 }
143 
144 /**
145  * Locks the BLE host mutex.  Nested locks allowed.
146  */
ble_hs_lock_nested(void)147 void ble_hs_lock_nested(void)
148 {
149     int rc;
150 #if MYNEWT_VAL(BLE_HS_DEBUG)
151 
152     if (!ble_npl_os_started()) {
153         ble_hs_dbg_mutex_locked = 1;
154         return;
155     }
156 
157 #endif
158     rc = ble_npl_mutex_pend(&ble_hs_mutex, 0xffffffff);
159     BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
160 }
161 
162 /**
163  * Unlocks the BLE host mutex.  Nested locks allowed.
164  */
ble_hs_unlock_nested(void)165 void ble_hs_unlock_nested(void)
166 {
167     int rc;
168 #if MYNEWT_VAL(BLE_HS_DEBUG)
169 
170     if (!ble_npl_os_started()) {
171         ble_hs_dbg_mutex_locked = 0;
172         return;
173     }
174 
175 #endif
176     rc = ble_npl_mutex_release(&ble_hs_mutex);
177     BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
178 }
179 
180 /**
181  * Locks the BLE host mutex.  Nested locks not allowed.
182  */
ble_hs_lock(void)183 void ble_hs_lock(void)
184 {
185     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
186 #if MYNEWT_VAL(BLE_HS_DEBUG)
187 
188     if (!ble_npl_os_started()) {
189         BLE_HS_DBG_ASSERT(!ble_hs_dbg_mutex_locked);
190     }
191 
192 #endif
193     ble_hs_lock_nested();
194 }
195 
196 /**
197  * Unlocks the BLE host mutex.  Nested locks not allowed.
198  */
ble_hs_unlock(void)199 void ble_hs_unlock(void)
200 {
201 #if MYNEWT_VAL(BLE_HS_DEBUG)
202 
203     if (!ble_npl_os_started()) {
204         BLE_HS_DBG_ASSERT(ble_hs_dbg_mutex_locked);
205     }
206 
207 #endif
208     ble_hs_unlock_nested();
209 }
210 
ble_hs_process_rx_data_queue(void)211 void ble_hs_process_rx_data_queue(void)
212 {
213     struct os_mbuf *om;
214     while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) {
215 #if BLE_MONITOR
216         ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_RX_PKT, om);
217 #endif
218         ble_hs_hci_evt_acl_process(om);
219     }
220 }
221 
ble_hs_wakeup_tx_conn(struct ble_hs_conn * conn)222 static int ble_hs_wakeup_tx_conn(struct ble_hs_conn *conn)
223 {
224     struct os_mbuf_pkthdr *omp;
225     struct os_mbuf *om;
226 
227     while ((omp = STAILQ_FIRST(&conn->bhc_tx_q)) != NULL) {
228         STAILQ_REMOVE_HEAD(&conn->bhc_tx_q, omp_next);
229         om = OS_MBUF_PKTHDR_TO_MBUF(omp);
230         int rc = ble_hs_hci_acl_tx_now(conn, &om);
231         if (rc == BLE_HS_EAGAIN) {
232             /* Controller is at capacity.  This packet will be the first to
233              * get transmitted next time around.
234              */
235             STAILQ_INSERT_HEAD(&conn->bhc_tx_q, OS_MBUF_PKTHDR(om), omp_next);
236             return BLE_HS_EAGAIN;
237         }
238     }
239 
240     return 0;
241 }
242 
243 /**
244  * Schedules the transmission of all queued ACL data packets to the controller.
245  */
ble_hs_wakeup_tx(void)246 void ble_hs_wakeup_tx(void)
247 {
248     struct ble_hs_conn *conn;
249     int rc;
250     ble_hs_lock();
251 
252     /* If there is a connection with a partially transmitted packet, it has to
253      * be serviced first.  The controller is waiting for the remainder so it
254      * can reassemble it.
255      */
256     for (conn = ble_hs_conn_first();
257             conn != NULL;
258             conn = SLIST_NEXT(conn, bhc_next)) {
259         if (conn->bhc_flags & BLE_HS_CONN_F_TX_FRAG) {
260             rc = ble_hs_wakeup_tx_conn(conn);
261             if (rc != 0) {
262                 goto done;
263             }
264 
265             break;
266         }
267     }
268 
269     /* For each connection, transmit queued packets until there are no more
270      * packets to send or the controller's buffers are exhausted.
271      */
272     for (conn = ble_hs_conn_first();
273             conn != NULL;
274             conn = SLIST_NEXT(conn, bhc_next)) {
275         rc = ble_hs_wakeup_tx_conn(conn);
276         if (rc != 0) {
277             goto done;
278         }
279     }
280 
281 done:
282     ble_hs_unlock();
283 }
284 
ble_hs_clear_rx_queue(void)285 static void ble_hs_clear_rx_queue(void)
286 {
287     struct os_mbuf *om;
288     while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) {
289         os_mbuf_free_chain(om);
290     }
291 }
292 
ble_hs_is_enabled(void)293 int ble_hs_is_enabled(void)
294 {
295     return ble_hs_enabled_state == BLE_HS_ENABLED_STATE_ON;
296 }
297 
ble_hs_synced(void)298 int ble_hs_synced(void)
299 {
300     return ble_hs_sync_state == BLE_HS_SYNC_STATE_GOOD;
301 }
302 
ble_hs_sync(void)303 static int ble_hs_sync(void)
304 {
305     ble_npl_time_t retry_tmo_ticks;
306     int rc;
307     /* Set the sync state to "bringup."  This allows the parent task to send
308      * the startup sequence to the controller.  No other tasks are allowed to
309      * send any commands.
310      */
311     ble_hs_sync_state = BLE_HS_SYNC_STATE_BRINGUP;
312     rc = ble_hs_startup_go();
313     if (rc == 0) {
314         ble_hs_sync_state = BLE_HS_SYNC_STATE_GOOD;
315     } else {
316         ble_hs_sync_state = BLE_HS_SYNC_STATE_BAD;
317     }
318 
319     retry_tmo_ticks = ble_npl_time_ms_to_ticks32(BLE_HS_SYNC_RETRY_TIMEOUT_MS);
320     ble_hs_timer_sched(retry_tmo_ticks);
321 
322     if (rc == 0) {
323         rc = ble_hs_misc_restore_irks();
324         if (rc != 0) {
325             BLE_HS_LOG(INFO, "Failed to restore IRKs from store; status=%d\n",
326                        rc);
327         }
328 
329         if (ble_hs_cfg.sync_cb != NULL) {
330             ble_hs_cfg.sync_cb();
331         }
332 
333         STATS_INC(ble_hs_stats, sync);
334     }
335 
336     return rc;
337 }
338 
ble_hs_reset(void)339 static int ble_hs_reset(void)
340 {
341     int rc;
342     STATS_INC(ble_hs_stats, reset);
343     ble_hs_sync_state = 0;
344     /* Reset transport.  Assume success; there is nothing we can do in case of
345      * failure.  If the transport failed to reset, the host will reset itself
346      * again when it fails to sync with the controller.
347      */
348     (void)ble_hci_trans_reset();
349     ble_hs_clear_rx_queue();
350 
351     while (1) {
352         uint16_t conn_handle = ble_hs_atomic_first_conn_handle();
353         if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
354             break;
355         }
356 
357         ble_gap_conn_broken(conn_handle, ble_hs_reset_reason);
358     }
359 
360     /* Clear configured addresses. */
361     ble_hs_id_reset();
362 
363     if (ble_hs_cfg.reset_cb != NULL && ble_hs_reset_reason != 0) {
364         ble_hs_cfg.reset_cb(ble_hs_reset_reason);
365     }
366 
367     ble_hs_reset_reason = 0;
368     rc = ble_hs_sync();
369     return rc;
370 }
371 
372 /**
373  * Called when the host timer expires.  Handles unresponsive timeouts and
374  * periodic retries in case of resource shortage.
375  */
ble_hs_timer_exp(struct ble_npl_event * ev)376 static void ble_hs_timer_exp(struct ble_npl_event *ev)
377 {
378     int32_t ticks_until_next;
379 
380     switch (ble_hs_sync_state) {
381         case BLE_HS_SYNC_STATE_GOOD:
382             ticks_until_next = ble_gattc_timer();
383             ble_hs_timer_sched(ticks_until_next);
384             ticks_until_next = ble_gap_timer();
385             ble_hs_timer_sched(ticks_until_next);
386             ticks_until_next = ble_l2cap_sig_timer();
387             ble_hs_timer_sched(ticks_until_next);
388             ticks_until_next = ble_sm_timer();
389             ble_hs_timer_sched(ticks_until_next);
390             ticks_until_next = ble_hs_conn_timer();
391             ble_hs_timer_sched(ticks_until_next);
392             break;
393 
394         case BLE_HS_SYNC_STATE_BAD:
395             ble_hs_reset();
396             break;
397 
398         case BLE_HS_SYNC_STATE_BRINGUP:
399         default:
400             /* The timer should not be set in this state. */
401             assert(0);
402             break;
403     }
404 }
405 
ble_hs_timer_reset(uint32_t ticks)406 static void ble_hs_timer_reset(uint32_t ticks)
407 {
408     if (!ble_hs_is_enabled()) {
409         ble_npl_callout_stop(&ble_hs_timer);
410     } else {
411         int rc = ble_npl_callout_reset(&ble_hs_timer, ticks);
412         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
413     }
414 }
415 
ble_hs_timer_sched(int32_t ticks_from_now)416 static void ble_hs_timer_sched(int32_t ticks_from_now)
417 {
418     ble_npl_time_t abs_time;
419 
420     if (ticks_from_now == BLE_HS_FOREVER) {
421         return;
422     }
423 
424     /* Reset timer if it is not currently scheduled or if the specified time is
425      * sooner than the previous expiration time.
426      */
427     abs_time = ble_npl_time_get() + ticks_from_now;
428     if (!ble_npl_callout_is_active(&ble_hs_timer) ||
429             ((ble_npl_stime_t)(abs_time -
430                                ble_npl_callout_get_ticks(&ble_hs_timer))) < 0) {
431         ble_hs_timer_reset(ticks_from_now);
432     }
433 }
434 
ble_hs_timer_resched(void)435 void ble_hs_timer_resched(void)
436 {
437     /* Reschedule the timer to run immediately.  The timer callback will query
438      * each module for an up-to-date expiration time.
439      */
440     ble_hs_timer_reset(0);
441 }
442 
ble_hs_sched_start_stage2(void)443 static void ble_hs_sched_start_stage2(void)
444 {
445     ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(),
446                        &ble_hs_ev_start_stage2);
447 }
448 
ble_hs_sched_start(void)449 void ble_hs_sched_start(void)
450 {
451 #ifdef MYNEWT
452     ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(),
453                        &ble_hs_ev_start_stage1);
454 #else
455     ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1);
456 #endif
457 }
458 
ble_hs_event_rx_hci_ev(struct ble_npl_event * ev)459 static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev)
460 {
461     const struct ble_hci_ev *hci_ev;
462     int rc;
463     hci_ev = ble_npl_event_get_arg(ev);
464     rc = os_memblock_put(&ble_hs_hci_ev_pool, ev);
465     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
466 #if BLE_MONITOR
467     ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, hci_ev,
468                      hci_ev->length + sizeof(*hci_ev));
469 #endif
470     ble_hs_hci_evt_process(hci_ev);
471 }
472 
ble_hs_event_tx_notify(struct ble_npl_event * ev)473 static void ble_hs_event_tx_notify(struct ble_npl_event *ev)
474 {
475     ble_gatts_tx_notifications();
476 }
477 
ble_hs_event_rx_data(struct ble_npl_event * ev)478 static void ble_hs_event_rx_data(struct ble_npl_event *ev)
479 {
480     ble_hs_process_rx_data_queue();
481 }
482 
ble_hs_event_reset(struct ble_npl_event * ev)483 static void ble_hs_event_reset(struct ble_npl_event *ev)
484 {
485     ble_hs_reset();
486 }
487 
488 /**
489  * Implements the first half of the start process.  This just enqueues another
490  * event on the host parent task's event queue.
491  *
492  * Starting is done in two stages to allow the application time to configure
493  * the event queue to use after system initialization but before the host
494  * starts.
495  */
ble_hs_event_start_stage1(struct ble_npl_event * ev)496 static void ble_hs_event_start_stage1(struct ble_npl_event *ev)
497 {
498     ble_hs_sched_start_stage2();
499 }
500 
501 /**
502  * Implements the second half of the start process.  This actually starts the
503  * host.
504  *
505  * Starting is done in two stages to allow the application time to configure
506  * the event queue to use after system initialization but before the host
507  * starts.
508  */
ble_hs_event_start_stage2(struct ble_npl_event * ev)509 static void ble_hs_event_start_stage2(struct ble_npl_event *ev)
510 {
511     int rc;
512     rc = ble_hs_start();
513     assert(rc == 0);
514 }
515 
ble_hs_enqueue_hci_event(uint8_t * hci_evt)516 void ble_hs_enqueue_hci_event(uint8_t *hci_evt)
517 {
518     struct ble_npl_event *ev;
519     ev = os_memblock_get(&ble_hs_hci_ev_pool);
520     if (ev == NULL) {
521         ble_hci_trans_buf_free(hci_evt);
522     } else {
523         ble_npl_event_init(ev, ble_hs_event_rx_hci_ev, hci_evt);
524         ble_npl_eventq_put(ble_hs_evq, ev);
525     }
526 }
527 
528 /**
529  * Schedules for all pending notifications and indications to be sent in the
530  * host parent task.
531  */
ble_hs_notifications_sched(void)532 void ble_hs_notifications_sched(void)
533 {
534 #if !MYNEWT_VAL(BLE_HS_REQUIRE_OS)
535 
536     if (!ble_npl_os_started()) {
537         ble_gatts_tx_notifications();
538         return;
539     }
540 
541 #endif
542     ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_tx_notifications);
543 }
544 
ble_hs_sched_reset(int reason)545 void ble_hs_sched_reset(int reason)
546 {
547     BLE_HS_DBG_ASSERT(ble_hs_reset_reason == 0);
548     ble_hs_reset_reason = reason;
549     ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_reset);
550 }
551 
ble_hs_hw_error(uint8_t hw_code)552 void ble_hs_hw_error(uint8_t hw_code)
553 {
554     ble_hs_sched_reset(BLE_HS_HW_ERR(hw_code));
555 }
556 
ble_hs_start(void)557 int ble_hs_start(void)
558 {
559     int rc;
560     ble_hs_lock();
561 
562     switch (ble_hs_enabled_state) {
563         case BLE_HS_ENABLED_STATE_ON:
564             rc = BLE_HS_EALREADY;
565             break;
566 
567         case BLE_HS_ENABLED_STATE_STOPPING:
568             rc = BLE_HS_EBUSY;
569             break;
570 
571         case BLE_HS_ENABLED_STATE_OFF:
572             ble_hs_enabled_state = BLE_HS_ENABLED_STATE_ON;
573             rc = 0;
574             break;
575 
576         default:
577             assert(0);
578             rc = BLE_HS_EUNKNOWN;
579             break;
580     }
581 
582     ble_hs_unlock();
583 
584     if (rc != 0) {
585         return rc;
586     }
587 
588     ble_hs_parent_task = ble_npl_get_current_task_id();
589 #if MYNEWT_VAL(SELFTEST)
590     /* Stop the timer just in case the host was already running (e.g., unit
591      * tests).
592      */
593     ble_npl_callout_stop(&ble_hs_timer);
594 #endif
595     ble_npl_callout_init(&ble_hs_timer, ble_hs_evq, ble_hs_timer_exp, NULL);
596     ble_hs_sync();
597     return 0;
598 }
599 
600 /**
601  * Called when a data packet is received from the controller.  This function
602  * consumes the supplied mbuf, regardless of the outcome.
603  *
604  * @param om                    The incoming data packet, beginning with the
605  *                                  HCI ACL data header.
606  *
607  * @return                      0 on success; nonzero on failure.
608  */
ble_hs_rx_data(struct os_mbuf * om,void * arg)609 static int ble_hs_rx_data(struct os_mbuf *om, void *arg)
610 {
611     int rc;
612     /* If flow control is enabled, mark this packet with its corresponding
613      * connection handle.
614      */
615     ble_hs_flow_fill_acl_usrhdr(om);
616     rc = ble_mqueue_put(&ble_hs_rx_q, ble_hs_evq, om);
617     if (rc != 0) {
618         os_mbuf_free_chain(om);
619         return BLE_HS_EOS;
620     }
621 
622     return 0;
623 }
624 
625 /**
626  * Enqueues an ACL data packet for transmission.  This function consumes the
627  * supplied mbuf, regardless of the outcome.
628  *
629  * @param om                    The outgoing data packet, beginning with the
630  *                                  HCI ACL data header.
631  *
632  * @return                      0 on success; nonzero on failure.
633  */
ble_hs_tx_data(struct os_mbuf * om)634 int ble_hs_tx_data(struct os_mbuf *om)
635 {
636 #if BLE_MONITOR
637     ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_TX_PKT, om);
638 #endif
639     return ble_hci_trans_hs_acl_tx(om);
640 }
641 
ble_hs_init(void)642 void ble_hs_init(void)
643 {
644     int rc;
645     /* Ensure this function only gets called by sysinit. */
646     SYSINIT_ASSERT_ACTIVE();
647     /* Create memory pool of OS events */
648     rc = os_mempool_init(&ble_hs_hci_ev_pool, BLE_HS_HCI_EVT_COUNT,
649                          sizeof(struct ble_npl_event), ble_hs_hci_os_event_buf,
650                          "ble_hs_hci_ev_pool");
651     SYSINIT_PANIC_ASSERT(rc == 0);
652     /* These get initialized here to allow unit tests to run without a zeroed
653      * bss.
654      */
655     ble_hs_reset_reason = 0;
656     ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF;
657     ble_npl_event_init(&ble_hs_ev_tx_notifications, ble_hs_event_tx_notify,
658                        NULL);
659     ble_npl_event_init(&ble_hs_ev_reset, ble_hs_event_reset, NULL);
660     ble_npl_event_init(&ble_hs_ev_start_stage1, ble_hs_event_start_stage1,
661                        NULL);
662     ble_npl_event_init(&ble_hs_ev_start_stage2, ble_hs_event_start_stage2,
663                        NULL);
664     ble_hs_hci_init();
665     rc = ble_hs_conn_init();
666     SYSINIT_PANIC_ASSERT(rc == 0);
667 #if MYNEWT_VAL(BLE_PERIODIC_ADV)
668     rc = ble_hs_periodic_sync_init();
669     SYSINIT_PANIC_ASSERT(rc == 0);
670 #endif
671     rc = ble_l2cap_init();
672     SYSINIT_PANIC_ASSERT(rc == 0);
673     rc = ble_att_init();
674     SYSINIT_PANIC_ASSERT(rc == 0);
675     rc = ble_att_svr_init();
676     SYSINIT_PANIC_ASSERT(rc == 0);
677     rc = ble_gap_init();
678     SYSINIT_PANIC_ASSERT(rc == 0);
679     rc = ble_gattc_init();
680     SYSINIT_PANIC_ASSERT(rc == 0);
681     rc = ble_gatts_init();
682     SYSINIT_PANIC_ASSERT(rc == 0);
683     ble_hs_stop_init();
684     ble_mqueue_init(&ble_hs_rx_q, ble_hs_event_rx_data, NULL);
685     rc = stats_init_and_reg(STATS_HDR(ble_hs_stats), STATS_SIZE_INIT_PARMS(ble_hs_stats,
686                             STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_hs_stats), "ble_hs");
687     SYSINIT_PANIC_ASSERT(rc == 0);
688     rc = ble_npl_mutex_init(&ble_hs_mutex);
689     SYSINIT_PANIC_ASSERT(rc == 0);
690 #if MYNEWT_VAL(BLE_HS_DEBUG)
691     ble_hs_dbg_mutex_locked = 0;
692 #endif
693 #ifdef MYNEWT
694     ble_hs_evq_set((struct ble_npl_eventq *)os_eventq_dflt_get());
695 #else
696     ble_hs_evq_set(nimble_port_get_dflt_eventq());
697 #endif
698     /* Configure the HCI transport to communicate with a host. */
699     ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL);
700 #if BLE_MONITOR
701     rc = ble_monitor_init();
702     SYSINIT_PANIC_ASSERT(rc == 0);
703 #endif
704     /* Enqueue the start event to the default event queue.  Using the default
705      * queue ensures the event won't run until the end of main().  This allows
706      * the application to configure this package in the meantime.
707      */
708 #if MYNEWT_VAL(BLE_HS_AUTO_START)
709 #ifdef MYNEWT
710     ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(),
711                        &ble_hs_ev_start_stage1);
712 #else
713     ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1);
714 #endif
715 #endif
716 #if BLE_MONITOR
717     ble_monitor_new_index(0, (uint8_t[6]) { }, "nimble0");
718 #endif
719 }
720 
ble_hs_deinit(void)721 void ble_hs_deinit(void)
722 {
723     ble_gatts_stop();
724     ble_npl_callout_deinit(&ble_hs_timer);
725     ble_npl_mutex_deinit(&ble_hs_mutex);
726     ble_gap_deinit();
727     ble_hs_stop_deinit();
728     ble_hs_hci_deinit();
729 }