fix(nimble): Defer events / requests from stack until connection event is sent to GAP layer

This commit is contained in:
Rahul Tank
2026-07-02 14:53:47 +05:30
parent bdc5010548
commit d750d6baeb
13 changed files with 1270 additions and 57 deletions
+104 -4
View File
@@ -22,6 +22,10 @@
#include "ble_hs_priv.h"
#include "host/ble_att.h"
#include "host/ble_hs_log.h"
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
#include "host/ble_gap.h"
#include "esp_nimble_mem.h"
#endif
#if NIMBLE_BLE_CONNECT
@@ -547,10 +551,9 @@ ble_att_rx_handle_unknown_request(uint8_t op, uint16_t conn_handle,
}
#if MYNEWT_VAL(BLE_GATTS)
os_mbuf_adj(*om, OS_MBUF_PKTLEN(*om));
if (ble_att_svr_tx_error_rsp(conn_handle, cid, *om, op, 0,
BLE_ATT_ERR_REQ_NOT_SUPPORTED) == 0) {
*om = NULL;
}
ble_att_svr_tx_error_rsp(conn_handle, cid, *om, op, 0,
BLE_ATT_ERR_REQ_NOT_SUPPORTED);
*om = NULL;
#else
os_mbuf_free_chain(*om);
*om = NULL;
@@ -576,7 +579,11 @@ ble_att_send_outstanding_after_response(uint16_t conn_handle)
ble_hs_unlock();
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
int
#else
static int
#endif
ble_att_rx_extended(uint16_t conn_handle, uint16_t cid, struct os_mbuf **om)
{
const struct ble_att_rx_dispatch_entry *entry;
@@ -585,6 +592,99 @@ ble_att_rx_extended(uint16_t conn_handle, uint16_t cid, struct os_mbuf **om)
BLE_HS_DBG_ASSERT(*om != NULL);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
{
struct ble_hs_conn *conn;
ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
if (conn != NULL && !conn->bhc_connect_delivered) {
struct ble_att_deferred_req *req;
bool defer_ok = true;
if ((conn->bhc_deferred_event_cnt + conn->bhc_deferred_att_cnt) >=
BLE_HS_CONN_DEFERRED_EVENT_MAX) {
defer_ok = false;
BLE_HS_LOG(ERROR,
"ble_att_rx_extended: defer queue full; conn=%u cid=%u\n",
conn_handle, cid);
}
ble_hs_unlock();
if (defer_ok) {
req = nimble_platform_mem_calloc(1, sizeof(*req));
if (req == NULL) {
BLE_HS_LOG(ERROR,
"ble_att_rx_extended: defer alloc failed; conn=%u cid=%u\n",
conn_handle, cid);
} else {
ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
if (conn == NULL) {
ble_hs_unlock();
nimble_platform_mem_free(req);
return BLE_HS_ENOTCONN;
} else if (conn->bhc_connect_delivered) {
ble_hs_unlock();
nimble_platform_mem_free(req);
goto process_att_normally;
} else if ((conn->bhc_deferred_event_cnt +
conn->bhc_deferred_att_cnt) >=
BLE_HS_CONN_DEFERRED_EVENT_MAX) {
ble_hs_unlock();
nimble_platform_mem_free(req);
BLE_HS_LOG(ERROR,
"ble_att_rx_extended: defer queue full post-alloc; "
"conn=%u cid=%u\n",
conn_handle, cid);
} else {
req->cid = cid;
req->om = *om;
req->seq = conn->bhc_deferred_seq++;
STAILQ_INSERT_TAIL(&conn->bhc_deferred_att_reqs, req, next);
conn->bhc_deferred_att_cnt++;
*om = NULL;
ble_hs_unlock();
return 0;
}
}
}
rc = os_mbuf_copydata(*om, 0, 1, &op);
if (rc != 0) {
return BLE_HS_EMSGSIZE;
}
/*
* Defer queue is full or allocation failed. Respond on the wire
* for ATT requests; drop everything else. Either way the
* application is not invoked so CONNECT stays first.
*/
if (cid == BLE_L2CAP_CID_ATT && ble_att_is_request_op(op)) {
#if MYNEWT_VAL(BLE_GATTS)
os_mbuf_adj(*om, OS_MBUF_PKTLEN(*om));
ble_att_svr_tx_error_rsp(conn_handle, cid, *om, op, 0,
BLE_ATT_ERR_INSUFFICIENT_RES);
*om = NULL;
#endif
if (*om != NULL) {
os_mbuf_free_chain(*om);
*om = NULL;
}
} else {
/* Notifications, write commands, EATT ops, etc. */
os_mbuf_free_chain(*om);
*om = NULL;
}
return 0;
} else {
ble_hs_unlock();
}
}
process_att_normally:
#endif
rc = os_mbuf_copydata(*om, 0, 1, &op);
if (rc != 0) {
return BLE_HS_EMSGSIZE;
+3
View File
@@ -182,6 +182,9 @@ void ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan,
void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu);
uint16_t ble_att_chan_mtu(const struct ble_l2cap_chan *chan);
uint16_t ble_att_mtu_by_cid(uint16_t conn_handle, uint16_t cid);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
int ble_att_rx_extended(uint16_t conn_handle, uint16_t cid, struct os_mbuf **om);
#endif
int ble_att_init(void);
void ble_att_deinit(void);
/*** @svr */
+803 -22
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -35,6 +35,7 @@ struct hci_disconn_complete;
struct hci_encrypt_change;
struct ble_hs_hci_ack;
struct ble_hs_adv;
struct ble_hs_conn;
STATS_SECT_START(ble_gap_stats)
STATS_SECT_ENTRY(wl_set)
@@ -97,6 +98,10 @@ void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc);
void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used_feat *ev);
void ble_gap_rx_rd_rem_ver_info_complete(const struct ble_hci_ev_rd_rem_ver_info_cmp *ev);
void ble_gap_event_connect_call(uint16_t conn_handle, int status);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && NIMBLE_BLE_CONNECT
void ble_gap_conn_deferred_init(struct ble_hs_conn *conn);
void ble_gap_conn_deferred_cleanup(struct ble_hs_conn *conn);
#endif
#if MYNEWT_VAL(BLE_CONN_SUBRATING)
void ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev);
#endif
+8
View File
@@ -2222,7 +2222,11 @@ ble_gattc_cache_conn_get_svc_changed_handle(uint16_t conn_handle)
peer = ble_gattc_cache_conn_find(conn_handle);
if (peer == NULL) {
BLE_HS_LOG(ERROR, "Cannot find connection with conn_handle %d", conn_handle);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
return 0;
#else
return -1;
#endif
}
/* Check if attr_handle is of service change char */
@@ -2231,7 +2235,11 @@ ble_gattc_cache_conn_get_svc_changed_handle(uint16_t conn_handle)
if (chr == NULL) {
BLE_HS_LOG(DEBUG, "Cannot find service change characteristic");
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
return 0;
#else
return -1;
#endif
}
return chr->chr.val_handle;
}
+13
View File
@@ -207,6 +207,15 @@ ble_hs_conn_alloc(uint16_t conn_handle)
memset(conn, 0, sizeof *conn);
conn->bhc_handle = conn_handle;
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
STAILQ_INIT(&conn->bhc_deferred_events);
conn->bhc_deferred_event_cnt = 0;
conn->bhc_deferred_att_cnt = 0;
conn->bhc_deferred_seq = 0;
STAILQ_INIT(&conn->bhc_deferred_att_reqs);
ble_gap_conn_deferred_init(conn);
#endif
SLIST_INIT(&conn->bhc_channels);
chan = ble_att_create_chan(conn_handle);
@@ -323,6 +332,10 @@ ble_hs_conn_free(struct ble_hs_conn *conn)
os_mbuf_free_chain(OS_MBUF_PKTHDR_TO_MBUF(omp));
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && NIMBLE_BLE_CONNECT
ble_gap_conn_deferred_cleanup(conn);
#endif
#if MYNEWT_VAL(BLE_HS_DEBUG)
memset(conn, 0xff, sizeof *conn);
#endif
+48
View File
@@ -38,6 +38,37 @@ typedef uint8_t ble_hs_conn_flags_t;
#define BLE_HS_CONN_F_TERMINATING 0x02
#define BLE_HS_CONN_F_TX_FRAG 0x04 /* Cur ACL packet partially txed. */
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
#include "host/ble_gap.h"
/**
* GAP event deferred until BLE_GAP_EVENT_CONNECT has been delivered.
* Queued on ble_hs_conn.bhc_deferred_events.
*/
struct ble_gap_deferred_event {
STAILQ_ENTRY(ble_gap_deferred_event) next;
uint16_t seq;
struct ble_gap_event event;
uint8_t enc_security_restored;
uint8_t enc_bonded;
struct ble_gap_upd_params upd_peer;
struct ble_gap_upd_params upd_self;
};
/**
* L2CAP ATT payload deferred until BLE_GAP_EVENT_CONNECT has been delivered.
* Queued on ble_hs_conn.bhc_deferred_att_reqs.
*/
struct ble_att_deferred_req {
STAILQ_ENTRY(ble_att_deferred_req) next;
struct os_mbuf *om;
uint16_t cid;
uint16_t seq;
};
#define BLE_HS_CONN_DEFERRED_EVENT_MAX 64
#endif
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
#define BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN_REM \
((MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) % (8 * sizeof(uint32_t))) ? 1 : 0)
@@ -51,6 +82,23 @@ struct ble_hs_conn {
SLIST_ENTRY(ble_hs_conn) bhc_next;
uint8_t bhc_our_addr_type;
uint8_t slave_conn : 1;
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
uint8_t bhc_connect_delivered : 1;
uint8_t bhc_deferred_draining : 1;
uint8_t bhc_deferred_inited : 1;
uint8_t bhc_deferred_event_cnt;
uint8_t bhc_deferred_att_cnt;
uint16_t bhc_deferred_seq;
STAILQ_HEAD(, ble_gap_deferred_event) bhc_deferred_events;
STAILQ_HEAD(, ble_att_deferred_req) bhc_deferred_att_reqs;
struct ble_npl_event bhc_deferred_drain_ev;
#if MYNEWT_VAL(BLE_HS_PVCY) && !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
uint8_t bhc_deferred_pvcy_add;
uint8_t bhc_deferred_pvcy_replace;
ble_addr_t bhc_deferred_pvcy_addr;
uint8_t bhc_deferred_pvcy_irk[16];
#endif
#endif
#if MYNEWT_VAL(BLE_EXT_ADV)
uint8_t bhc_our_rnd_addr[6];
#endif
+87
View File
@@ -125,17 +125,57 @@ void ble_hs_reset_rpa_timeout(void)
}
#if (!MYNEWT_VAL(BLE_HOST_BASED_PRIVACY))
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
static uint8_t ble_hs_pvcy_resolve_en;
#endif
int
ble_hs_pvcy_set_resolve_enabled(int enable)
{
struct ble_hci_le_set_addr_res_en_cp cmd;
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
int rc;
cmd.enable = !!enable;
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_SET_ADDR_RES_EN),
&cmd, sizeof(cmd), NULL, 0);
if (rc == 0) {
ble_hs_pvcy_resolve_en = cmd.enable;
}
return rc;
#else
cmd.enable = enable;
return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_SET_ADDR_RES_EN),
&cmd, sizeof(cmd), NULL, 0);
#endif
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
static void
ble_hs_pvcy_restore_resolve_if_needed(uint8_t was_enabled)
{
int rc_en;
if (!was_enabled) {
return;
}
rc_en = BLE_HS_EUNKNOWN;
for (int i = 0; i < 3 && rc_en != 0; i++) {
rc_en = ble_hs_pvcy_set_resolve_enabled(1);
}
if (rc_en != 0) {
BLE_HS_LOG(ERROR,
"ble_hs_pvcy: address resolution restore failed after "
"retries; privacy broken\n");
}
}
#endif
#endif
int
@@ -227,6 +267,41 @@ ble_hs_pvcy_add_entry_hci(const uint8_t *addr, uint8_t addr_type,
return 0;
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
int
ble_hs_pvcy_replace_entry(const uint8_t *addr, uint8_t addr_type,
const uint8_t *irk)
{
#if (MYNEWT_VAL(BLE_HOST_BASED_PRIVACY))
(void)ble_hs_pvcy_remove_entry(addr_type, addr);
return ble_hs_pvcy_add_entry(addr, addr_type, irk);
#else
int rc;
uint8_t resolve_was_en;
STATS_INC(ble_hs_stats, pvcy_add_entry);
ble_gap_preempt();
resolve_was_en = ble_hs_pvcy_resolve_en;
rc = ble_hs_pvcy_set_resolve_enabled(0);
if (rc == 0) {
(void)ble_hs_pvcy_remove_entry(addr_type, addr);
rc = ble_hs_pvcy_add_entry_hci(addr, addr_type, irk);
ble_hs_pvcy_restore_resolve_if_needed(resolve_was_en);
}
ble_gap_preempt_done();
if (rc != 0) {
STATS_INC(ble_hs_stats, pvcy_add_entry_fail);
}
return rc;
#endif
}
#endif /* MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) */
int
ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type,
const uint8_t *irk)
@@ -244,8 +319,20 @@ ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type,
#else
ble_gap_preempt();
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
uint8_t resolve_was_en;
resolve_was_en = ble_hs_pvcy_resolve_en;
rc = ble_hs_pvcy_set_resolve_enabled(0);
if (rc == 0) {
/* Try to add the entry now that GAP is halted and address resolution is disabled. */
rc = ble_hs_pvcy_add_entry_hci(addr, addr_type, irk);
ble_hs_pvcy_restore_resolve_if_needed(resolve_was_en);
}
#else
/* Try to add the entry now that GAP is halted. */
rc = ble_hs_pvcy_add_entry_hci(addr, addr_type, irk);
#endif
/* Allow GAP procedures to be started again. */
ble_gap_preempt_done();
+4
View File
@@ -39,6 +39,10 @@ int ble_hs_pvcy_our_irk(const uint8_t **out_irk);
int ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr);
int ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addrtype,
const uint8_t *irk);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
int ble_hs_pvcy_replace_entry(const uint8_t *addr, uint8_t addr_type,
const uint8_t *irk);
#endif
int ble_hs_pvcy_ensure_started(void);
int ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode);
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
+57
View File
@@ -996,6 +996,22 @@ ble_sm_chk_repeat_pairing(uint16_t conn_handle,
int rc;
do {
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
int defer_repeat_chk;
defer_repeat_chk = 0;
ble_hs_lock();
{
struct ble_hs_conn *conn;
conn = ble_hs_conn_find(conn_handle);
if (conn != NULL && !conn->bhc_connect_delivered) {
defer_repeat_chk = 1;
}
}
ble_hs_unlock();
#endif
/* If the peer isn't bonded, indicate that the pairing procedure should
* continue.
*/
@@ -1009,6 +1025,25 @@ ble_sm_chk_repeat_pairing(uint16_t conn_handle,
return rc;
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
/*
* Repeat pairing needs a synchronous app decision and cannot be
* deferred. Reject pairing from bonded peers until CONNECT is
* delivered so the bond is not overwritten without consent.
*/
if (defer_repeat_chk) {
struct ble_hs_conn *conn;
ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
if (conn != NULL && !conn->bhc_connect_delivered) {
ble_hs_unlock();
return BLE_HS_EBUSY;
}
ble_hs_unlock();
}
#endif
/* Peer is already bonded. Ask the application what to do about it. */
rp.conn_handle = conn_handle;
rp.cur_key_size = bond.key_size;
@@ -1122,7 +1157,12 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res,
ble_sm_persist_keys(proc);
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
if (res->enc_cb &&
res->app_status != BLE_HS_ENOTCONN) {
#else
if (res->enc_cb) {
#endif
BLE_HS_DBG_ASSERT(proc == NULL || rm);
ble_gap_enc_event(conn_handle, res->app_status, res->restore, res->bonded);
}
@@ -2081,6 +2121,13 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
/* The app indicated that the pairing request should be ignored. */
res->app_status = rc;
res->execute = 0;
if (rc == BLE_HS_EBUSY) {
/*
* CONNECT not yet delivered; send Pairing Failed so the peer
* does not sit in SMP until the 30 s timer expires.
*/
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
}
}
}
}
@@ -2885,12 +2932,22 @@ ble_sm_incr_peer_sign_counter(uint16_t conn_handle)
}
#if MYNEWT_VAL(BLE_HS_PVCY)
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
/*
* Only the sign counter is being bumped; the IRK is unchanged.
* The controller resolving list stores the IRK, not the sign counter,
* so there is no reason to remove and re-add the entry here.
* ble_store_write_peer_sec will update the resolving list entry at
* disconnect (deferred path) or immediately if the peer is not connected.
*/
#else
if (value_sec.irk_present == 1) {
ble_hs_pvcy_remove_entry(value_sec.peer_addr.type, value_sec.peer_addr.val);
/* No need to check if the above command fails or passes.
* Proceed with trying to write the new sign counter.
*/
}
#endif
#endif
value_sec.sign_counter += 1;
+61 -2
View File
@@ -283,6 +283,20 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec)
#if NIMBLE_BLE_CONNECT && MYNEWT_VAL(BLE_SM_SC)
int rc;
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) && MYNEWT_VAL(BLE_HS_PVCY)
struct ble_store_key_sec key_sec;
struct ble_store_value_sec old_sec;
int replace_entry;
replace_entry = 0;
if (ble_addr_cmp(&value_sec->peer_addr, BLE_ADDR_ANY) &&
value_sec->irk_present) {
memset(&key_sec, 0, sizeof key_sec);
key_sec.peer_addr = value_sec->peer_addr;
rc = ble_store_read_peer_sec(&key_sec, &old_sec);
replace_entry = rc == 0 && old_sec.irk_present;
}
#endif /* BLE_DEFER_CONN_EVENTS && BLE_HS_PVCY */
rc = ble_store_persist_sec(BLE_STORE_OBJ_TYPE_PEER_SEC, value_sec);
if (rc != 0) {
@@ -292,11 +306,56 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec)
if (ble_addr_cmp(&value_sec->peer_addr, BLE_ADDR_ANY) &&
value_sec->irk_present) {
#if MYNEWT_VAL(BLE_HS_PVCY)
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
/* Do not update the controller resolving list while this peer is still
* connected. The bond is already persisted for the current link, and
* some controllers reject LE Add Device To Resolving List in this
* state even when GAP is preempted.
*/
#if !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
ble_hs_lock();
struct ble_hs_conn *conn = ble_hs_conn_find_by_addr(&value_sec->peer_addr);
if (conn != NULL) {
conn->bhc_deferred_pvcy_add = 1;
conn->bhc_deferred_pvcy_replace = replace_entry;
conn->bhc_deferred_pvcy_addr = value_sec->peer_addr;
memcpy(conn->bhc_deferred_pvcy_irk, value_sec->irk,
sizeof conn->bhc_deferred_pvcy_irk);
ble_hs_unlock();
return 0;
}
ble_hs_unlock();
#endif
/* Write the peer IRK to the controller keycache
* There is not much to do here if it fails */
if (replace_entry) {
rc = ble_hs_pvcy_replace_entry(value_sec->peer_addr.val,
value_sec->peer_addr.type,
value_sec->irk);
} else {
rc = ble_hs_pvcy_add_entry(value_sec->peer_addr.val,
value_sec->peer_addr.type,
value_sec->irk);
if (rc == BLE_HS_EINVAL ||
rc == BLE_HS_HCI_ERR(BLE_ERR_CMD_DISALLOWED) ||
rc == BLE_HS_HCI_ERR(BLE_ERR_INV_HCI_CMD_PARMS)) {
/* Entry already present in resolving list; replace it.
* Occurs when the store entry was deleted and re-written
* without first removing the resolving list entry (e.g.
* sign-counter increment with BLE_HOST_BASED_PRIVACY=1). */
rc = ble_hs_pvcy_replace_entry(value_sec->peer_addr.val,
value_sec->peer_addr.type,
value_sec->irk);
}
}
#else
/* Write the peer IRK to the controller keycache
* There is not much to do here if it fails */
rc = ble_hs_pvcy_add_entry(value_sec->peer_addr.val,
value_sec->peer_addr.type,
value_sec->irk);
value_sec->peer_addr.type,
value_sec->irk);
#endif /* MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) */
if (rc != 0) {
return rc;
}
+21 -1
View File
@@ -110,10 +110,18 @@ ble_hs_pvcy_test_util_add_irk_set_acks(bool scanning, bool connecting)
0);
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
ble_hs_test_util_hci_ack_append(
BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN), 0);
#endif
ble_hs_test_util_hci_ack_append(
BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), 0);
ble_hs_test_util_hci_ack_append(
BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PRIVACY_MODE), 0);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
ble_hs_test_util_hci_ack_append(
BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN), 0);
#endif
}
static void
@@ -167,6 +175,12 @@ ble_hs_pvcy_test_util_add_irk_verify_tx(const ble_addr_t *peer_addr,
NULL);
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_SET_ADDR_RES_EN,
NULL);
#endif
ble_hs_test_util_hci_verify_tx_add_irk(peer_addr->type,
peer_addr->val,
peer_irk,
@@ -175,6 +189,12 @@ ble_hs_pvcy_test_util_add_irk_verify_tx(const ble_addr_t *peer_addr,
ble_hs_test_util_hci_verify_tx_set_priv_mode(peer_addr->type,
peer_addr->val,
BLE_GAP_PRIVATE_MODE_DEVICE);
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_SET_ADDR_RES_EN,
NULL);
#endif
}
static void
@@ -192,7 +212,7 @@ ble_hs_pvcy_test_util_add_irk(const ble_addr_t *peer_addr,
rc = ble_hs_pvcy_add_entry(peer_addr->val, peer_addr->type, peer_irk);
TEST_ASSERT_FATAL(rc == 0);
num_acks = 3;
num_acks = MYNEWT_VAL(BLE_DEFER_CONN_EVENTS) ? 5 : 3;
if (scanning) {
num_acks++;
}
+56 -28
View File
@@ -42,6 +42,7 @@
portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED;
static SemaphoreHandle_t npl_eventq_sync;
static uint8_t hw_critical_state_status[portNUM_PROCESSORS];
#if CONFIG_BT_NIMBLE_USE_ESP_TIMER
static const char *TAG = "Timer";
@@ -357,25 +358,35 @@ static void
npl_eventq_sync_init(void)
{
if (npl_eventq_sync == NULL) {
npl_eventq_sync = xSemaphoreCreateMutex();
npl_eventq_sync = xSemaphoreCreateRecursiveMutex();
BLE_LL_ASSERT(npl_eventq_sync);
}
}
static void
static bool
npl_eventq_lock(void)
{
if (!in_isr()) {
BLE_LL_ASSERT(npl_eventq_sync);
xSemaphoreTake(npl_eventq_sync, portMAX_DELAY);
BaseType_t core;
if (in_isr()) {
return false;
}
core = xPortGetCoreID();
if (core >= portNUM_PROCESSORS || hw_critical_state_status[core] != 0) {
return false;
}
BLE_LL_ASSERT(npl_eventq_sync);
xSemaphoreTakeRecursive(npl_eventq_sync, portMAX_DELAY);
return true;
}
static void
npl_eventq_unlock(void)
npl_eventq_unlock(bool locked)
{
if (!in_isr()) {
xSemaphoreGive(npl_eventq_sync);
if (locked) {
xSemaphoreGiveRecursive(npl_eventq_sync);
}
}
@@ -485,7 +496,8 @@ npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo)
}
}
} else if (tmo == 0) {
npl_eventq_lock();
bool locked = npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) {
@@ -495,7 +507,7 @@ npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo)
}
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
npl_eventq_unlock(locked);
} else {
TickType_t deadline = 0;
TickType_t remaining;
@@ -518,7 +530,8 @@ npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo)
return NULL;
}
npl_eventq_lock();
bool locked = npl_eventq_lock();
portENTER_CRITICAL(&ble_port_mutex);
ret = xQueueReceive(eventq->q, &ev, 0);
if (ret == pdPASS && ev != NULL) {
@@ -526,12 +539,13 @@ npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo)
if (event) {
event->queued = false;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
break;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
if (ret == pdPASS && ev != NULL) {
npl_eventq_unlock(locked);
break;
}
npl_eventq_unlock(locked);
}
}
@@ -561,10 +575,10 @@ npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_event *ev)
}
return;
} else {
npl_eventq_lock();
bool locked = npl_eventq_lock();
if (npl_eventq_queued_claim(event)) {
npl_eventq_unlock();
npl_eventq_unlock(locked);
return;
}
@@ -573,7 +587,7 @@ npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_event *ev)
ESP_LOGW("NimBLE", "eventq put: queue full, event dropped");
npl_eventq_queued_set_task(event, false);
}
npl_eventq_unlock();
npl_eventq_unlock(locked);
}
}
@@ -637,9 +651,10 @@ npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
} else {
removed = false;
npl_eventq_lock();
bool locked = npl_eventq_lock();
if (!npl_eventq_queued_get_task(event)) {
npl_eventq_unlock();
npl_eventq_unlock(locked);
return;
}
@@ -663,11 +678,10 @@ npl_freertos_eventq_remove(struct ble_npl_eventq *evq,
}
}
if (removed) {
event->queued = 0;
event->queued = false;
}
portEXIT_CRITICAL(&ble_port_mutex);
npl_eventq_unlock();
npl_eventq_unlock(locked);
}
}
@@ -1341,26 +1355,40 @@ npl_freertos_hw_set_isr(int irqn, uint32_t addr)
#endif
uint8_t hw_critical_state_status = 0;
uint32_t
npl_freertos_hw_enter_critical(void)
{
++hw_critical_state_status;
BaseType_t core;
portENTER_CRITICAL(&ble_port_mutex);
core = xPortGetCoreID();
if (core < portNUM_PROCESSORS) {
++hw_critical_state_status[core];
}
return 0;
}
uint8_t
npl_freertos_hw_is_in_critical(void)
{
return hw_critical_state_status;
BaseType_t core;
core = xPortGetCoreID();
if (core >= portNUM_PROCESSORS) {
return 0;
}
return hw_critical_state_status[core];
}
void
npl_freertos_hw_exit_critical(uint32_t ctx)
{
--hw_critical_state_status;
BaseType_t core;
core = xPortGetCoreID();
if (core < portNUM_PROCESSORS && hw_critical_state_status[core] > 0) {
--hw_critical_state_status[core];
}
portEXIT_CRITICAL(&ble_port_mutex);
}