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);