From a9a4c701981b86c91fdc63fce4cb7bc05c69caac Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 10 Feb 2025 15:02:05 +0530 Subject: [PATCH] fix(nimble): Handle not sending disconnect in slave role if connect was not sent --- nimble/host/src/ble_gap.c | 35 +++++++++--- nimble/host/src/ble_hs_hci_evt.c | 93 ++++++++++++++++++-------------- 2 files changed, 79 insertions(+), 49 deletions(-) diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index f19ff1f60..681ff9b4a 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -292,6 +292,7 @@ static uint8_t pawr_adv_handle; static uint16_t pawr_sync_handle; #endif +int slave_conn[MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1]; static void ble_gap_update_entry_free(struct ble_gap_update_entry *entry); #if NIMBLE_BLE_CONNECT @@ -1524,6 +1525,8 @@ ble_gap_conn_broken(uint16_t conn_handle, int reason) struct ble_gap_update_entry *entry; struct ble_gap_snapshot snap; struct ble_gap_event event; + struct ble_hs_conn *conn; + bool send = 1; int rc; memset(&event, 0, sizeof event); @@ -1560,6 +1563,19 @@ ble_gap_conn_broken(uint16_t conn_handle, int reason) #endif ble_hs_flow_connection_broken(conn_handle);; + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + ble_hs_unlock(); + + // Send disconnect event in slave role if connect was sent + if ((conn != NULL) && !(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { + if (slave_conn[conn_handle]) { + slave_conn[conn_handle] = 0; + } else { + send = 0; + } + } + ble_hs_atomic_conn_delete(conn_handle); g_max_tx_time[conn_handle] = 0; @@ -1570,8 +1586,10 @@ ble_gap_conn_broken(uint16_t conn_handle, int reason) event.type = BLE_GAP_EVENT_DISCONNECT; event.disconnect.reason = reason; - ble_gap_event_listener_call(&event); - ble_gap_call_event_cb(&event, snap.cb, snap.cb_arg); + if (send) { + ble_gap_event_listener_call(&event); + ble_gap_call_event_cb(&event, snap.cb, snap.cb_arg); + } STATS_INC(ble_gap_stats, disconnect); #endif @@ -2740,16 +2758,16 @@ ble_gap_link_estab_call(uint16_t conn_handle, int status) event.link_estab.conn_handle = handle; #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) - event.link_estab.sync_handle = pawr_sync_handle; - event.link_estab.adv_handle = pawr_adv_handle; + event.link_estab.sync_handle = pawr_sync_handle; + event.link_estab.adv_handle = pawr_adv_handle; #endif - ble_gap_event_listener_call(&event); - ble_gap_call_conn_event_cb(&event, handle); + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, handle); #if !SOC_ESP_NIMBLE_CONTROLLER - ble_hs_hci_util_set_data_len(le16toh(conn_handle), BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX, - BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX); + ble_hs_hci_util_set_data_len(le16toh(conn_handle), BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX, + BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX); #endif } @@ -2772,6 +2790,7 @@ ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used if ((conn != NULL) && (ev->status == 0)) { conn->supported_feat = get_le32(ev->features); ble_gap_link_estab_call(ev->conn_handle, ev->status); + slave_conn[ev->conn_handle] = 1; } } #endif diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index 3d7699d1f..b03a6f993 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -35,6 +35,7 @@ struct ble_gap_reattempt_ctxt { extern int ble_gap_master_connect_reattempt(uint16_t conn_handle); extern int ble_gap_slave_adv_reattempt(void); +extern int slave_conn[MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1]; #endif #if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) @@ -247,58 +248,68 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data, ble_hs_unlock(); #if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) - if (conn && ev->reason == BLE_ERR_CONN_ESTABLISHMENT) { + if (conn) { uint16_t handle; - int rc; + int rc; - if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { //slave - BLE_HS_LOG(INFO, "Reattempt advertising; reason: 0x%x, status = %x", - ev->reason, ev->status); + /* For master role, check if failure reason is 0x3E, to restart connect attempt + * For slave role, check whether + * a. Failure reason is 0x3E + * b. Connect event was not posted and 0x8 was received + * Restart advertising in above reasons for slave. + */ - ble_l2cap_sig_conn_broken(ev->conn_handle, BLE_ERR_CONN_ESTABLISHMENT); - ble_sm_connection_broken(ev->conn_handle); - ble_gatts_connection_broken(ev->conn_handle); - ble_gattc_connection_broken(ev->conn_handle); - ble_hs_flow_connection_broken(ev->conn_handle);; -#if MYNEWT_VAL(BLE_GATT_CACHING) - ble_gattc_cache_conn_broken(ev->conn_handle); -#endif - rc = ble_hs_atomic_conn_delete(ev->conn_handle); - if (rc != 0) { - return rc; - } - - rc = ble_gap_slave_adv_reattempt(); - if (rc != 0) { - BLE_HS_LOG(INFO, "Adv reattempt failed; rc= %d ", rc); - } - - return 0; // Restart advertising, so don't post disconnect event - - } else { // master - if (reattempt_conn.count < MAX_REATTEMPT_ALLOWED) { - /* Got for connection */ + if ((conn->bhc_flags & BLE_HS_CONN_F_MASTER) && \ + (ev->reason == BLE_ERR_CONN_ESTABLISHMENT)) { // master + if (reattempt_conn.count < MAX_REATTEMPT_ALLOWED) { + /* Go for connection */ BLE_HS_LOG(INFO, "Reattempt connection; reason = 0x%x, status = %d," - "reattempt count = %d ", ev->reason, ev->status, - reattempt_conn.count); + "reattempt count = %d ", ev->reason, ev->status, + reattempt_conn.count); reattempt_conn.count += 1; - handle = le16toh(ev->conn_handle); - /* Post event to interested application */ - ble_gap_reattempt_count(handle, reattempt_conn.count); + handle = le16toh(ev->conn_handle); + /* Post event to interested application */ + ble_gap_reattempt_count(handle, reattempt_conn.count); rc = ble_gap_master_connect_reattempt(ev->conn_handle); - if (rc != 0) { - BLE_HS_LOG(INFO, "Master reconnect attempt failed; rc = %d", rc); - } - } else { - /* Exhausted attempts */ - memset(&reattempt_conn, 0x0, sizeof (struct ble_gap_reattempt_ctxt)); + if (rc != 0) { + BLE_HS_LOG(INFO, "Master reconnect attempt failed; rc = %d", rc); + } + } else { + /* Exhausted attempts */ + memset(&reattempt_conn, 0x0, sizeof (struct ble_gap_reattempt_ctxt)); + } + } + else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER) && \ + ((ev->reason == BLE_ERR_CONN_ESTABLISHMENT) || \ + (!slave_conn[ev->conn_handle] && ev->reason == BLE_ERR_CONN_SPVN_TMO))) { //slave + + BLE_HS_LOG(INFO, "Reattempt advertising; reason: 0x%x, status = %x", + ev->reason, ev->status); + ble_l2cap_sig_conn_broken(ev->conn_handle, BLE_ERR_CONN_ESTABLISHMENT); + ble_sm_connection_broken(ev->conn_handle); + ble_gatts_connection_broken(ev->conn_handle); + ble_gattc_connection_broken(ev->conn_handle); + ble_hs_flow_connection_broken(ev->conn_handle);; +#if MYNEWT_VAL(BLE_GATT_CACHING) + ble_gattc_cache_conn_broken(ev->conn_handle); +#endif + rc = ble_hs_atomic_conn_delete(ev->conn_handle); + if (rc != 0) { + return rc; } - } - } else { + + rc = ble_gap_slave_adv_reattempt(); + if (rc != 0) { + BLE_HS_LOG(INFO, "Adv reattempt failed; rc= %d ", rc); + } + + return 0; // Restart advertising, so don't post disconnect event + } else { /* Normal disconnect. Reset the structure */ memset(&reattempt_conn, 0x0, sizeof (struct ble_gap_reattempt_ctxt)); + } } #endif