From f3f06a8d6f9944fccfbad5b7c69ced2c53331738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Fri, 31 May 2019 14:18:00 +0200 Subject: [PATCH] nimble/ble_hs_stop: Change hs stop procedure This patch change a way of handling stop procedure. Before, host was disconnecting one by one all the active connections. This could result in long procedure time when some devices came out of range and host was waiting as long as supervision timout takes. Now, host is sending in the raw Disconnect Command to all the active connections and then start graceful disconnect timeout 2s. Host notifies that is stop when a) all the disconnection complete events arrived within 2s b) disconnect timeout fires --- nimble/host/src/ble_hs_stop.c | 100 +++++++++++------- nimble/host/syscfg.yml | 6 ++ .../examples/linux/include/syscfg/syscfg.h | 4 + .../linux_blemesh/include/syscfg/syscfg.h | 4 + porting/nimble/include/syscfg/syscfg.h | 4 + porting/npl/riot/include/syscfg/syscfg.h | 3 + 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/nimble/host/src/ble_hs_stop.c b/nimble/host/src/ble_hs_stop.c index ff540b931..5831d0761 100644 --- a/nimble/host/src/ble_hs_stop.c +++ b/nimble/host/src/ble_hs_stop.c @@ -21,9 +21,12 @@ #include "sysinit/sysinit.h" #include "syscfg/syscfg.h" #include "ble_hs_priv.h" +#include "nimble/nimble_npl.h" +#ifndef MYNEWT +#include "nimble/nimble_port.h" +#endif -static ble_npl_event_fn ble_hs_stop_term_event_cb; -static struct ble_npl_event ble_hs_stop_term_ev; +#define BLE_HOST_STOP_TIMEOUT_MS MYNEWT_VAL(BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT) static struct ble_gap_event_listener ble_hs_stop_gap_listener; @@ -33,6 +36,11 @@ static struct ble_gap_event_listener ble_hs_stop_gap_listener; SLIST_HEAD(ble_hs_stop_listener_slist, ble_hs_stop_listener); static struct ble_hs_stop_listener_slist ble_hs_stop_listeners; +/* Track number of connections */ +static uint8_t ble_hs_stop_conn_cnt; + +static struct ble_npl_callout ble_hs_stop_terminate_tmo; + /** * Called when a stop procedure has completed. */ @@ -42,6 +50,8 @@ ble_hs_stop_done(int status) struct ble_hs_stop_listener_slist slist; struct ble_hs_stop_listener *listener; + ble_npl_callout_stop(&ble_hs_stop_terminate_tmo); + ble_hs_lock(); ble_gap_event_listener_unregister(&ble_hs_stop_gap_listener); @@ -95,47 +105,41 @@ ble_hs_stop_terminate_all_periodic_sync(void) #endif /** - * Terminates the first open connection. - * - * If there are no open connections, Check for any active periodic sync - * handles. + * Terminates connection. */ -static void -ble_hs_stop_terminate_next_conn(void) +static int +ble_hs_stop_terminate_conn(struct ble_hs_conn *conn, void *arg) { - uint16_t handle; int rc; - handle = ble_hs_atomic_first_conn_handle(); - if (handle == BLE_HS_CONN_HANDLE_NONE) { - /* No open connections. Signal completion of the stop procedure. */ - ble_hs_stop_done(0); - return; - } - - rc = ble_gap_terminate(handle, BLE_ERR_REM_USER_CONN_TERM); + rc = ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); if (rc == 0) { /* Terminate procedure successfully initiated. Let the GAP event * handler deal with the result. */ + ble_hs_stop_conn_cnt++; } else { - BLE_HS_LOG(ERROR, - "ble_hs_stop: failed to terminate connection; rc=%d\n", rc); - ble_hs_stop_done(rc); + /* If failed, just make sure we are not going to wait for connection complete event, + * just count it as already disconnected + */ + BLE_HS_LOG(ERROR, "ble_hs_stop: failed to terminate connection; rc=%d\n", rc); } + + return 0; } /** - * Event handler. Attempts to terminate the first open connection if there is - * one. All additional connections are terminated elsewhere in the GAP event - * handler. - * - * If there are no connections, signals completion of the stop procedure. + * This is called when host graceful disconnect timeout fires. That means some devices + * are out of range and disconnection completed did no happen yet. */ static void -ble_hs_stop_term_event_cb(struct ble_npl_event *ev) +ble_hs_stop_terminate_timeout_cb(struct ble_npl_event *ev) { - ble_hs_stop_terminate_next_conn(); + BLE_HS_LOG(ERROR, "ble_hs_stop_terminate_timeout_cb," + "%d connection(s) still up \n", ble_hs_stop_conn_cnt); + + /* TODO: Shall we send error here? */ + ble_hs_stop_done(0); } /** @@ -151,7 +155,11 @@ ble_hs_stop_gap_event(struct ble_gap_event *event, void *arg) if (event->type == BLE_GAP_EVENT_DISCONNECT || event->type == BLE_GAP_EVENT_TERM_FAILURE) { - ble_hs_stop_terminate_next_conn(); + ble_hs_stop_conn_cnt--; + + if (ble_hs_stop_conn_cnt == 0) { + ble_hs_stop_done(0); + } } return 0; @@ -233,12 +241,6 @@ ble_hs_stop(struct ble_hs_stop_listener *listener, ble_gap_preempt(); ble_gap_preempt_done(); - rc = ble_gap_event_listener_register(&ble_hs_stop_gap_listener, - ble_hs_stop_gap_event, NULL); - if (rc != 0) { - return rc; - } - #if MYNEWT_VAL(BLE_PERIODIC_ADV) /* Check for active periodic sync first and terminate it all */ rc = ble_hs_stop_terminate_all_periodic_sync(); @@ -247,11 +249,23 @@ ble_hs_stop(struct ble_hs_stop_listener *listener, } #endif - /* Schedule termination of all open connections in the host task. This is - * done even if there are no open connections so that the result of the - * stop procedure is signaled in a consistent manner (asynchronously). - */ - ble_npl_eventq_put(ble_hs_evq_get(), &ble_hs_stop_term_ev); + rc = ble_gap_event_listener_register(&ble_hs_stop_gap_listener, + ble_hs_stop_gap_event, NULL); + if (rc != 0) { + return rc; + } + + ble_hs_lock(); + ble_hs_conn_foreach(ble_hs_stop_terminate_conn, NULL); + ble_hs_unlock(); + + if (ble_hs_stop_conn_cnt > 0) { + ble_npl_callout_reset(&ble_hs_stop_terminate_tmo, + ble_npl_time_ms_to_ticks32(BLE_HOST_STOP_TIMEOUT_MS)); + } else { + /* No connections, stop is completed */ + ble_hs_stop_done(0); + } return 0; } @@ -259,5 +273,11 @@ ble_hs_stop(struct ble_hs_stop_listener *listener, void ble_hs_stop_init(void) { - ble_npl_event_init(&ble_hs_stop_term_ev, ble_hs_stop_term_event_cb, NULL); +#ifdef MYNEWT + ble_npl_callout_init(&ble_hs_stop_terminate_tmo, ble_npl_eventq_dflt_get(), + ble_hs_stop_terminate_timeout_cb, NULL); +#else + ble_npl_callout_init(&ble_hs_stop_terminate_tmo, nimble_port_get_dflt_eventq(), + ble_hs_stop_terminate_timeout_cb, NULL); +#endif } diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml index 0b9766165..3c3c21da0 100644 --- a/nimble/host/syscfg.yml +++ b/nimble/host/syscfg.yml @@ -435,6 +435,12 @@ syscfg.defs: entails aborting all GAP procedures and terminating open connections. value: 1 + + BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT: + description: > + Timeout used in NimBLE's host stop procedure in ms. + value: 2000 + BLE_HS_SYSINIT_STAGE: description: > Sysinit stage for the NimBLE host. diff --git a/porting/examples/linux/include/syscfg/syscfg.h b/porting/examples/linux/include/syscfg/syscfg.h index d4d4aee8e..507a580dd 100644 --- a/porting/examples/linux/include/syscfg/syscfg.h +++ b/porting/examples/linux/include/syscfg/syscfg.h @@ -723,6 +723,10 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif +#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT +#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000) +#endif + /*** nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) diff --git a/porting/examples/linux_blemesh/include/syscfg/syscfg.h b/porting/examples/linux_blemesh/include/syscfg/syscfg.h index 522345e50..12d969b1d 100644 --- a/porting/examples/linux_blemesh/include/syscfg/syscfg.h +++ b/porting/examples/linux_blemesh/include/syscfg/syscfg.h @@ -723,6 +723,10 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif +#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT +#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000) +#endif + /*** nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) diff --git a/porting/nimble/include/syscfg/syscfg.h b/porting/nimble/include/syscfg/syscfg.h index 6ebfc63b7..bbfed5781 100644 --- a/porting/nimble/include/syscfg/syscfg.h +++ b/porting/nimble/include/syscfg/syscfg.h @@ -723,6 +723,10 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif +#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT +#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000) +#endif + /*** nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) diff --git a/porting/npl/riot/include/syscfg/syscfg.h b/porting/npl/riot/include/syscfg/syscfg.h index 84321dbff..b0b9c5ab1 100644 --- a/porting/npl/riot/include/syscfg/syscfg.h +++ b/porting/npl/riot/include/syscfg/syscfg.h @@ -933,6 +933,9 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif +#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT +#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000) +#endif /*** net/nimble/host/mesh */ #ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT