From 1022de21ca9eb62af86b2b59024b29bff17f29c8 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 1 Apr 2026 11:09:45 +0530 Subject: [PATCH] fix(nimble): Resolve host lock assert issue --- nimble/host/src/ble_att.c | 2 ++ nimble/host/src/ble_eatt.c | 14 ++++++++++++-- nimble/host/src/ble_gap.c | 24 ++++++++++++++++-------- nimble/host/src/ble_hs.c | 22 ++++++++++++++-------- nimble/host/src/ble_hs_conn.c | 14 ++++++++++---- nimble/host/src/ble_hs_hci_evt.c | 6 ++++++ nimble/host/src/ble_hs_id.c | 4 ++-- nimble/host/src/ble_hs_pvcy.c | 16 +++++++++++----- nimble/host/src/ble_hs_resolv.c | 2 +- nimble/host/src/ble_hs_resolv_priv.h | 2 +- nimble/host/src/ble_store_util.c | 28 ++++++++++++++++++++++++++-- 11 files changed, 101 insertions(+), 33 deletions(-) diff --git a/nimble/host/src/ble_att.c b/nimble/host/src/ble_att.c index 6f9889036..196ecdd0a 100644 --- a/nimble/host/src/ble_att.c +++ b/nimble/host/src/ble_att.c @@ -789,10 +789,12 @@ ble_att_get_default_bearer_cid(uint16_t conn_handle) { struct ble_hs_conn * conn; uint16_t default_cid = 0; + ble_hs_lock_nested(); conn = ble_hs_conn_find(conn_handle); if (conn != NULL) { default_cid = conn->default_cid; } + ble_hs_unlock_nested(); return default_cid; #endif diff --git a/nimble/host/src/ble_eatt.c b/nimble/host/src/ble_eatt.c index ef8b3ae6d..1a3f91500 100644 --- a/nimble/host/src/ble_eatt.c +++ b/nimble/host/src/ble_eatt.c @@ -550,8 +550,10 @@ uint16_t ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op) { uint16_t default_cid; + uint16_t cid; struct ble_eatt * eatt; + ble_hs_lock_nested(); default_cid = ble_att_get_default_bearer_cid(conn_handle); if (default_cid) { eatt = ble_eatt_find(conn_handle, default_cid); @@ -559,11 +561,16 @@ ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op) eatt = ble_eatt_find_not_busy(conn_handle); } if (!eatt) { - return BLE_L2CAP_CID_ATT; + cid = BLE_L2CAP_CID_ATT; + goto done; } eatt->client_op = op; - return eatt->chan->scid; + cid = eatt->chan->scid; + +done: + ble_hs_unlock_nested(); + return cid; } @@ -572,8 +579,10 @@ ble_eatt_release_chan(uint16_t conn_handle, uint8_t op) { struct ble_eatt *eatt; + ble_hs_lock_nested(); eatt = ble_eatt_find_by_conn_handle_and_busy_op(conn_handle, op); if (!eatt) { + ble_hs_unlock_nested(); BLE_EATT_LOG_DEBUG("ble_eatt_release_chan:" "EATT not found for conn_handle 0x%04x, operation 0x%02x\n", conn_handle, op); @@ -581,6 +590,7 @@ ble_eatt_release_chan(uint16_t conn_handle, uint8_t op) } eatt->client_op = 0; + ble_hs_unlock_nested(); } int diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 3e24e42b6..0176aa6b5 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -437,7 +437,9 @@ static void ble_gap_update_entry_free(struct ble_gap_update_entry *entry); static struct ble_gap_update_entry * ble_gap_update_entry_find(uint16_t conn_handle, struct ble_gap_update_entry **out_prev); +#endif +#if NIMBLE_BLE_CONNECT static void ble_gap_update_l2cap_cb(uint16_t conn_handle, int status, void *arg); #endif @@ -971,7 +973,7 @@ ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask, int ble_gap_get_local_used_addr(ble_addr_t *addr) { uint8_t own_addr_type = 0; - const uint8_t *out_id_addr; + uint8_t out_id_addr[BLE_DEV_ADDR_LEN]; int rc; if (addr == NULL) { @@ -980,7 +982,7 @@ int ble_gap_get_local_used_addr(ble_addr_t *addr) own_addr_type = ble_gap_slave[0].our_addr_type; - rc = ble_hs_id_addr(own_addr_type, &out_id_addr,NULL); + rc = ble_hs_id_copy_addr(own_addr_type, out_id_addr, NULL); if (rc == 0) { addr->type = own_addr_type; @@ -2466,8 +2468,10 @@ ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_ /* remove any sync_lost event from queue */ ble_npl_eventq_remove(ble_hs_evq_get(), &psync->lost_ev); - /* Free the memory occupied by psync as it is no longer needed */ + /* ble_hs_periodic_sync_free() requires host lock. */ + ble_hs_lock(); ble_hs_periodic_sync_free(psync); + ble_hs_unlock(); ble_gap_event_listener_call(&event); if (cb) { @@ -5383,8 +5387,10 @@ ble_gap_npl_sync_lost(struct ble_npl_event *ev) event.periodic_sync_lost.sync_handle = psync->sync_handle; event.periodic_sync_lost.reason = BLE_HS_EDONE; - /* Free the memory occupied by psync as it is no longer needed */ + /* ble_hs_periodic_sync_free() requires host lock. */ + ble_hs_lock(); ble_hs_periodic_sync_free(psync); + ble_hs_unlock(); ble_gap_event_listener_call(&event); if (cb) { @@ -8692,7 +8698,8 @@ ble_gap_reset_irk(void) ble_addr_t oldest_peer_id_addr[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; struct ble_store_value_local_irk value_local_irk; struct ble_store_key_local_irk key_local_irk; - uint8_t *local_id = NULL; + uint8_t local_id[BLE_DEV_ADDR_LEN]; + int have_local_id; int rc, num_peers; uint8_t tmp_addr[6]; @@ -8706,10 +8713,11 @@ ble_gap_reset_irk(void) memset(&key_local_irk, 0, sizeof key_local_irk); memset(&value_local_irk, 0x0, sizeof value_local_irk); - ble_hs_id_addr(BLE_ADDR_PUBLIC, (const uint8_t **) &local_id, NULL); + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, local_id, NULL); + have_local_id = (rc == 0); - if (local_id) { - memcpy (key_local_irk.addr.val , local_id, BLE_DEV_ADDR_LEN); + if (have_local_id) { + memcpy(key_local_irk.addr.val, local_id, BLE_DEV_ADDR_LEN); } key_local_irk.addr.type = BLE_ADDR_PUBLIC; diff --git a/nimble/host/src/ble_hs.c b/nimble/host/src/ble_hs.c index 9ab38eafd..e2be2f642 100644 --- a/nimble/host/src/ble_hs.c +++ b/nimble/host/src/ble_hs.c @@ -749,9 +749,15 @@ ble_hs_notifications_sched(void) void ble_hs_sched_reset(int reason) { - BLE_HS_DBG_ASSERT(ble_hs_reset_reason == 0); + ble_hs_lock_nested(); + if (ble_hs_reset_reason != 0) { + ble_hs_unlock_nested(); + return; + } ble_hs_reset_reason = reason; + ble_hs_unlock_nested(); + ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_reset); } @@ -933,6 +939,13 @@ ble_hs_init(void) ble_hs_reset_reason = 0; ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF; + rc = ble_npl_mutex_init(&ble_hs_mutex); + SYSINIT_PANIC_ASSERT(rc == 0); + +#if MYNEWT_VAL(BLE_HS_DEBUG) + ble_hs_dbg_mutex_locked = 0; +#endif + #if NIMBLE_BLE_CONNECT #if MYNEWT_VAL(BLE_GATTS) ble_npl_event_init(&ble_hs_ev_tx_notifications, ble_hs_event_tx_notify, @@ -1002,13 +1015,6 @@ ble_hs_init(void) STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_hs_stats), "ble_hs"); SYSINIT_PANIC_ASSERT(rc == 0); - rc = ble_npl_mutex_init(&ble_hs_mutex); - SYSINIT_PANIC_ASSERT(rc == 0); - -#if MYNEWT_VAL(BLE_HS_DEBUG) - ble_hs_dbg_mutex_locked = 0; -#endif - #ifdef MYNEWT ble_hs_evq_set((struct ble_npl_eventq *)os_eventq_dflt_get()); #else diff --git a/nimble/host/src/ble_hs_conn.c b/nimble/host/src/ble_hs_conn.c index 96e963117..17ebda2f2 100644 --- a/nimble/host/src/ble_hs_conn.c +++ b/nimble/host/src/ble_hs_conn.c @@ -78,7 +78,7 @@ ble_hs_conn_can_alloc(void) int result; - ble_hs_lock(); + ble_hs_lock_nested(); #if MYNEWT_VAL(BLE_GATTS) result = ble_hs_conn_pool.mp_num_free >= 1 && @@ -89,7 +89,7 @@ ble_hs_conn_can_alloc(void) ble_l2cap_chan_pool.mp_num_free >= BLE_HS_CONN_MIN_CHANS; #endif - ble_hs_unlock(); + ble_hs_unlock_nested(); return result; } @@ -504,13 +504,17 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn, addrs->our_id_addr.type == BLE_ADDR_RANDOM) { our_id_addr_val = conn->bhc_our_rnd_addr; } else { + ble_hs_lock_nested(); rc = ble_hs_id_addr(addrs->our_id_addr.type, &our_id_addr_val, NULL); + ble_hs_unlock_nested(); if (rc != 0) { return; } } #else + ble_hs_lock_nested(); rc = ble_hs_id_addr(addrs->our_id_addr.type, &our_id_addr_val, NULL); + ble_hs_unlock_nested(); if (rc != 0) { return; } @@ -535,14 +539,15 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn, memcpy(bhc_peer_addr.val, conn->bhc_peer_addr.val, BLE_DEV_ADDR_LEN); struct ble_hs_resolv_entry *rl = NULL; + ble_hs_lock_nested(); rl = ble_hs_resolv_list_find(bhc_peer_addr.val); if (rl != NULL) { memcpy(addrs->peer_id_addr.val, rl->rl_identity_addr, BLE_DEV_ADDR_LEN); addrs->peer_id_addr.type = rl->rl_addr_type; if (ble_host_rpa_enabled()) { - uint8_t *local_id = NULL; - rc = ble_hs_id_addr(BLE_ADDR_PUBLIC, (const uint8_t **) &local_id, NULL); + const uint8_t *local_id = NULL; + rc = ble_hs_id_addr(BLE_ADDR_PUBLIC, &local_id, NULL); /* RL is present: populate our id addr with public ID */ if (rc == 0 && local_id != NULL) { @@ -554,6 +559,7 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn, } } } + ble_hs_unlock_nested(); #endif switch (conn->bhc_peer_addr.type) { case BLE_ADDR_PUBLIC: diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index c5ce4cba5..82ac2322a 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -732,8 +732,10 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data, } struct ble_hs_resolv_entry *rl = NULL; + ble_hs_lock(); ble_rpa_replace_peer_params_with_rl(evt.peer_addr, &evt.peer_addr_type, &rl); + ble_hs_unlock(); #endif evt.conn_itvl = le16toh(ev->conn_itvl); evt.conn_latency = le16toh(ev->conn_latency); @@ -804,8 +806,10 @@ ble_hs_hci_evt_le_conn_complete(uint8_t subevent, const void *data, } struct ble_hs_resolv_entry *rl = NULL; + ble_hs_lock(); ble_rpa_replace_peer_params_with_rl(evt.peer_addr, &evt.peer_addr_type, &rl); + ble_hs_unlock(); #endif evt.conn_itvl = le16toh(ev->conn_itvl); evt.conn_latency = le16toh(ev->conn_latency); @@ -930,6 +934,7 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, const void *data, unsigned int len) #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) struct ble_hs_resolv_entry *rl = NULL; + ble_hs_lock(); rl = ble_hs_resolv_rpa_addr(desc.addr.val, desc.addr.type); if (rl != NULL) { @@ -939,6 +944,7 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, const void *data, unsigned int len) memcpy(desc.addr.val, rl->rl_identity_addr, BLE_DEV_ADDR_LEN); desc.addr.type = rl->rl_addr_type; } + ble_hs_unlock(); #endif desc.length_data = rpt->data_len; diff --git a/nimble/host/src/ble_hs_id.c b/nimble/host/src/ble_hs_id.c index 2ad9ba5b7..ebb3ba1fb 100644 --- a/nimble/host/src/ble_hs_id.c +++ b/nimble/host/src/ble_hs_id.c @@ -330,14 +330,14 @@ ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr, const uint8_t *addr; int rc; - ble_hs_lock(); + ble_hs_lock_nested(); rc = ble_hs_id_addr(id_addr_type, &addr, out_is_nrpa); if (rc == 0 && out_id_addr != NULL) { memcpy(out_id_addr, addr, 6); } - ble_hs_unlock(); + ble_hs_unlock_nested(); return rc; } diff --git a/nimble/host/src/ble_hs_pvcy.c b/nimble/host/src/ble_hs_pvcy.c index 6279ac88a..831da9682 100644 --- a/nimble/host/src/ble_hs_pvcy.c +++ b/nimble/host/src/ble_hs_pvcy.c @@ -192,7 +192,9 @@ ble_hs_pvcy_add_entry_hci(const uint8_t *addr, uint8_t addr_type, memcpy(cmd.peer_irk, irk, 16); #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) + ble_hs_lock_nested(); rc = ble_hs_resolv_list_add((uint8_t *) &cmd); + ble_hs_unlock_nested(); if (rc != 0) { return rc; } @@ -299,18 +301,20 @@ void ble_hs_pvcy_set_default_irk(void) struct ble_store_value_local_irk value_local_irk; struct ble_store_key_local_irk key_local_irk; - uint8_t *local_id = NULL; + uint8_t local_id[BLE_DEV_ADDR_LEN]; + bool have_local_id; int rc; memset(&key_local_irk, 0, sizeof key_local_irk); memset(&value_local_irk, 0x0, sizeof value_local_irk); - rc = ble_hs_id_addr(BLE_ADDR_PUBLIC, (const uint8_t **) &local_id, NULL); + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, local_id, NULL); + have_local_id = (rc == 0); /* Create key / value */ /* Some controllers give all 0s as address. Handle such case */ - if (local_id) { - memcpy (key_local_irk.addr.val , local_id, BLE_DEV_ADDR_LEN); + if (have_local_id) { + memcpy(key_local_irk.addr.val, local_id, BLE_DEV_ADDR_LEN); } key_local_irk.addr.type = BLE_ADDR_PUBLIC; @@ -350,7 +354,7 @@ void ble_hs_pvcy_set_default_irk(void) memcpy(&value_local_irk.irk, ble_hs_pvcy_default_irk, 16); - if (local_id) { + if (have_local_id) { memcpy(value_local_irk.addr.val, local_id, BLE_DEV_ADDR_LEN); } @@ -397,6 +401,7 @@ ble_hs_pvcy_set_our_irk(const uint8_t *irk) #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) if (irk != NULL) { + ble_hs_lock_nested(); bool rpa_state = false; if ((rpa_state = ble_host_rpa_enabled()) == true) { @@ -408,6 +413,7 @@ ble_hs_pvcy_set_our_irk(const uint8_t *irk) if (rpa_state) { ble_hs_resolv_enable(1); } + ble_hs_unlock_nested(); } #else rc = ble_hs_pvcy_set_resolve_enabled(0); diff --git a/nimble/host/src/ble_hs_resolv.c b/nimble/host/src/ble_hs_resolv.c index d6f24b874..9956c5ecf 100644 --- a/nimble/host/src/ble_hs_resolv.c +++ b/nimble/host/src/ble_hs_resolv.c @@ -131,7 +131,7 @@ ble_rpa_peer_dev_rec_clear_all(void) * NULL otherwise */ struct ble_hs_dev_records * -ble_rpa_find_peer_dev_rec(uint8_t *addr) +ble_rpa_find_peer_dev_rec(const uint8_t *addr) { struct ble_hs_dev_records *p_dev_rec = &peer_dev_rec[0]; int i; diff --git a/nimble/host/src/ble_hs_resolv_priv.h b/nimble/host/src/ble_hs_resolv_priv.h index 382ac82b8..370f5a7d5 100644 --- a/nimble/host/src/ble_hs_resolv_priv.h +++ b/nimble/host/src/ble_hs_resolv_priv.h @@ -98,7 +98,7 @@ struct ble_hs_dev_records *ble_rpa_get_peer_dev_records(void); int ble_rpa_get_num_peer_dev_records(void); void ble_rpa_set_num_peer_dev_records(int); int ble_rpa_remove_peer_dev_rec(struct ble_hs_dev_records *); -struct ble_hs_dev_records *ble_rpa_find_peer_dev_rec(uint8_t *); +struct ble_hs_dev_records *ble_rpa_find_peer_dev_rec(const uint8_t *); /* Set the resolvable private address timeout */ int ble_hs_resolv_set_rpa_tmo(uint16_t); diff --git a/nimble/host/src/ble_store_util.c b/nimble/host/src/ble_store_util.c index df49e1ee2..439ca7cbf 100644 --- a/nimble/host/src/ble_store_util.c +++ b/nimble/host/src/ble_store_util.c @@ -28,6 +28,18 @@ struct ble_store_util_peer_set { int status; }; +#if NIMBLE_BLE_CONNECT && MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) +static int +ble_store_util_lock_owned_by_cur_task(void) +{ +#if MYNEWT_VAL(BLE_HS_DEBUG) + return ble_hs_locked_by_cur_task(); +#else + return 0; +#endif +} +#endif + #if NIMBLE_BLE_CONNECT static int ble_store_util_iter_unique_peer(int obj_type, @@ -197,8 +209,14 @@ ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) } #if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY) - struct ble_hs_dev_records *peer_rec = - ble_rpa_find_peer_dev_rec(key.sec.peer_addr.val); + struct ble_hs_dev_records *peer_rec; + int needs_unlock; + + needs_unlock = !ble_store_util_lock_owned_by_cur_task(); + if (needs_unlock) { + ble_hs_lock(); + } + peer_rec = ble_rpa_find_peer_dev_rec(peer_id_addr->val); if (peer_rec != NULL) { rc = ble_hs_resolv_list_rmv(peer_rec->peer_sec.peer_addr.type, @@ -210,9 +228,15 @@ ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) rc = ble_rpa_remove_peer_dev_rec(peer_rec); if (rc != 0) { + if (needs_unlock) { + ble_hs_unlock(); + } return rc; } } + if (needs_unlock) { + ble_hs_unlock(); + } #endif return 0;