mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-10-02 21:27:22 +00:00
fix(nimble): Defer events / requests from stack until connection event is sent to GAP layer
This commit is contained in:
+104
-4
@@ -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;
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user