You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/05/21 22:19:49 UTC
[4/4] incubator-mynewt-core git commit: BLE Host - Tx updates upon
rebonding.
BLE Host - Tx updates upon rebonding.
When bonding is restored:
* Restores persisted CCCD entries for the connected peer.
* Sends all pending notifications to the connected peer.
* Sends up to one pending indication to the connected peer;
schedules any remaining pending indications.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/486dd570
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/486dd570
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/486dd570
Branch: refs/heads/develop
Commit: 486dd57057a20c6adc81e904e7baed2e9b9c9d94
Parents: d98f4d1
Author: Christopher Collins <cc...@apache.org>
Authored: Sat May 21 15:18:25 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Sat May 21 15:18:25 2016 -0700
----------------------------------------------------------------------
net/nimble/host/src/ble_gap.c | 8 +-
net/nimble/host/src/ble_gap_priv.h | 2 +-
net/nimble/host/src/ble_gatt_priv.h | 3 +-
net/nimble/host/src/ble_gatts.c | 215 ++++++++++++++++++++++++-------
net/nimble/host/src/ble_l2cap_sm.c | 3 +-
5 files changed, 179 insertions(+), 52 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/486dd570/net/nimble/host/src/ble_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c
index 32656b0..0f7211a 100644
--- a/net/nimble/host/src/ble_gap.c
+++ b/net/nimble/host/src/ble_gap.c
@@ -2122,8 +2122,8 @@ ble_gap_passkey_event(uint16_t conn_handle, uint8_t passkey_action)
}
void
-ble_gap_security_event(uint16_t conn_handle, int status,
- struct ble_gap_sec_state *sec_state)
+ble_gap_enc_changed(uint16_t conn_handle, int status,
+ struct ble_gap_sec_state *sec_state)
{
struct ble_gap_conn_ctxt ctxt;
struct ble_gap_snapshot snap;
@@ -2149,6 +2149,10 @@ ble_gap_security_event(uint16_t conn_handle, int status,
ctxt.enc_change.status = status;
ble_gap_call_event_cb(BLE_GAP_EVENT_ENC_CHANGE, &ctxt,
snap.cb, snap.cb_arg);
+
+ if (sec_state->bonded) {
+ ble_gatts_bonding_restored(conn_handle);
+ }
}
/*****************************************************************************
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/486dd570/net/nimble/host/src/ble_gap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_priv.h b/net/nimble/host/src/ble_gap_priv.h
index 9e2d8f4..6fb987f 100644
--- a/net/nimble/host/src/ble_gap_priv.h
+++ b/net/nimble/host/src/ble_gap_priv.h
@@ -74,7 +74,7 @@ void ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt);
void ble_gap_rx_param_req(struct hci_le_conn_param_req *evt);
int ble_gap_rx_l2cap_update_req(uint16_t conn_handle,
struct ble_gap_upd_params *params);
-void ble_gap_security_event(uint16_t conn_handle, int status,
+void ble_gap_enc_changed(uint16_t conn_handle, int status,
struct ble_gap_sec_state *sec_state);
void ble_gap_passkey_event(uint16_t conn_handle, uint8_t passkey_action);
void ble_gap_notify_event(uint16_t conn_handle, uint16_t attr_handle,
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/486dd570/net/nimble/host/src/ble_gatt_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatt_priv.h b/net/nimble/host/src/ble_gatt_priv.h
index d19a911..e2c4583 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -138,7 +138,7 @@ int ble_gattc_init(void);
/*** @server. */
#define BLE_GATTS_CLT_CFG_F_NOTIFY 0x0001
#define BLE_GATTS_CLT_CFG_F_INDICATE 0x0002
-#define BLE_GATTS_CLT_CFG_F_UPDATED 0x0080 /* Internal only. */
+#define BLE_GATTS_CLT_CFG_F_INDICATE_PENDING 0x0080 /* Internal only. */
#define BLE_GATTS_CLT_CFG_F_RESERVED 0xfffc
#define BLE_GATTS_INC_SVC_LEN_NO_UUID 4
@@ -146,6 +146,7 @@ int ble_gattc_init(void);
int ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle);
int ble_gatts_send_next_indicate(uint16_t conn_handle);
+void ble_gatts_bonding_restored(uint16_t conn_handle);
/*** @misc. */
void ble_gatts_conn_deinit(struct ble_gatts_conn *gatts_conn);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/486dd570/net/nimble/host/src/ble_gatts.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatts.c b/net/nimble/host/src/ble_gatts.c
index d56609d..7a9a939 100644
--- a/net/nimble/host/src/ble_gatts.c
+++ b/net/nimble/host/src/ble_gatts.c
@@ -1018,6 +1018,49 @@ ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn)
return 0;
}
+
+/**
+ * Schedules a notification or indication for the specified peer-CCCD pair. If
+ * the udpate should be sent immediately, it is indicated in the return code.
+ * If the update can only be sent in the future, the appropriate flags are set
+ * to ensure this happens.
+ *
+ * @param conn The connection to schedule the update for.
+ * @param clt_cfg The client config entry corresponding to the
+ * peer and affected characteristic.
+ *
+ * @return The att_op of the update to send immediately,
+ * if any. 0 if nothing should get sent.
+ */
+static uint8_t
+ble_gatts_schedule_update(struct ble_hs_conn *conn,
+ struct ble_gatts_clt_cfg *clt_cfg)
+{
+ uint8_t att_op;
+
+ if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) {
+ /* Notifications always get sent immediately. */
+ att_op = BLE_ATT_OP_NOTIFY_REQ;
+ } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE) {
+ /* Only one outstanding indication per peer is allowed. If we
+ * are still awaiting an ack, mark this CCCD as updated so that
+ * we know to send the indication upon receiving the expected ack.
+ * If there isn't an outstanding indication, send this one now.
+ */
+ if (conn->bhc_gatt_svr.indicate_val_handle != 0) {
+ clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_INDICATE_PENDING;
+ att_op = 0;
+ } else {
+ att_op = BLE_ATT_OP_INDICATE_REQ;
+ }
+ } else {
+ BLE_HS_DBG_ASSERT(0);
+ att_op = 0;
+ }
+
+ return att_op;
+}
+
int
ble_gatts_send_next_indicate(uint16_t conn_handle)
{
@@ -1036,14 +1079,14 @@ ble_gatts_send_next_indicate(uint16_t conn_handle)
if (conn != NULL) {
for (i = 0; i < conn->bhc_gatt_svr.num_clt_cfgs; i++) {
clt_cfg = conn->bhc_gatt_svr.clt_cfgs + i;
- if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_UPDATED) {
+ if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE_PENDING) {
BLE_HS_DBG_ASSERT(clt_cfg->flags &
BLE_GATTS_CLT_CFG_F_INDICATE);
chr_val_handle = clt_cfg->chr_val_handle;
- /* Clear updated flag in anticipation of indication tx. */
- clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_UPDATED;
+ /* Clear pending flag in anticipation of indication tx. */
+ clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_INDICATE_PENDING;
break;
}
}
@@ -1111,7 +1154,7 @@ ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle)
BLE_HS_DBG_ASSERT(clt_cfg->chr_val_handle == chr_val_handle);
persist = conn->bhc_sec_state.bonded &&
- !(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_UPDATED);
+ !(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE_PENDING);
if (persist) {
cccd_value.peer_addr_type = conn->bhc_addr_type;
memcpy(cccd_value.peer_addr, conn->bhc_addr, 6);
@@ -1149,9 +1192,10 @@ ble_gatts_chr_updated(uint16_t chr_val_handle)
struct ble_store_key_cccd cccd_key;
struct ble_gatts_clt_cfg *clt_cfg;
struct ble_hs_conn *conn;
- uint16_t clt_cfg_flags;
uint16_t conn_handle;
+ uint8_t att_op;
int clt_cfg_idx;
+ int persist;
int rc;
int i;
@@ -1175,73 +1219,76 @@ ble_gatts_chr_updated(uint16_t chr_val_handle)
clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx;
BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_val_handle == chr_val_handle);
-
- if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) {
- clt_cfg_flags = clt_cfg->flags;
- } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE) {
- /* Only one outstanding indication per peer is allowed. If we
- * are still awaiting an ack, mark this CCCD as updated so that
- * an indication will get sent after the current one is
- * acknowledged. If there isn't an outstanding indication,
- * just send this one now.
- */
- if (conn->bhc_gatt_svr.indicate_val_handle != 0) {
- clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_UPDATED;
- clt_cfg_flags = 0;
- } else {
- clt_cfg_flags = clt_cfg->flags;
- }
- } else {
- clt_cfg_flags = 0;
- }
+ /* Determine what kind of update should get sent immediately (if
+ * any).
+ */
+ att_op = ble_gatts_schedule_update(conn, clt_cfg);
conn_handle = conn->bhc_handle;
-
}
ble_hs_unlock();
if (conn == NULL) {
+ /* No more connected devices. */
break;
}
- if (clt_cfg_flags & BLE_GATTS_CLT_CFG_F_INDICATE) {
- ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL);
- } else if (clt_cfg_flags & BLE_GATTS_CLT_CFG_F_NOTIFY) {
+ switch (att_op) {
+ case 0:
+ break;
+ case BLE_ATT_OP_NOTIFY_REQ:
ble_gattc_notify(conn_handle, chr_val_handle);
+ break;
+ case BLE_ATT_OP_INDICATE_REQ:
+ ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL);
+ break;
+ default:
+ BLE_HS_DBG_ASSERT(0);
+ break;
}
}
- /* Persist updated flag for devices for which an update was not sent or
- * scheduled. Retrieve each record corresponding to the modified
- * characteristic.
- */
- cccd_key = (struct ble_store_key_cccd) {
- .peer_addr_type = BLE_STORE_PEER_ADDR_TYPE_NONE,
- .chr_val_handle = chr_val_handle,
- .idx = 0,
- };
+ /*** Persist updated flag for unconnected and not-yet-bonded devices. */
+
+ /* Retrieve each record corresponding to the modified characteristic. */
+ cccd_key.peer_addr_type = BLE_STORE_PEER_ADDR_TYPE_NONE,
+ cccd_key.chr_val_handle = chr_val_handle,
+ cccd_key.idx = 0;
while (1) {
rc = ble_store_read_cccd(&cccd_key, &cccd_value);
if (rc != 0) {
+ /* Read error or no more CCCD records. */
break;
}
- /* Assume no update was scheduled for this device .*/
- clt_cfg_flags = 0;
-
+ /* Determine if this record needs to be rewritten. */
ble_hs_lock();
conn = ble_hs_conn_find_by_addr(cccd_value.peer_addr_type,
cccd_value.peer_addr);
- if (conn != NULL) {
- clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx;
- clt_cfg_flags = clt_cfg->flags;
+
+ if (conn == NULL) {
+ /* Device isn't connected; persist the changed flag so that an
+ * update can be sent when the device reconnects and rebonds.
+ */
+ persist = 1;
+ } else if (cccd_value.flags & BLE_GATTS_CLT_CFG_F_INDICATE) {
+ /* Indication for a connected device; record that the
+ * characteristic has changed until we receive the ack.
+ */
+ persist = 1;
+ } else {
+ /* Notification for a connected device; we already sent it so there
+ * is no need to persist.
+ */
+ persist = 0;
}
+
ble_hs_unlock();
- /* Only persist if the value changed flag wasn't already set (i.e.,
- * only if we are writing new information).
+ /* Only persist if the value changed flag wasn't already sent (i.e.,
+ * don't overwrite with identical data).
*/
- if (clt_cfg_flags == 0 && !cccd_value.value_changed) {
+ if (persist && !cccd_value.value_changed) {
cccd_value.value_changed = 1;
ble_store_write_cccd(&cccd_value);
}
@@ -1251,6 +1298,82 @@ ble_gatts_chr_updated(uint16_t chr_val_handle)
}
}
+/**
+ * Called when bonding has been restored via the encryption procedure. This
+ * function:
+ * o Restores persisted CCCD entries for the connected peer.
+ * o Sends all pending notifications to the connected peer.
+ * o Sends up to one pending indication to the connected peer; schedules
+ * any remaining pending indications.
+ */
+void
+ble_gatts_bonding_restored(uint16_t conn_handle)
+{
+ struct ble_store_value_cccd cccd_value;
+ struct ble_store_key_cccd cccd_key;
+ struct ble_gatts_clt_cfg *clt_cfg;
+ struct ble_hs_conn *conn;
+ uint8_t att_op;
+ int rc;
+
+ ble_hs_lock();
+
+ conn = ble_hs_conn_find(conn_handle);
+ BLE_HS_DBG_ASSERT(conn != NULL);
+ BLE_HS_DBG_ASSERT(conn->bhc_sec_state.bonded);
+
+ cccd_key.peer_addr_type = conn->bhc_addr_type;
+ memcpy(cccd_key.peer_addr, conn->bhc_addr, 6);
+ cccd_key.chr_val_handle = 0;
+ cccd_key.idx = 0;
+
+ ble_hs_unlock();
+
+ while (1) {
+ rc = ble_store_read_cccd(&cccd_key, &cccd_value);
+ if (rc != 0) {
+ break;
+ }
+
+ ble_hs_lock();
+
+ conn = ble_hs_conn_find(conn_handle);
+ BLE_HS_DBG_ASSERT(conn != NULL);
+
+ clt_cfg = ble_gatts_clt_cfg_find(conn->bhc_gatt_svr.clt_cfgs,
+ cccd_value.chr_val_handle);
+ if (clt_cfg != NULL) {
+ clt_cfg->flags = cccd_value.flags;
+ if (cccd_value.value_changed) {
+ att_op = ble_gatts_schedule_update(conn, clt_cfg);
+ }
+ }
+
+ ble_hs_unlock();
+
+ switch (att_op) {
+ case 0:
+ break;
+ case BLE_ATT_OP_NOTIFY_REQ:
+ rc = ble_gattc_notify(conn_handle, cccd_value.chr_val_handle);
+ if (rc == 0) {
+ cccd_value.value_changed = 0;
+ ble_store_write_cccd(&cccd_value);
+ }
+ break;
+ case BLE_ATT_OP_INDICATE_REQ:
+ ble_gattc_indicate(conn_handle, cccd_value.chr_val_handle,
+ NULL, NULL);
+ break;
+ default:
+ BLE_HS_DBG_ASSERT(0);
+ break;
+ }
+
+ cccd_key.idx++;
+ }
+}
+
static void
ble_gatts_free_mem(void)
{
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/486dd570/net/nimble/host/src/ble_l2cap_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm.c b/net/nimble/host/src/ble_l2cap_sm.c
index 18e6b52..5f20c18 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -513,7 +513,7 @@ ble_l2cap_sm_gap_event(struct ble_l2cap_sm_proc *proc, int status,
struct ble_gap_sec_state sec_state;
ble_l2cap_sm_sec_state(proc, &sec_state, enc_enabled);
- ble_gap_security_event(proc->conn_handle, status, &sec_state);
+ ble_gap_enc_changed(proc->conn_handle, status, &sec_state);
}
static int
@@ -1504,7 +1504,6 @@ ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
ble_hs_unlock();
- /* a successful ending of the link */
if (rc == 0) {
if (sm_end) {
ble_l2cap_sm_gap_event(proc, 0, 1);