diff --git a/nimble/host/include/host/ble_hs_pvcy.h b/nimble/host/include/host/ble_hs_pvcy.h index 0ff32b80b..19087f220 100644 --- a/nimble/host/include/host/ble_hs_pvcy.h +++ b/nimble/host/include/host/ble_hs_pvcy.h @@ -19,6 +19,9 @@ * under the License. */ +#ifndef H_BLE_HS_PVCY_ +#define H_BLE_HS_PVCY_ + #include "host/ble_hs.h" #ifdef __cplusplus @@ -26,15 +29,45 @@ extern "C" { #endif #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) -/* Called to configure local(own) privacy (RPA) when using host based privacy. In - * Host based privacy as controller is not aware of RPA, we do it via - * 'BLE_ADDR_RANDOM' addr_type route. + +#define NIMBLE_HOST_DISABLE_PRIVACY 0x00 +#define NIMBLE_HOST_ENABLE_RPA 0x01 +#define NIMBLE_HOST_ENABLE_NRPA 0x02 + +/* Called to configure local(own) privacy (RPA/NRPA) when using Host based privacy. + * In Host based privacy, as controller is not aware of RPA/NRPA address is in use, + * we do it through 'BLE_ADDR_RANDOM (0x01)' addr_type route. This is necessary + * so as to set the private address as random address in controller. + * Remember to configure `BLE_SM_PAIR_KEY_DIST_ID` in our & their + * key distributions for using RPA. For NRPA part of privacy it is not + * necessary to configure key distributions in host, as anyway NRPA is non-resolvable. + * Please call this API once host-controller are synced as we set the private + * (RPA/NRPA) address using host-controller HCI commands. * - * @param enable RPA when enable is not 0 - * disable RPA otherwise + * To give brief information on how to use this feature, + * please refer to following steps while using RPA feature: + * + * 1. Include "host/ble_hs_pvcy.h". + * 2. Set own_addr_type to `BLE_OWN_ADDR_RANDOM`. + * 3. Add `BLE_SM_PAIR_KEY_DIST_ID` to key distribution in + * `ble_hs_cfg.sm_our_key_dist` & `ble_hs_cfg.sm_their_key_dist`. + * 4. Call `ble_hs_pvcy_rpa_config(1)` in Host-Controller sync callback. + * + * In case of NRPA, steps 1, 2 and calling ble_hs_pvcy_rpa_config(2) will + * suffice. + * + * @param enable RPA when param = 1 (NIMBLE_HOST_ENABLE_RPA) + * enable NRPA when param = 2 (NIMBLE_HOST_ENABLE_NRPA) + * disable privacy when param = 0 (NIMBLE_HOST_DISABLE_PRIVACY) * * @return return 0 when successful. * return appropriate error code otherwise */ int ble_hs_pvcy_rpa_config(uint8_t enable); #endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/nimble/host/src/ble_hs_id.c b/nimble/host/src/ble_hs_id.c index 2786e7fa9..48481fec4 100644 --- a/nimble/host/src/ble_hs_id.c +++ b/nimble/host/src/ble_hs_id.c @@ -67,6 +67,37 @@ ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr) } #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) +/** + * Sets the device's pseudo Non Resolvable Private Address when 'Host based + * privacy' is in use. + * + * @return 0 on success; + * Appropriate error code if failure. + */ +int +ble_hs_id_set_nrpa_rnd() +{ + + ble_addr_t nrpa_addr; + int rc; + + ble_hs_id_gen_rnd(1, &nrpa_addr); + + ble_hs_lock(); + + /* set the NRPA address as pseudo random address in controller */ + rc = ble_hs_hci_util_set_random_addr(nrpa_addr.val); + if (rc != 0) { + goto done; + } + + memcpy(ble_hs_id_rnd, nrpa_addr.val, BLE_DEV_ADDR_LEN); + +done: + ble_hs_unlock(); + return rc; +} + /** * Sets the device's pseudo RPA address when 'Host based privacy' is in use. * The address type (RPA) is inferred from the most-significant bits. The diff --git a/nimble/host/src/ble_hs_id_priv.h b/nimble/host/src/ble_hs_id_priv.h index c031b9511..85260ec48 100644 --- a/nimble/host/src/ble_hs_id_priv.h +++ b/nimble/host/src/ble_hs_id_priv.h @@ -36,6 +36,7 @@ void ble_hs_id_rnd_reset(void); #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) bool ble_hs_is_rpa(uint8_t *addr, uint8_t addr_type); int ble_hs_id_set_pseudo_rnd(const uint8_t *); +int ble_hs_id_set_nrpa_rnd(void); #endif #ifdef __cplusplus } diff --git a/nimble/host/src/ble_hs_pvcy.c b/nimble/host/src/ble_hs_pvcy.c index 32f15974b..69f3da543 100644 --- a/nimble/host/src/ble_hs_pvcy.c +++ b/nimble/host/src/ble_hs_pvcy.c @@ -22,6 +22,7 @@ #include "stats/stats.h" #include "ble_hs_priv.h" #include "ble_hs_resolv_priv.h" +#include "host/ble_hs_pvcy.h" static uint8_t ble_hs_pvcy_started; static uint8_t ble_hs_pvcy_irk[16]; @@ -329,7 +330,7 @@ ble_hs_pvcy_rpa_config(uint8_t enable) { int rc = 0; - if (enable != 0) { + if (enable != NIMBLE_HOST_DISABLE_PRIVACY) { rc = ble_hs_pvcy_ensure_started(); if (rc != 0) { return rc; @@ -337,8 +338,15 @@ ble_hs_pvcy_rpa_config(uint8_t enable) ble_hs_resolv_enable(true); + /* Configure NRPA address related flags according to input parameter */ + if (enable == NIMBLE_HOST_ENABLE_NRPA) { + ble_hs_resolv_nrpa_enable(); + } else { + ble_hs_resolv_nrpa_disable(); + } + /* Generate local RPA address and set it in controller */ - rc = ble_hs_gen_own_rpa_random(); + rc = ble_hs_gen_own_private_rnd(); } else { ble_hs_resolv_enable(false); } diff --git a/nimble/host/src/ble_hs_resolv.c b/nimble/host/src/ble_hs_resolv.c index 7f2413898..46e5577f6 100644 --- a/nimble/host/src/ble_hs_resolv.c +++ b/nimble/host/src/ble_hs_resolv.c @@ -50,6 +50,9 @@ struct ble_hs_resolv_data { struct ble_npl_callout rpa_timer; }; +/* NRPA bit: Enables NRPA as private address. */ +static bool nrpa_pvcy; + /*** APIs for Peer Device Records. * * These Peer records are necessary to take care of Peers with RPA address when @@ -178,6 +181,44 @@ is_rpa_resolvable_by_peer_rec(struct ble_hs_dev_records *p_dev_rec, uint8_t *pee return false; } +static void +ble_rpa_replace_id_with_rand_addr(uint8_t *addr_type, uint8_t *peer_addr) +{ + struct ble_hs_dev_records *p_dev_rec; + ble_addr_t p_addr = {0}; + struct ble_hs_conn *conn = NULL; + + p_dev_rec = ble_rpa_find_peer_dev_rec(peer_addr); + + if (p_dev_rec != NULL) { + if (memcmp(p_dev_rec->rand_addr, p_dev_rec->identity_addr, BLE_DEV_ADDR_LEN)) { + /* OTA address (before resolving) gets saved in RAND_ADDR when the peer + * record is fetched from resolving list. Replace peer address + * with rand_addr to maintain status quo for new pairing/encryption request. */ + p_addr.type = *addr_type; + memcpy(&p_addr.val[0], peer_addr, BLE_DEV_ADDR_LEN); + + ble_hs_lock(); + + conn = ble_hs_conn_find_by_addr(&p_addr); + /* Rewrite the peer address history in ble_hs_conn. Need to take + * this step to avoid taking wrong address during re-pairing + * process */ + if (conn != NULL) { + conn->bhc_peer_rpa_addr.type = p_dev_rec->rand_addr_type; + memcpy(&conn->bhc_peer_rpa_addr.val[0], p_dev_rec->rand_addr, BLE_DEV_ADDR_LEN); + conn->bhc_peer_addr.type = p_dev_rec->rand_addr_type; + memcpy(&conn->bhc_peer_addr.val[0], p_dev_rec->rand_addr, BLE_DEV_ADDR_LEN); + BLE_HS_LOG(DEBUG, "\n Replace Identity addr with random addr received at" + " start of the connection\n"); + } + + ble_hs_unlock(); + } + } + return; +} + /* Add peer to peer device records. * * @return 0 if added successfully, @@ -224,6 +265,7 @@ ble_rpa_find_rl_from_peer_records(uint8_t *peer_addr, uint8_t *peer_addr_type) if (is_rpa_resolvable_by_peer_rec(p_dev_rec, peer_addr)) { memcpy(p_dev_rec->rand_addr, peer_addr, BLE_DEV_ADDR_LEN); + p_dev_rec->rand_addr_type = *peer_addr_type; rl = ble_hs_resolv_list_find(p_dev_rec->identity_addr); if (rl) { memcpy(peer_addr, p_dev_rec->identity_addr, BLE_DEV_ADDR_LEN); @@ -274,13 +316,10 @@ ble_rpa_replace_peer_params_with_rl(uint8_t *peer_addr, uint8_t *addr_type, if (is_rpa) { ble_hs_log_flat_buf(peer_addr, BLE_DEV_ADDR_LEN); - rl_tmp = ble_hs_resolv_list_find(peer_addr); + BLE_HS_LOG(DEBUG, "\n"); - /* Try to find from your peer_device records, if RL doesn't - * exist */ - if (rl_tmp == NULL) { - rl_tmp = ble_rpa_find_rl_from_peer_records(peer_addr, addr_type); - } + /* Try to find RL from your peer_device records */ + rl_tmp = ble_rpa_find_rl_from_peer_records(peer_addr, addr_type); } if (rl != NULL) { @@ -305,6 +344,10 @@ is_ble_hs_resolv_enabled(void) bool ble_host_rpa_enabled(void) { + if (nrpa_pvcy) { + return false; + } + if (is_ble_hs_resolv_enabled() && ble_hs_pvcy_enabled()) { return true; } @@ -385,12 +428,16 @@ ble_hs_resolv_gen_priv_addr(struct ble_hs_resolv_entry *rl, int local) addr[2] = ecb.cipher_text[13]; } -/* Called to generate RPA address and this address is set in controller as - * Random address. This is necessary in Host based privacy because controller is unaware of RPA - * address is being used */ +/* Called to generate private (RPA/NRPA) address and this address is set in controller as + * Random address. This is necessary in Host based privacy because controller + * is unaware of private address is being used */ int -ble_hs_gen_own_rpa_random(void) +ble_hs_gen_own_private_rnd(void) { + if (nrpa_pvcy) { + return ble_hs_id_set_nrpa_rnd(); + } + struct ble_hs_resolv_entry *rl = &g_ble_hs_resolv_list[0]; ble_hs_resolv_gen_priv_addr(rl, 1); @@ -412,12 +459,11 @@ ble_hs_get_rpa_local(void) static void ble_hs_resolv_rpa_timer_cb(struct ble_npl_event *ev) { - if (ble_host_rpa_enabled()) { - BLE_HS_LOG(DEBUG, "RPA Timeout; start active adv & scan with new RPA\n"); - + if (ble_host_rpa_enabled() || (nrpa_pvcy)) { + BLE_HS_LOG(DEBUG, "RPA/NRPA Timeout; start active adv & scan with new Private address \n"); ble_gap_preempt(); - /* Generate local RPA */ - ble_hs_gen_own_rpa_random(); + /* Generate local private address */ + ble_hs_gen_own_private_rnd(); ble_npl_callout_reset(&g_ble_hs_resolv_data.rpa_timer, (int32_t)g_ble_hs_resolv_data.rpa_tmo); ble_gap_preempt_done(); @@ -561,7 +607,7 @@ ble_hs_resolv_list_add(uint8_t *cmdbuf) int ble_hs_resolv_list_rmv(uint8_t addr_type, uint8_t *ident_addr) { - int position; + int position, rc = BLE_HS_ENOENT; /* Remove from IRK records */ position = ble_hs_is_on_resolv_list(ident_addr, addr_type); @@ -573,10 +619,15 @@ ble_hs_resolv_list_rmv(uint8_t addr_type, uint8_t *ident_addr) ble_hs_resolv_entry)); --g_ble_hs_resolv_data.rl_cnt; - return 0; + rc = 0; } - return BLE_HS_ENOENT; + /* As we are removing the RL record, it is needed to change + * peer_address to its latest received OTA address, this helps when existing bond at + * peer side is removed */ + ble_rpa_replace_id_with_rand_addr(&addr_type, ident_addr); + + return rc; } /** @@ -595,6 +646,23 @@ ble_hs_resolv_list_clear_all(void) return; } +/** +* Called by host stack to enable NRPA privacy flag for future reference +*/ +void +ble_hs_resolv_nrpa_enable(void) +{ + nrpa_pvcy = true; +} + +/** +* Called by host stack to disable NRPA privacy flag +*/ +void +ble_hs_resolv_nrpa_disable(void) +{ + nrpa_pvcy = false; +} /** * Called to enable or disable address resolution in the host * diff --git a/nimble/host/src/ble_hs_resolv_priv.h b/nimble/host/src/ble_hs_resolv_priv.h index 568aa89ab..7bc8a2fe6 100644 --- a/nimble/host/src/ble_hs_resolv_priv.h +++ b/nimble/host/src/ble_hs_resolv_priv.h @@ -53,6 +53,7 @@ struct ble_hs_peer_sec { */ struct ble_hs_dev_records { bool rec_used; + uint8_t rand_addr_type; uint8_t pseudo_addr[BLE_DEV_ADDR_LEN]; uint8_t rand_addr[BLE_DEV_ADDR_LEN]; uint8_t identity_addr[BLE_DEV_ADDR_LEN]; @@ -61,7 +62,7 @@ struct ble_hs_dev_records { /* Add a device to the resolving list */ int ble_hs_resolv_list_add(uint8_t *cmdbuf); -int ble_hs_gen_own_rpa_random(void); +int ble_hs_gen_own_private_rnd(void); uint8_t *ble_hs_get_rpa_local(void); /* Remove a device from the resolving list */ @@ -71,6 +72,8 @@ void ble_hs_resolv_list_clear_all(void); /* Address resolution enable command */ void ble_hs_resolv_enable(bool); +void ble_hs_resolv_nrpa_enable(void); +void ble_hs_resolv_nrpa_disable(void); /* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */ struct ble_hs_resolv_entry * diff --git a/porting/nimble/src/os_mempool.c b/porting/nimble/src/os_mempool.c index f4c712ff1..ba837e7d6 100644 --- a/porting/nimble/src/os_mempool.c +++ b/porting/nimble/src/os_mempool.c @@ -346,7 +346,8 @@ os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi) omi->omi_num_blocks = cur->mp_num_blocks; omi->omi_num_free = cur->mp_num_free; omi->omi_min_free = cur->mp_min_free; - strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name)); + strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name) - 1); + omi->omi_name[sizeof(omi->omi_name) - 1] = '\0'; return (cur); }