From 2daa87d6dd7eb2d9de3d675dc562f25f615170bf Mon Sep 17 00:00:00 2001 From: Christopher Collins Date: Mon, 2 Oct 2017 15:05:43 -0700 Subject: [PATCH] MYNEWT-842 BLE Host - Stop GAP, add to rslv list If an attempt to add a peer's IRK to the resolving list fails, the failure is not reported, and the operation is not reattempted. Adding to the resolving list fails if the host is scanning or advertising at the time, so this is a common occurrence. This commit address this problem as follows. Before attempting to add an entry to the resolving list, the host stops all active GAP procedures. After the entry has been successfully added, the application must restart interrupted procedures as needed. Interrupted procedures are reported with a reason or status code of `BLE_HS_EPREEMPTED`. Furthermore, an attempt to initiate a new GAP procedure during preemption fails with a return code of `BLE_HS_EPREEMPTED`. There is one additional requirement which complicates this feature: interrupted procedures must not be reported until after preemption has ended. That way, the application can restart the procedure immediately upon receiving the event. This requirement implies a somewhat strange order of events when an entry is added to the resolving list: 1. Set the preempted state. 2. Abort all GAP procedures, but don't report anything. 3. Add the entry to the resolving list. 4. Clear the preempted state. 5. Finally, report interrupted procedures. The implementation is further complicated by the nature of the 'cancel-create-connection' HCI exchange. The cancel operation can be considered complete as soon as the command-complete event is received, but it does not get reported until the subsequent 'le-connection-complete' event is received. For this reason, the GAP must stay in the preempted state indefinitely until the expected event is received. X-Original-Commit: 76bfc3ba0d85ab591c97ba54728d5c3fa0669b57 --- nimble/host/src/ble_hs.c | 1 + nimble/host/src/ble_hs_pvcy.c | 53 +++++++++++++++++++++++++++++------ nimble/host/src/ble_store.c | 11 -------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/nimble/host/src/ble_hs.c b/nimble/host/src/ble_hs.c index 33e51d0f1..c7755f364 100644 --- a/nimble/host/src/ble_hs.c +++ b/nimble/host/src/ble_hs.c @@ -631,6 +631,7 @@ ble_hs_init(void) /* These get initialized here to allow unit tests to run without a zeroed * bss. */ + ble_hs_reset_reason = 0; ble_hs_ev_tx_notifications = (struct os_event) { .ev_cb = ble_hs_event_tx_notify, }; diff --git a/nimble/host/src/ble_hs_pvcy.c b/nimble/host/src/ble_hs_pvcy.c index 95b22c262..dbabb720c 100644 --- a/nimble/host/src/ble_hs_pvcy.c +++ b/nimble/host/src/ble_hs_pvcy.c @@ -106,16 +106,15 @@ ble_hs_pvcy_clear_entries(void) return 0; } -int -ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type, - const uint8_t *irk) +static int +ble_hs_pvcy_add_entry_hci(const uint8_t *addr, uint8_t addr_type, + const uint8_t *irk) { struct hci_add_dev_to_resolving_list add; uint8_t buf[BLE_HCI_ADD_TO_RESOLV_LIST_LEN]; + ble_addr_t peer_addr; int rc; - STATS_INC(ble_hs_stats, pvcy_add_entry); - add.addr_type = addr_type; memcpy(add.addr, addr, 6); memcpy(add.local_irk, ble_hs_pvcy_irk, 16); @@ -123,20 +122,56 @@ ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type, rc = ble_hs_hci_cmd_build_add_to_resolv_list(&add, buf, sizeof(buf)); if (rc != 0) { - goto err; + return rc; } rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), buf, sizeof(buf), NULL, 0, NULL); if (rc != 0) { - goto err; + return rc; + } + + + /* FIXME Controller is BT5.0 and default privacy mode is network which + * can cause problems for apps which are not aware of it. We need to + * sort it out somehow. For now we set device mode for all of the peer + * devices and application should change it to network if needed + */ + peer_addr.type = addr_type; + memcpy(peer_addr.val, addr, sizeof peer_addr.val); + rc = ble_hs_pvcy_set_mode(&peer_addr, BLE_GAP_PRIVATE_MODE_DEVICE); + if (rc != 0) { + return rc; } return 0; +} + +int +ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type, + const uint8_t *irk) +{ + int rc; + + STATS_INC(ble_hs_stats, pvcy_add_entry); + + /* No GAP procedures can be active when adding an entry to the resolving + * list (Vol 2, Part E, 7.8.38). Stop all GAP procedures and temporarily + * prevent any new ones from being started. + */ + ble_gap_preempt(); + + /* Try to add the entry now that GAP is halted. */ + rc = ble_hs_pvcy_add_entry_hci(addr, addr_type, irk); + + /* Allow GAP procedures to be started again. */ + ble_gap_preempt_done(); + + if (rc != 0) { + STATS_INC(ble_hs_stats, pvcy_add_entry_fail); + } -err: - STATS_INC(ble_hs_stats, pvcy_add_entry_fail); return rc; } diff --git a/nimble/host/src/ble_store.c b/nimble/host/src/ble_store.c index 0aa444ef2..22e608947 100644 --- a/nimble/host/src/ble_store.c +++ b/nimble/host/src/ble_store.c @@ -244,17 +244,6 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec) if (rc != 0) { return rc; } - - /* FIXME Controller is BT5.0 and default privacy mode is network which - * can cause problems for apps which are not aware of it. We need to - * sort it out somehow. For now we set device mode for all of the peer - * devices and application should change it to network if needed - */ - rc = ble_hs_pvcy_set_mode(&value_sec->peer_addr, - BLE_GAP_PRIVATE_MODE_DEVICE); - if (rc != 0) { - return rc; - } } return 0;