mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-10-04 22:07:22 +00:00
fix(nimble): recover PAwR connect timeout and V2 handle routing
This commit is contained in:
@@ -3282,10 +3282,12 @@ int ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
|
||||
* @param peer_addr The address of the peer to connect to.
|
||||
* If this parameter is NULL, the white list
|
||||
* is used.
|
||||
* @param duration_ms The duration of the discovery procedure.
|
||||
* On expiration, the procedure ends and a
|
||||
* BLE_GAP_EVENT_DISC_COMPLETE event is
|
||||
* reported. Units are milliseconds.
|
||||
* @param duration_ms The duration of the connect procedure. On
|
||||
* expiration, the procedure is cancelled and
|
||||
* a BLE_GAP_EVENT_CONNECT event with a status
|
||||
* of BLE_HS_ETIMEOUT is reported. Units are
|
||||
* milliseconds. Specify BLE_HS_FOREVER to
|
||||
* wait indefinitely for the controller.
|
||||
* @param phy_mask Define on which PHYs connection attempt should
|
||||
* be done
|
||||
* @param phy_1m_conn_params Additional arguments specifying the
|
||||
|
||||
+256
-19
@@ -222,6 +222,10 @@ struct ble_gap_master_state {
|
||||
uint8_t using_wl:1;
|
||||
uint8_t our_addr_type:2;
|
||||
uint8_t cancel:1;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
uint8_t synchronized:1;
|
||||
uint8_t timeout_cancel_pending:1;
|
||||
#endif
|
||||
ble_addr_t peer_addr;
|
||||
} conn;
|
||||
|
||||
@@ -1672,6 +1676,10 @@ ble_gap_master_reset_state(void)
|
||||
ble_gap_master.conn.cancel = 0;
|
||||
ble_gap_master.cb = NULL;
|
||||
ble_gap_master.cb_arg = NULL;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
ble_gap_master.conn.synchronized = 0;
|
||||
ble_gap_master.conn.timeout_cancel_pending = 0;
|
||||
#endif
|
||||
memset(&ble_gap_master.conn.peer_addr, 0,
|
||||
sizeof(ble_gap_master.conn.peer_addr));
|
||||
|
||||
@@ -3275,7 +3283,8 @@ ble_gap_periodic_sync_reattempt_clear(bool clear_sync_reattempt)
|
||||
#endif
|
||||
|
||||
void
|
||||
ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev)
|
||||
ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev,
|
||||
uint8_t subevent)
|
||||
{
|
||||
uint16_t sync_handle;
|
||||
struct ble_gap_event event;
|
||||
@@ -3284,6 +3293,9 @@ ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv
|
||||
#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT) && NIMBLE_BLE_CONNECT
|
||||
int rc;
|
||||
bool reattempt_triggered = false;
|
||||
#endif
|
||||
#if !MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
(void)subevent;
|
||||
#endif
|
||||
memset(&event, 0, sizeof event);
|
||||
|
||||
@@ -3320,10 +3332,13 @@ ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv
|
||||
event.periodic_sync.per_adv_ival = ev->interval;
|
||||
event.periodic_sync.adv_clk_accuracy = ev->aca;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
event.periodic_sync.num_subevents = ev->num_subevents;
|
||||
event.periodic_sync.subevent_interval = ev->subevent_interval;
|
||||
event.periodic_sync.response_slot_delay = ev->response_slot_delay;
|
||||
event.periodic_sync.response_slot_spacing = ev->response_slot_spacing;
|
||||
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB_V2) {
|
||||
ble_gap_sync.psync->num_subevents = ev->num_subevents;
|
||||
event.periodic_sync.num_subevents = ev->num_subevents;
|
||||
event.periodic_sync.subevent_interval = ev->subevent_interval;
|
||||
event.periodic_sync.response_slot_delay = ev->response_slot_delay;
|
||||
event.periodic_sync.response_slot_spacing = ev->response_slot_spacing;
|
||||
}
|
||||
#endif
|
||||
|
||||
ble_hs_periodic_sync_insert(ble_gap_sync.psync);
|
||||
@@ -3657,7 +3672,8 @@ periodic_adv_transfer_disable(uint16_t conn_handle)
|
||||
}
|
||||
|
||||
void
|
||||
ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev)
|
||||
ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev,
|
||||
uint8_t subevent)
|
||||
{
|
||||
struct ble_hci_le_periodic_adv_term_sync_cp cmd_term;
|
||||
struct ble_gap_event event;
|
||||
@@ -3667,6 +3683,9 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_
|
||||
uint16_t conn_handle;
|
||||
uint16_t opcode;
|
||||
void *cb_arg;
|
||||
#if !MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
(void)subevent;
|
||||
#endif
|
||||
|
||||
conn_handle = le16toh(ev->conn_handle);
|
||||
|
||||
@@ -3697,7 +3716,11 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_
|
||||
memset(&event, 0, sizeof event);
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER_V2;
|
||||
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER_V2) {
|
||||
event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER_V2;
|
||||
} else {
|
||||
event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER;
|
||||
}
|
||||
#else
|
||||
event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER;
|
||||
#endif // MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
@@ -3714,6 +3737,11 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_
|
||||
conn->psync->adv_sid = ev->sid;
|
||||
memcpy(conn->psync->advertiser_addr.val, ev->peer_addr, 6);
|
||||
conn->psync->advertiser_addr.type = ev->peer_addr_type;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER_V2) {
|
||||
conn->psync->num_subevents = ev->num_subevents;
|
||||
}
|
||||
#endif
|
||||
ble_hs_periodic_sync_insert(conn->psync);
|
||||
}
|
||||
|
||||
@@ -3730,10 +3758,12 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_
|
||||
event.periodic_transfer.per_adv_itvl = le16toh(ev->interval);
|
||||
event.periodic_transfer.adv_clk_accuracy = ev->aca;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
event.periodic_transfer.num_subevents = ev->num_subevents;
|
||||
event.periodic_transfer.subevent_interval = ev->subevent_interval;
|
||||
event.periodic_transfer.response_slot_delay = ev->response_slot_delay;
|
||||
event.periodic_transfer.response_slot_spacing = ev->response_slot_spacing;
|
||||
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER_V2) {
|
||||
event.periodic_transfer.num_subevents = ev->num_subevents;
|
||||
event.periodic_transfer.subevent_interval = ev->subevent_interval;
|
||||
event.periodic_transfer.response_slot_delay = ev->response_slot_delay;
|
||||
event.periodic_transfer.response_slot_spacing = ev->response_slot_spacing;
|
||||
}
|
||||
#endif
|
||||
ble_hs_unlock();
|
||||
|
||||
@@ -3953,6 +3983,69 @@ ble_gap_rd_rem_ver_tx(uint16_t handle)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) && NIMBLE_BLE_CONNECT
|
||||
/**
|
||||
* Determines the local address type used for a PAwR peripheral connection.
|
||||
*
|
||||
* Such a link is established by the controller through the periodic sync, so
|
||||
* no advertising instance describes it; the controller uses our identity
|
||||
* address, or an RPA generated from it.
|
||||
*/
|
||||
static int
|
||||
ble_gap_pawr_conn_our_addr(const struct ble_gap_conn_complete *evt,
|
||||
uint8_t *out_own_addr_type,
|
||||
uint8_t *out_random_addr)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
int privacy;
|
||||
int rc;
|
||||
|
||||
privacy = memcmp(evt->local_rpa, BLE_ADDR_ANY->val, 6) != 0;
|
||||
|
||||
rc = ble_hs_id_infer_auto(privacy, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
if (ble_hs_misc_own_addr_type_to_id(own_addr_type) == BLE_ADDR_RANDOM) {
|
||||
rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, out_random_addr, NULL);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)out_random_addr;
|
||||
#endif
|
||||
|
||||
*out_own_addr_type = own_addr_type;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NIMBLE_BLE_CONNECT
|
||||
/**
|
||||
* Drops a link the host has no state for. Such a connection can never be used
|
||||
* or terminated by the application, so leaving it up would strand it until the
|
||||
* supervision timeout expires.
|
||||
*/
|
||||
static void
|
||||
ble_gap_disconnect_unclaimed_conn(uint16_t conn_handle)
|
||||
{
|
||||
struct ble_hci_lc_disconnect_cp cmd;
|
||||
int rc;
|
||||
|
||||
cmd.conn_handle = htole16(conn_handle);
|
||||
cmd.reason = BLE_ERR_REM_USER_CONN_TERM;
|
||||
|
||||
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL,
|
||||
BLE_HCI_OCF_DISCONNECT_CMD),
|
||||
&cmd, sizeof(cmd), NULL, 0);
|
||||
BLE_HS_LOG(WARN, "GAP: no procedure owns conn_handle=%d; disconnecting; "
|
||||
"rc=%d\n", conn_handle, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Processes an incoming connection-complete HCI event.
|
||||
* instance parameter is valid only for slave connection.
|
||||
@@ -4010,13 +4103,26 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
case BLE_ERR_CONN_ESTABLISHMENT:
|
||||
#if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
/*
|
||||
* Failed enhanced connection-complete events do not contain
|
||||
* valid role or PAwR handle fields. Use host state to route
|
||||
* failures before inspecting those fields.
|
||||
*/
|
||||
if (ble_gap_conn_active()) {
|
||||
ble_gap_master_connect_failure(
|
||||
BLE_HS_HCI_ERR(evt->status));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (!v1_evt) {
|
||||
ble_gap_rx_conn_comp_failed(evt);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif // MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
default:
|
||||
/* this should never happen, unless controller is broken */
|
||||
BLE_HS_LOG(INFO, "controller reported invalid error code in conn"
|
||||
@@ -4044,13 +4150,22 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
|
||||
case BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER:
|
||||
rc = ble_gap_accept_master_conn();
|
||||
if (rc != 0) {
|
||||
ble_gap_disconnect_unclaimed_conn(evt->connection_handle);
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE:
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (evt->sync_handle != 0xFFFF) {
|
||||
/* PAwR peripheral links are accepted by the controller through
|
||||
* the synchronized connection procedure, not local advertising. */
|
||||
rc = 0;
|
||||
} else
|
||||
#endif
|
||||
rc = ble_gap_accept_slave_conn(instance);
|
||||
if (rc != 0) {
|
||||
ble_gap_disconnect_unclaimed_conn(evt->connection_handle);
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
@@ -4082,7 +4197,26 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
|
||||
if (!v1_evt && evt->sync_handle != 0xFFFF) {
|
||||
/* PAwR peripheral: application callback is on the periodic sync. */
|
||||
struct ble_hs_periodic_sync *psync;
|
||||
uint8_t own_addr_type;
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
uint8_t random_addr[BLE_DEV_ADDR_LEN];
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
rc = ble_gap_pawr_conn_our_addr(evt, &own_addr_type, random_addr);
|
||||
#else
|
||||
rc = ble_gap_pawr_conn_our_addr(evt, &own_addr_type, NULL);
|
||||
#endif
|
||||
if (rc == 0) {
|
||||
conn->bhc_our_addr_type = own_addr_type;
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
if (ble_hs_misc_own_addr_type_to_id(own_addr_type) ==
|
||||
BLE_ADDR_RANDOM) {
|
||||
memcpy(conn->bhc_our_rnd_addr, random_addr,
|
||||
BLE_DEV_ADDR_LEN);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ble_hs_lock();
|
||||
psync = ble_hs_periodic_sync_find_by_handle(evt->sync_handle);
|
||||
if (psync != NULL) {
|
||||
@@ -4094,12 +4228,20 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
|
||||
conn->bhc_cb = ble_gap_master.cb;
|
||||
conn->bhc_cb_arg = ble_gap_master.cb_arg;
|
||||
conn->bhc_our_addr_type = ble_gap_master.conn.our_addr_type;
|
||||
ble_gap_master_reset_state();
|
||||
} else {
|
||||
ble_hs_lock();
|
||||
conn->bhc_cb = ble_gap_slave[instance].cb;
|
||||
conn->bhc_cb_arg = ble_gap_slave[instance].cb_arg;
|
||||
conn->bhc_our_addr_type = ble_gap_slave[instance].our_addr_type;
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
memcpy(conn->bhc_our_rnd_addr, ble_gap_slave[instance].rnd_addr, 6);
|
||||
#endif
|
||||
ble_gap_slave_reset_state(instance);
|
||||
ble_hs_unlock();
|
||||
}
|
||||
#else
|
||||
ble_hs_lock();
|
||||
conn->bhc_cb = ble_gap_slave[instance].cb;
|
||||
conn->bhc_cb_arg = ble_gap_slave[instance].cb_arg;
|
||||
conn->bhc_our_addr_type = ble_gap_slave[instance].our_addr_type;
|
||||
@@ -4107,6 +4249,7 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
|
||||
memcpy(conn->bhc_our_rnd_addr, ble_gap_slave[instance].rnd_addr, 6);
|
||||
#endif
|
||||
ble_gap_slave_reset_state(instance);
|
||||
ble_hs_unlock();
|
||||
#endif
|
||||
|
||||
if (master_match) {
|
||||
@@ -4439,11 +4582,28 @@ static int32_t
|
||||
ble_gap_master_timer(void)
|
||||
{
|
||||
uint32_t ticks_until_exp;
|
||||
uint8_t op;
|
||||
#if NIMBLE_BLE_CONNECT && MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) && \
|
||||
(MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER))
|
||||
bool synchronized;
|
||||
bool timeout_cancel_pending;
|
||||
#endif
|
||||
#if NIMBLE_BLE_CONNECT || (NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV))
|
||||
int rc;
|
||||
#endif
|
||||
|
||||
ble_hs_lock();
|
||||
ticks_until_exp = ble_gap_master_ticks_until_exp();
|
||||
op = ble_gap_master.op;
|
||||
#if NIMBLE_BLE_CONNECT && MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) && \
|
||||
(MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER))
|
||||
synchronized = op == BLE_GAP_OP_M_CONN &&
|
||||
ble_gap_master.conn.synchronized;
|
||||
timeout_cancel_pending = op == BLE_GAP_OP_M_CONN &&
|
||||
ble_gap_master.conn.timeout_cancel_pending;
|
||||
#endif
|
||||
ble_hs_unlock();
|
||||
|
||||
if (ticks_until_exp != 0) {
|
||||
/* Timer not expired yet. */
|
||||
return ticks_until_exp;
|
||||
@@ -4451,16 +4611,70 @@ ble_gap_master_timer(void)
|
||||
|
||||
/*** Timer expired; process event. */
|
||||
|
||||
switch (ble_gap_master.op) {
|
||||
switch (op) {
|
||||
#if NIMBLE_BLE_CONNECT
|
||||
case BLE_GAP_OP_M_CONN:
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) && \
|
||||
(MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER))
|
||||
if (timeout_cancel_pending) {
|
||||
/*
|
||||
* The controller accepted the cancel but did not report its
|
||||
* connection-complete result within the grace period.
|
||||
*/
|
||||
ble_hs_lock();
|
||||
ble_gap_master.exp_set = 0;
|
||||
ble_hs_unlock();
|
||||
|
||||
ble_gap_master_connect_cancelled();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
rc = ble_gap_conn_cancel_tx();
|
||||
#if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER)
|
||||
if (rc == BLE_HS_HCI_ERR(BLE_ERR_CMD_DISALLOWED) ||
|
||||
rc == BLE_HS_HCI_ERR(BLE_ERR_UNKNOWN_HCI_CMD)) {
|
||||
/* The controller has no connection attempt pending, so no
|
||||
* connection complete event will follow the cancel. Report the
|
||||
* timeout here instead of retrying the cancel forever.
|
||||
*/
|
||||
ble_hs_lock();
|
||||
ble_gap_master.exp_set = 0;
|
||||
ble_hs_unlock();
|
||||
|
||||
ble_gap_master_connect_cancelled();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (rc != 0) {
|
||||
/* Failed to stop connecting; try again in 100 ms. */
|
||||
return ble_npl_time_ms_to_ticks32(BLE_GAP_CANCEL_RETRY_TIMEOUT_MS);
|
||||
} else {
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) && \
|
||||
(MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER))
|
||||
/*
|
||||
* A synchronized create-connection controller can fail to send
|
||||
* the completion event after accepting cancel. Allow the normal
|
||||
* event a short grace period, then complete the host procedure if
|
||||
* the controller remains silent.
|
||||
*/
|
||||
if (synchronized) {
|
||||
uint32_t grace_ticks =
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
BLE_GAP_CANCEL_RETRY_TIMEOUT_MS);
|
||||
|
||||
ble_hs_lock();
|
||||
ble_gap_master.conn.timeout_cancel_pending = 1;
|
||||
ble_gap_master.exp_os_ticks =
|
||||
ble_npl_time_get() + grace_ticks;
|
||||
ble_hs_unlock();
|
||||
return grace_ticks;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stop the timer now that the cancel command has been acked. */
|
||||
ble_hs_lock();
|
||||
ble_gap_master.exp_set = 0;
|
||||
ble_hs_unlock();
|
||||
|
||||
/* Timeout gets reported when we receive a connection complete
|
||||
* event indicating the connect procedure has been cancelled.
|
||||
@@ -8840,6 +9054,7 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle,
|
||||
const struct ble_gap_conn_params *phy_coded_conn_params,
|
||||
ble_gap_event_fn *cb, void *cb_arg)
|
||||
{
|
||||
uint32_t duration_ticks = 0;
|
||||
int rc;
|
||||
|
||||
STATS_INC(ble_gap_stats, initiate);
|
||||
@@ -8903,11 +9118,20 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle,
|
||||
duration_ms = BLE_GAP_CONN_DUR_DFLT;
|
||||
}
|
||||
|
||||
/* The connection creation timeout is not really useful for PAwR.
|
||||
* The controller will give a result for the connection attempt
|
||||
* within a periodic interval. We do not know the periodic interval
|
||||
* used, so disable the timeout.
|
||||
*/
|
||||
/* The controller reports the outcome of a synchronized connection attempt
|
||||
* within a periodic interval, but a controller that never reports it would
|
||||
* otherwise leave the initiate procedure pending forever with no event for
|
||||
* the application. Keep the host timeout as a recovery path; callers that
|
||||
* do not want it can pass BLE_HS_FOREVER.
|
||||
*/
|
||||
if (duration_ms != BLE_HS_FOREVER) {
|
||||
rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks);
|
||||
if (rc != 0) {
|
||||
/* Duration too great. */
|
||||
rc = BLE_HS_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify peer not already connected. */
|
||||
if (ble_hs_conn_find_by_addr(peer_addr) != NULL) {
|
||||
@@ -8928,6 +9152,7 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle,
|
||||
ble_gap_master.cb_arg = cb_arg;
|
||||
ble_gap_master.conn.using_wl = peer_addr == NULL;
|
||||
ble_gap_master.conn.our_addr_type = own_addr_type;
|
||||
ble_gap_master.conn.synchronized = 1;
|
||||
if (peer_addr != NULL) {
|
||||
ble_gap_master.conn.peer_addr = *peer_addr;
|
||||
} else {
|
||||
@@ -8945,6 +9170,12 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle,
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_ROLE_CENTRAL)
|
||||
if (duration_ms != BLE_HS_FOREVER) {
|
||||
ble_gap_master_set_timer(duration_ticks);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
|
||||
done:
|
||||
@@ -9300,6 +9531,9 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
|
||||
ble_gap_master.cb_arg = cb_arg;
|
||||
ble_gap_master.conn.using_wl = peer_addr == NULL;
|
||||
ble_gap_master.conn.our_addr_type = own_addr_type;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
ble_gap_master.conn.synchronized = 0;
|
||||
#endif
|
||||
if (peer_addr != NULL) {
|
||||
ble_gap_master.conn.peer_addr = *peer_addr;
|
||||
} else {
|
||||
@@ -9483,6 +9717,9 @@ ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
|
||||
ble_gap_master.cb_arg = cb_arg;
|
||||
ble_gap_master.conn.using_wl = peer_addr == NULL;
|
||||
ble_gap_master.conn.our_addr_type = own_addr_type;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
ble_gap_master.conn.synchronized = 0;
|
||||
#endif
|
||||
if (peer_addr != NULL) {
|
||||
ble_gap_master.conn.peer_addr = *peer_addr;
|
||||
} else {
|
||||
|
||||
@@ -84,10 +84,12 @@ void ble_gap_rx_le_scan_timeout(void);
|
||||
void ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc);
|
||||
void ble_gap_rx_adv_set_terminated(const struct ble_hci_ev_le_subev_adv_set_terminated *ev);
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
|
||||
void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev);
|
||||
void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev,
|
||||
uint8_t subevent);
|
||||
void ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_rpt *ev);
|
||||
void ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev);
|
||||
void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev);
|
||||
void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev,
|
||||
uint8_t subevent);
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) && !MYNEWT_VAL(BLE_ISO)
|
||||
void ble_gap_rx_biginfo_adv_rpt(const struct ble_hci_ev_le_subev_biginfo_adv_report *ev);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@@ -761,6 +762,86 @@ ble_hs_hci_evt_le_meta(uint8_t event_code, const void *data, unsigned int len)
|
||||
|
||||
|
||||
#if NIMBLE_BLE_CONNECT
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
static void
|
||||
ble_hs_hci_evt_conn_norm_handles(struct ble_gap_conn_complete *evt)
|
||||
{
|
||||
if (evt->status != BLE_ERR_SUCCESS) {
|
||||
evt->adv_handle = 0xff;
|
||||
evt->sync_handle = 0xffff;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (evt->role) {
|
||||
case BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER:
|
||||
evt->sync_handle = 0xffff;
|
||||
if (evt->adv_handle > 0xef) {
|
||||
evt->adv_handle = 0xff;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE:
|
||||
evt->adv_handle = 0xff;
|
||||
if (evt->sync_handle > 0x0eff) {
|
||||
evt->sync_handle = 0xffff;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
evt->adv_handle = 0xff;
|
||||
evt->sync_handle = 0xffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ble_hs_hci_evt_pawr_conn(struct ble_gap_conn_complete *evt,
|
||||
bool handles_present)
|
||||
{
|
||||
struct ble_hs_periodic_sync *psync;
|
||||
|
||||
/* Only a peripheral is identified by the sync handle. */
|
||||
if (evt->status == BLE_ERR_SUCCESS &&
|
||||
evt->role != BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ble_hs_lock();
|
||||
/*
|
||||
* The sync handle is only meaningful on a successful V2 event; it has
|
||||
* already been dropped in all the circumstances where the spec requires the
|
||||
* host to ignore it. Regular periodic syncs share the same list, so a sync
|
||||
* without subevents does not describe a PAwR train and must not
|
||||
* short-circuit the pending-connection / Advertising Set Terminated path.
|
||||
* That also rejects controllers reporting sync handle 0 for a connection
|
||||
* established from extended advertising.
|
||||
*/
|
||||
psync = NULL;
|
||||
if (evt->status == BLE_ERR_SUCCESS && handles_present &&
|
||||
evt->sync_handle != 0xffff) {
|
||||
psync = ble_hs_periodic_sync_find_by_handle(evt->sync_handle);
|
||||
if (psync != NULL && psync->num_subevents == 0) {
|
||||
psync = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (psync == NULL &&
|
||||
(evt->status == BLE_ERR_CONN_ESTABLISHMENT ||
|
||||
(evt->status == BLE_ERR_SUCCESS && !handles_present))) {
|
||||
psync = ble_hs_periodic_sync_find_pawr_locked();
|
||||
}
|
||||
|
||||
if (psync != NULL) {
|
||||
evt->sync_handle = psync->sync_handle;
|
||||
} else {
|
||||
evt->sync_handle = 0xffff;
|
||||
}
|
||||
ble_hs_unlock();
|
||||
|
||||
return psync != NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data,
|
||||
unsigned int len)
|
||||
@@ -791,6 +872,16 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data,
|
||||
|
||||
evt.status = ev->status;
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) {
|
||||
evt.adv_handle = 0xff;
|
||||
evt.sync_handle = 0xffff;
|
||||
} else {
|
||||
evt.adv_handle = ev->adv_handle;
|
||||
evt.sync_handle = le16toh(ev->sync_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (evt.status == BLE_ERR_SUCCESS) {
|
||||
evt.connection_handle = le16toh(ev->conn_handle);
|
||||
evt.role = ev->role;
|
||||
@@ -824,10 +915,32 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data,
|
||||
evt.connection_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
#endif
|
||||
}
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV) && !MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
ble_hs_hci_evt_conn_norm_handles(&evt);
|
||||
|
||||
/*
|
||||
* PAwR connection-complete failures contain only a valid status field,
|
||||
* so associate the event with the active PAwR sync before inspecting role.
|
||||
*/
|
||||
if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE_V2 &&
|
||||
ble_hs_hci_evt_pawr_conn(&evt, true)) {
|
||||
return ble_gap_rx_conn_complete(&evt, 0);
|
||||
}
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_EXT_ADV)
|
||||
if (evt.status == BLE_ERR_DIR_ADV_TMO ||
|
||||
evt.role == BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) {
|
||||
|
||||
/* PAwR slave connections are not followed by LE Advertising Set
|
||||
* Terminated, so they must not be stored as pending.
|
||||
*/
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (evt.status == BLE_ERR_SUCCESS &&
|
||||
subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE &&
|
||||
ble_hs_hci_evt_pawr_conn(&evt, false)) {
|
||||
return ble_gap_rx_conn_complete(&evt, 0);
|
||||
}
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
|
||||
if (ble_hs_hci_ensure_ctx()) {
|
||||
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
|
||||
@@ -843,16 +956,15 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data,
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) {
|
||||
evt.adv_handle = 0xFF;
|
||||
evt.sync_handle = 0xFFFF;
|
||||
} else {
|
||||
evt.adv_handle = ev->adv_handle;
|
||||
evt.sync_handle = ev->sync_handle;
|
||||
}
|
||||
#endif
|
||||
return ble_gap_rx_conn_complete(&evt, 0);
|
||||
uint8_t instance = 0;
|
||||
|
||||
if (evt.adv_handle < BLE_ADV_INSTANCES) {
|
||||
instance = evt.adv_handle;
|
||||
}
|
||||
return ble_gap_rx_conn_complete(&evt, instance);
|
||||
#else
|
||||
return ble_gap_rx_conn_complete(&evt, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -871,6 +983,12 @@ ble_hs_hci_evt_le_conn_complete(uint8_t subevent, const void *data,
|
||||
|
||||
evt.status = ev->status;
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
/* This event carries no PAwR handles. */
|
||||
evt.adv_handle = 0xff;
|
||||
evt.sync_handle = 0xffff;
|
||||
#endif
|
||||
|
||||
if (evt.status == BLE_ERR_SUCCESS) {
|
||||
evt.connection_handle = le16toh(ev->conn_handle);
|
||||
evt.role = ev->role;
|
||||
@@ -907,6 +1025,12 @@ ble_hs_hci_evt_le_conn_complete(uint8_t subevent, const void *data,
|
||||
if (evt.status == BLE_ERR_DIR_ADV_TMO ||
|
||||
evt.role == BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) {
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (evt.status == BLE_ERR_SUCCESS &&
|
||||
ble_hs_hci_evt_pawr_conn(&evt, false)) {
|
||||
return ble_gap_rx_conn_complete(&evt, 0);
|
||||
}
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
|
||||
if (ble_hs_hci_ensure_ctx()) {
|
||||
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
|
||||
@@ -1477,13 +1601,25 @@ ble_hs_hci_evt_le_periodic_adv_sync_estab(uint8_t subevent, const void *data,
|
||||
unsigned int len)
|
||||
{
|
||||
const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev = data;
|
||||
unsigned int min_len;
|
||||
|
||||
if (len != sizeof(*ev)) {
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB) {
|
||||
min_len = offsetof(struct ble_hci_ev_le_subev_periodic_adv_sync_estab,
|
||||
num_subevents);
|
||||
} else {
|
||||
min_len = sizeof(*ev);
|
||||
}
|
||||
#else
|
||||
min_len = sizeof(*ev);
|
||||
#endif
|
||||
|
||||
if (len < min_len) {
|
||||
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ECONTROLLER);
|
||||
return BLE_HS_ECONTROLLER;
|
||||
}
|
||||
|
||||
ble_gap_rx_peroidic_adv_sync_estab(ev);
|
||||
ble_gap_rx_peroidic_adv_sync_estab(ev, subevent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1564,22 +1700,25 @@ ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data,
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
|
||||
const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev = data;
|
||||
struct ble_hci_ev_le_subev_periodic_adv_sync_transfer ev_copy;
|
||||
unsigned int min_len;
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
/* V1 event is 4 bytes shorter (lacks PAwR fields); accept both lengths */
|
||||
unsigned int v1_len = sizeof(*ev) - 4;
|
||||
if (len != sizeof(*ev) && len != v1_len) {
|
||||
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER) {
|
||||
min_len = offsetof(struct ble_hci_ev_le_subev_periodic_adv_sync_transfer,
|
||||
num_subevents);
|
||||
} else {
|
||||
min_len = sizeof(*ev);
|
||||
}
|
||||
#else
|
||||
if (len != sizeof(*ev)) {
|
||||
min_len = sizeof(*ev);
|
||||
#endif
|
||||
|
||||
if (len < min_len) {
|
||||
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EBADDATA);
|
||||
return BLE_HS_EBADDATA;
|
||||
}
|
||||
|
||||
memset(&ev_copy, 0, sizeof(ev_copy));
|
||||
memcpy(&ev_copy, ev, len);
|
||||
ble_gap_rx_periodic_adv_sync_transfer(&ev_copy);
|
||||
ble_gap_rx_periodic_adv_sync_transfer(ev, subevent);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -206,6 +206,32 @@ ble_hs_periodic_sync_first(void)
|
||||
return psync;
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
/**
|
||||
* Find first PAwR sync (num_subevents > 0) in the active sync list.
|
||||
*
|
||||
* Regular periodic syncs share the same list; callers that need a PAwR
|
||||
* association must not use ble_hs_periodic_sync_first().
|
||||
*
|
||||
* @note Host lock must be held.
|
||||
*/
|
||||
struct ble_hs_periodic_sync *
|
||||
ble_hs_periodic_sync_find_pawr_locked(void)
|
||||
{
|
||||
struct ble_hs_periodic_sync *psync;
|
||||
|
||||
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
|
||||
|
||||
SLIST_FOREACH(psync, &g_ble_hs_periodic_sync_handles, next) {
|
||||
if (psync->num_subevents > 0) {
|
||||
return psync;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ble_hs_periodic_sync_deinit(void)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,10 @@ struct ble_hs_periodic_sync {
|
||||
uint16_t sync_handle;
|
||||
ble_addr_t advertiser_addr;
|
||||
uint8_t adv_sid;
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
/* From Sync Established/Transfer V2; >0 means PAwR sync. */
|
||||
uint8_t num_subevents;
|
||||
#endif
|
||||
|
||||
ble_gap_event_fn *cb;
|
||||
void *cb_arg;
|
||||
@@ -46,6 +50,9 @@ struct ble_hs_periodic_sync *ble_hs_periodic_sync_find_by_handle(uint16_t sync_h
|
||||
struct ble_hs_periodic_sync *ble_hs_periodic_sync_find(const ble_addr_t *addr,
|
||||
uint8_t sid);
|
||||
struct ble_hs_periodic_sync *ble_hs_periodic_sync_first(void);
|
||||
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
|
||||
struct ble_hs_periodic_sync *ble_hs_periodic_sync_find_pawr_locked(void);
|
||||
#endif
|
||||
int ble_hs_periodic_sync_init(void);
|
||||
void ble_hs_periodic_sync_deinit(void);
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user