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 15:57:25 UTC

[1/2] incubator-mynewt-core git commit: BLE Host - Chr updates for unconnected bonded peer

Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop bd4a45687 -> 825f488b4


BLE Host - Chr updates for unconnected bonded peer

We need to persist the fact that the characteristic was updated while
the peer was unconnected or unbonded.  When the peer restores bonding,
we should send the notification or indication.


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/825f488b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/825f488b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/825f488b

Branch: refs/heads/develop
Commit: 825f488b4d57d30e530469f8705ae3f8da994fbf
Parents: ddd76b6
Author: Christopher Collins <cc...@apache.org>
Authored: Fri May 20 19:29:45 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Sat May 21 08:57:12 2016 -0700

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_store.h |   8 +
 net/nimble/host/src/ble_gatt_priv.h      |   2 +-
 net/nimble/host/src/ble_gattc.c          |   2 +-
 net/nimble/host/src/ble_gatts.c          | 210 ++++++++++++--------------
 net/nimble/host/src/ble_hs_conn.c        |  46 ++++++
 net/nimble/host/src/ble_hs_conn_priv.h   |   3 +
 net/nimble/host/src/ble_store.c          |  14 ++
 7 files changed, 168 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/include/host/ble_store.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_store.h b/net/nimble/host/include/host/ble_store.h
index d25c238..0f56cbd 100644
--- a/net/nimble/host/include/host/ble_store.h
+++ b/net/nimble/host/include/host/ble_store.h
@@ -25,6 +25,7 @@
 #define BLE_STORE_OBJ_TYPE_OUR_LTK      1
 #define BLE_STORE_OBJ_TYPE_PEER_LTK     2
 #define BLE_STORE_OBJ_TYPE_CCCD         3
+#define BLE_STORE_OBJ_TYPE_CCCD_IDX     4
 
 struct ble_store_key_ltk {
     uint16_t ediv;
@@ -43,6 +44,11 @@ struct ble_store_key_cccd {
     uint8_t peer_addr_type;
 };
 
+struct ble_store_key_cccd_idx {
+    uint16_t chr_def_handle;
+    uint8_t idx;
+};
+
 struct ble_store_value_cccd {
     uint8_t peer_addr[6];
     uint8_t peer_addr_type;
@@ -72,6 +78,8 @@ int ble_store_read(int obj_type, union ble_store_key *key,
 int ble_store_write(int obj_type, union ble_store_value *val);
 int ble_store_delete(int obj_type, union ble_store_key *key);
 
+int ble_store_read_cccd_idx(struct ble_store_key_cccd_idx *key,
+                            struct ble_store_value_cccd *out_value);
 int ble_store_write_cccd(struct ble_store_value_cccd *value);
 int ble_store_delete_cccd(struct ble_store_key_cccd *key);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/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 9a4c4fb..5653057 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -142,7 +142,7 @@ int ble_gattc_init(void);
 #define BLE_GATTS_INC_SVC_LEN_NO_UUID           4
 #define BLE_GATTS_INC_SVC_LEN_UUID              6
 
-void ble_gatts_send_updates_for_conn(uint16_t conn_handle);
+int ble_gatts_send_next_indicate(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/825f488b/net/nimble/host/src/ble_gattc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gattc.c b/net/nimble/host/src/ble_gattc.c
index 916da80..338010d 100644
--- a/net/nimble/host/src/ble_gattc.c
+++ b/net/nimble/host/src/ble_gattc.c
@@ -3664,7 +3664,7 @@ ble_gattc_indicate_rx_rsp(struct ble_gattc_proc *proc)
 
     /* Send the next indication if one is pending. */
     if (conn != NULL) {
-        ble_gatts_send_updates_for_conn(proc->conn_handle);
+        ble_gatts_send_next_indicate(proc->conn_handle);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/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 62cfe80..3e51b85 100644
--- a/net/nimble/host/src/ble_gatts.c
+++ b/net/nimble/host/src/ble_gatts.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -1017,170 +1017,150 @@ ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn)
     return 0;
 }
 
-static int
-ble_gatts_send_one_update(uint16_t conn_handle)
+int
+ble_gatts_send_next_indicate(uint16_t conn_handle)
 {
     struct ble_gatts_clt_cfg *clt_cfg;
     struct ble_hs_conn *conn;
     uint16_t chr_val_handle;
-    uint8_t att_op;
     int rc;
     int i;
 
-    /* Silence spurious gcc warning. */
+    /* Assume no pending indications. */
     chr_val_handle = 0;
 
-    /* Assume no pending updates. */
-    att_op = 0;
-
     ble_hs_lock();
+
     conn = ble_hs_conn_find(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_NOTIFY) {
-                    att_op = BLE_ATT_OP_NOTIFY_REQ;
-                } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE &&
-                           !(conn->bhc_flags & BLE_HS_CONN_F_INDICATE_TXED)) {
-                    att_op = BLE_ATT_OP_INDICATE_REQ;
-                }
+                BLE_HS_DBG_ASSERT(clt_cfg->flags &
+                                  BLE_GATTS_CLT_CFG_F_INDICATE);
 
-                if (att_op != 0) {
-                    chr_val_handle = clt_cfg->chr_def_handle + 1;
-                    clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_UPDATED;
-                    break;
-                }
+                /* Clear updated flag in anticipation of intication tx. */
+                clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_UPDATED;
+
+                chr_val_handle = clt_cfg->chr_def_handle + 1;
+                break;
             }
         }
     }
-    ble_hs_unlock();
-
-    switch (att_op) {
-    case 0:
-        return BLE_HS_EDONE;
 
-    case BLE_ATT_OP_NOTIFY_REQ:
-        rc = ble_gattc_notify(conn_handle, chr_val_handle);
-        return rc;
-        
-    case BLE_ATT_OP_INDICATE_REQ:
-        rc = ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL);
-        return rc;
+    ble_hs_unlock();
 
-    default:
-        BLE_HS_DBG_ASSERT(0);
-        return BLE_HS_EUNKNOWN;
+    if (conn == NULL) {
+        return BLE_HS_ENOTCONN;
     }
-}
 
-static void
-ble_gatts_send_updates(uint16_t *conn_handles, int num_conns)
-{
-    int more_sends;
-    int rc;
-    int i;
-
-    more_sends = 1;
-
-    while (more_sends) {
-        for (i = 0; i < num_conns; i++) {
-            more_sends = 0;
-            for (i = 0; i < num_conns; i++) {
-                if (conn_handles[i] != BLE_HS_CONN_HANDLE_NONE) {
-                    rc = ble_gatts_send_one_update(conn_handles[i]);
-                    if (rc == 0) {
-                        more_sends = 1;
-                    } else {
-                        conn_handles[i] = BLE_HS_CONN_HANDLE_NONE;
-                    }
-                }
-            }
-        }
+    if (chr_val_handle == 0) {
+        return BLE_HS_ENOENT;
     }
-}
-
-void
-ble_gatts_send_updates_for_conn(uint16_t conn_handle)
-{
-    ble_gatts_send_updates(&conn_handle, 1);
-}
 
-static int
-ble_gatts_conns_with_pending_updates(uint16_t *conn_handles)
-{
-    struct ble_gatts_clt_cfg *clt_cfg;
-    struct ble_hs_conn *conn;
-    int num_conns;
-    int i;
-
-    num_conns = 0;
-
-    for (conn = ble_hs_conn_first();
-         conn != NULL;
-         conn = SLIST_NEXT(conn, bhc_next)) {
-
-        /* XXX: Consider caching this information as a connection flag. */
-        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) {
-                conn_handles[num_conns++] = conn->bhc_handle;
-                break;
-            }
-        }
+    rc = ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL);
+    if (rc != 0) {
+        return rc;
     }
 
-    return num_conns;
+    return 0;
 }
 
 void
 ble_gatts_chr_updated(uint16_t chr_def_handle)
 {
+    struct ble_store_key_cccd_idx cccd_idx;
+    struct ble_store_value_cccd cccd_value;
     struct ble_gatts_clt_cfg *clt_cfg;
     struct ble_hs_conn *conn;
-    uint16_t conn_handles[NIMBLE_OPT(MAX_CONNECTIONS)];
-    int any_updates;
-    int num_conns;
-    int idx;
+    uint16_t chr_val_handle;
+    uint16_t clt_cfg_flags;
+    uint16_t conn_handle;
+    int clt_cfg_idx;
+    int rc;
+    int i;
 
     /* Determine if notifications / indications are enabled for this
-     * characteristic, and remember the client config offset.
+     * characteristic.
      */
-    idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs, chr_def_handle);
-    if (idx == -1) {
+    clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs,
+                                             chr_def_handle);
+    if (clt_cfg_idx == -1) {
         return;
     }
 
-    /* Assume no peers are subscribed to this characteristic. */
-    any_updates = 0;
+    chr_val_handle = chr_def_handle + 1;
+    BLE_HS_DBG_ASSERT(chr_val_handle > chr_def_handle);
 
-    ble_hs_lock();
+    /* Handle the connected devices. */
+    for (i = 0; ; i++) {
+        ble_hs_lock();
 
-    for (conn = ble_hs_conn_first();
-         conn != NULL;
-         conn = SLIST_NEXT(conn, bhc_next)) {
+        conn = ble_hs_conn_find_by_idx(i);
+        if (conn != NULL) {
+            BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs >
+                                   clt_cfg_idx);
+            clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx;
+            BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_def_handle == chr_def_handle);
 
-        BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs > idx);
-        clt_cfg = conn->bhc_gatt_svr.clt_cfgs + idx;
-        BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_def_handle == chr_def_handle);
 
-        if (clt_cfg->flags &
-            (BLE_GATTS_CLT_CFG_F_NOTIFY | BLE_GATTS_CLT_CFG_F_INDICATE)) {
+            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) {
+                if (conn->bhc_flags & BLE_HS_CONN_F_INDICATE_TXED) {
+                    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;
+            }
+            conn_handle = conn->bhc_handle;
 
-            clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_UPDATED;
-            any_updates = 1;
         }
-    }
+        ble_hs_unlock();
+
+        if (conn == NULL) {
+            break;
+        }
 
-    if (any_updates) {
-        num_conns = ble_gatts_conns_with_pending_updates(conn_handles);
+        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) {
+            ble_gattc_notify(conn_handle, chr_val_handle);
+        }
     }
 
-    ble_hs_unlock();
+    /* Persist updated flag for devices for which an update was not sent or
+     * scheduled.
+     */
+    cccd_idx.chr_def_handle = chr_def_handle;
+    for (cccd_idx.idx = 0; ; cccd_idx.idx++) {
+        rc = ble_store_read_cccd_idx(&cccd_idx, &cccd_value);
+        if (rc != 0) {
+            break;
+        }
+
+        /* Assume no update was scheduled for this device .*/
+        clt_cfg_flags = 0;
 
-    if (any_updates) {
-        ble_gatts_send_updates(conn_handles, num_conns);
+        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;
+        }
+        ble_hs_unlock();
+
+        /* Only persist if the value changed flag wasn't already set (i.e.,
+         * only if we are writing new information).
+         */
+        if (clt_cfg_flags == 0 && !cccd_value.value_changed) {
+            cccd_value.value_changed = 1;
+            ble_store_write_cccd(&cccd_value);
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_hs_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn.c b/net/nimble/host/src/ble_hs_conn.c
index 7afcce3..251a768 100644
--- a/net/nimble/host/src/ble_hs_conn.c
+++ b/net/nimble/host/src/ble_hs_conn.c
@@ -244,6 +244,52 @@ ble_hs_conn_find(uint16_t conn_handle)
     return NULL;
 }
 
+struct ble_hs_conn *
+ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr)
+{
+#if !NIMBLE_OPT(CONNECT)
+    return NULL;
+#endif
+
+    struct ble_hs_conn *conn;
+
+    BLE_HS_DBG_ASSERT(ble_hs_thread_safe());
+
+    SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
+        if (conn->bhc_addr_type == addr_type &&
+            memcmp(conn->bhc_addr, addr, 6) == 0) {
+
+            return conn;
+        }
+    }
+
+    return NULL;
+}
+
+struct ble_hs_conn *
+ble_hs_conn_find_by_idx(int idx)
+{
+#if !NIMBLE_OPT(CONNECT)
+    return NULL;
+#endif
+
+    struct ble_hs_conn *conn;
+    int i;
+
+    BLE_HS_DBG_ASSERT(ble_hs_thread_safe());
+
+    i = 0;
+    SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
+        if (i == idx) {
+            return conn;
+        }
+
+        i++;
+    }
+
+    return NULL;
+}
+
 int
 ble_hs_conn_exists(uint16_t conn_handle)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_hs_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn_priv.h b/net/nimble/host/src/ble_hs_conn_priv.h
index 4ccdbab..36f6747 100644
--- a/net/nimble/host/src/ble_hs_conn_priv.h
+++ b/net/nimble/host/src/ble_hs_conn_priv.h
@@ -20,6 +20,7 @@
 #ifndef H_BLE_HS_CONN_
 #define H_BLE_HS_CONN_
 
+#include <inttypes.h>
 #include "ble_l2cap_priv.h"
 #include "ble_gatt_priv.h"
 #include "ble_att_priv.h"
@@ -64,6 +65,8 @@ void ble_hs_conn_free(struct ble_hs_conn *conn);
 void ble_hs_conn_insert(struct ble_hs_conn *conn);
 void ble_hs_conn_remove(struct ble_hs_conn *conn);
 struct ble_hs_conn *ble_hs_conn_find(uint16_t conn_handle);
+struct ble_hs_conn *ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr);
+struct ble_hs_conn *ble_hs_conn_find_by_idx(int idx);
 int ble_hs_conn_exists(uint16_t conn_handle);
 struct ble_hs_conn *ble_hs_conn_first(void);
 struct ble_l2cap_chan *ble_hs_conn_chan_find(struct ble_hs_conn *conn,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_store.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_store.c b/net/nimble/host/src/ble_store.c
index de4cc7a..6ffbacc 100644
--- a/net/nimble/host/src/ble_store.c
+++ b/net/nimble/host/src/ble_store.c
@@ -64,6 +64,20 @@ ble_store_delete(int obj_type, union ble_store_key *key)
 }
 
 int
+ble_store_read_cccd_idx(struct ble_store_key_cccd_idx *key,
+                        struct ble_store_value_cccd *out_value)
+{
+    union ble_store_value *store_value;
+    union ble_store_key *store_key;
+    int rc;
+
+    store_key = (void *)key;
+    store_value = (void *)out_value;
+    rc = ble_store_read(BLE_STORE_OBJ_TYPE_CCCD_IDX, store_key, store_value);
+    return rc;
+}
+
+int
 ble_store_write_cccd(struct ble_store_value_cccd *value)
 {
     union ble_store_value *store_value;


[2/2] incubator-mynewt-core git commit: BLE Host - Don't require key in persist write.

Posted by cc...@apache.org.
BLE Host - Don't require key in persist write.


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/ddd76b6b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/ddd76b6b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/ddd76b6b

Branch: refs/heads/develop
Commit: ddd76b6b3953ba5eab18a39cdcc3d83bf2e3cc5c
Parents: bd4a456
Author: Christopher Collins <cc...@apache.org>
Authored: Fri May 20 18:24:12 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Sat May 21 08:57:12 2016 -0700

----------------------------------------------------------------------
 apps/bleprph/src/bleprph.h                   |  7 ++-
 apps/bleprph/src/keystore.c                  | 18 ++++----
 apps/bleprph/src/main.c                      | 21 ++++++---
 apps/bletiny/src/bletiny_priv.h              |  9 ++--
 apps/bletiny/src/keystore.c                  | 18 ++++----
 apps/bletiny/src/main.c                      | 22 ++++-----
 net/nimble/host/include/host/ble_store.h     | 55 ++++++++++++++---------
 net/nimble/host/src/ble_gatts.c              | 34 +++++++++++---
 net/nimble/host/src/ble_l2cap_sm.c           | 18 +++-----
 net/nimble/host/src/ble_store.c              | 31 ++++++++++---
 net/nimble/host/src/test/ble_hs_test.c       |  1 -
 net/nimble/host/src/test/ble_l2cap_sm_test.c |  7 ++-
 12 files changed, 147 insertions(+), 94 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/apps/bleprph/src/bleprph.h
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/bleprph.h b/apps/bleprph/src/bleprph.h
index 1a9b150..873d35b 100644
--- a/apps/bleprph/src/bleprph.h
+++ b/apps/bleprph/src/bleprph.h
@@ -52,9 +52,8 @@ extern const uint8_t gatt_svr_chr_bleprph_write[16];
 void gatt_svr_init(void);
 
 /** Keystore. */
-int keystore_lookup(uint16_t ediv, uint64_t rand_num,
-                    void *out_ltk, int *out_authenticated);
-int keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *key,
-                 int authenticated);
+int keystore_lookup(struct ble_store_key_ltk *store_key, uint8_t *out_ltk,
+                    int *out_authenticated);
+int keystore_add(struct ble_store_value_ltk *store_value);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/apps/bleprph/src/keystore.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/keystore.c b/apps/bleprph/src/keystore.c
index 5f3ff55..efa17ea 100644
--- a/apps/bleprph/src/keystore.c
+++ b/apps/bleprph/src/keystore.c
@@ -53,8 +53,8 @@ static int keystore_num_entries;
  * @return                      0 if a key was found; else BLE_HS_ENOENT.
  */
 int
-keystore_lookup(uint16_t ediv, uint64_t rand_num,
-                void *out_ltk, int *out_authenticated)
+keystore_lookup(struct ble_store_key_ltk *store_key, uint8_t *out_ltk,
+                int *out_authenticated)
 {
     struct keystore_entry *entry;
     int i;
@@ -62,7 +62,9 @@ keystore_lookup(uint16_t ediv, uint64_t rand_num,
     for (i = 0; i < keystore_num_entries; i++) {
         entry = keystore_entries + i;
 
-        if (entry->ediv == ediv && entry->rand_num == rand_num) {
+        if (entry->ediv == store_key->ediv &&
+            entry->rand_num == store_key->rand_num) {
+
             memcpy(out_ltk, entry->ltk, sizeof entry->ltk);
             *out_authenticated = entry->authenticated;
 
@@ -80,7 +82,7 @@ keystore_lookup(uint16_t ediv, uint64_t rand_num,
  *                                  full.
  */
 int
-keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *ltk, int authenticated)
+keystore_add(struct ble_store_value_ltk *store_value)
 {
     struct keystore_entry *entry;
 
@@ -91,10 +93,10 @@ keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *ltk, int authenticated)
     entry = keystore_entries + keystore_num_entries;
     keystore_num_entries++;
 
-    entry->ediv = ediv;
-    entry->rand_num = rand_num;
-    memcpy(entry->ltk, ltk, sizeof entry->ltk);
-    entry->authenticated = authenticated;
+    entry->ediv = store_value->ediv;
+    entry->rand_num = store_value->rand_num;
+    memcpy(entry->ltk, store_value->key, sizeof entry->ltk);
+    entry->authenticated = store_value->authenticated;
 
     return 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/apps/bleprph/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/main.c b/apps/bleprph/src/main.c
index f48cdbd..96db35b 100755
--- a/apps/bleprph/src/main.c
+++ b/apps/bleprph/src/main.c
@@ -246,8 +246,7 @@ bleprph_store_read(int obj_type, union ble_store_key *key,
          * result.  The nimble stack will use this key if this function returns
          * success.
          */
-        rc = keystore_lookup(key->ltk.ediv, key->ltk.rand_num,
-                             dst->ltk.key, &authenticated);
+        rc = keystore_lookup(&key->ltk, dst->ltk.key, &authenticated);
         if (rc == 0) {
             dst->ltk.authenticated = authenticated;
             BLEPRPH_LOG(INFO, "ltk=");
@@ -269,9 +268,18 @@ bleprph_store_read(int obj_type, union ble_store_key *key,
     }
 }
 
+static void
+bleprph_print_key_exchange_parms(struct ble_store_value_ltk *ltk)
+{
+    BLEPRPH_LOG(INFO, "ediv=%u rand=%llu authenticated=%d ", ltk->ediv,
+                   ltk->rand_num, ltk->authenticated);
+    BLEPRPH_LOG(INFO, "ltk=");
+    bleprph_print_bytes(ltk->key, 16);
+    BLEPRPH_LOG(INFO, "\n");
+}
+
 static int
-bleprph_store_write(int obj_type, union ble_store_key *key,
-                    union ble_store_value *dst)
+bleprph_store_write(int obj_type, union ble_store_value *val)
 {
     int rc;
 
@@ -282,8 +290,9 @@ bleprph_store_write(int obj_type, union ble_store_key *key,
          * to occur on subsequent connections with this peer (as long as
          * bleprph isn't restarted!).
          */
-        rc = keystore_add(key->ltk.ediv, key->ltk.rand_num,
-                          dst->ltk.key, dst->ltk.authenticated);
+        BLEPRPH_LOG(INFO, "persisting our ltk; ");
+        bleprph_print_key_exchange_parms(&val->ltk);
+        rc = keystore_add(&val->ltk);
         if (rc != 0) {
             BLEPRPH_LOG(INFO, "error persisting LTK; status=%d\n", rc);
         }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/apps/bletiny/src/bletiny_priv.h
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/bletiny_priv.h b/apps/bletiny/src/bletiny_priv.h
index 5ecf2e5..df18890 100644
--- a/apps/bletiny/src/bletiny_priv.h
+++ b/apps/bletiny/src/bletiny_priv.h
@@ -33,6 +33,8 @@ struct ble_gap_crt_params;
 struct hci_adv_params;
 struct ble_l2cap_sig_update_req;
 struct ble_l2cap_sig_update_params;
+struct ble_store_key_ltk;
+struct ble_store_value_ltk;
 
 typedef int cmd_fn(int argc, char **argv);
 struct cmd_entry {
@@ -186,9 +188,8 @@ extern const uint8_t gatt_svr_chr_bleprph_write[16];
 void gatt_svr_init(void);
 
 /** Keystore. */
-int keystore_lookup(uint16_t ediv, uint64_t rand_num,
-                    void *out_ltk, int *out_authenticated);
-int keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *key,
-                 int authenticated);
+int keystore_lookup(struct ble_store_key_ltk *store_key, uint8_t *out_ltk,
+                    int *out_authenticated);
+int keystore_add(struct ble_store_value_ltk *store_value);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/apps/bletiny/src/keystore.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/keystore.c b/apps/bletiny/src/keystore.c
index 5f3ff55..efa17ea 100644
--- a/apps/bletiny/src/keystore.c
+++ b/apps/bletiny/src/keystore.c
@@ -53,8 +53,8 @@ static int keystore_num_entries;
  * @return                      0 if a key was found; else BLE_HS_ENOENT.
  */
 int
-keystore_lookup(uint16_t ediv, uint64_t rand_num,
-                void *out_ltk, int *out_authenticated)
+keystore_lookup(struct ble_store_key_ltk *store_key, uint8_t *out_ltk,
+                int *out_authenticated)
 {
     struct keystore_entry *entry;
     int i;
@@ -62,7 +62,9 @@ keystore_lookup(uint16_t ediv, uint64_t rand_num,
     for (i = 0; i < keystore_num_entries; i++) {
         entry = keystore_entries + i;
 
-        if (entry->ediv == ediv && entry->rand_num == rand_num) {
+        if (entry->ediv == store_key->ediv &&
+            entry->rand_num == store_key->rand_num) {
+
             memcpy(out_ltk, entry->ltk, sizeof entry->ltk);
             *out_authenticated = entry->authenticated;
 
@@ -80,7 +82,7 @@ keystore_lookup(uint16_t ediv, uint64_t rand_num,
  *                                  full.
  */
 int
-keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *ltk, int authenticated)
+keystore_add(struct ble_store_value_ltk *store_value)
 {
     struct keystore_entry *entry;
 
@@ -91,10 +93,10 @@ keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *ltk, int authenticated)
     entry = keystore_entries + keystore_num_entries;
     keystore_num_entries++;
 
-    entry->ediv = ediv;
-    entry->rand_num = rand_num;
-    memcpy(entry->ltk, ltk, sizeof entry->ltk);
-    entry->authenticated = authenticated;
+    entry->ediv = store_value->ediv;
+    entry->rand_num = store_value->rand_num;
+    memcpy(entry->ltk, store_value->key, sizeof entry->ltk);
+    entry->authenticated = store_value->authenticated;
 
     return 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/apps/bletiny/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/main.c b/apps/bletiny/src/main.c
index db60ae5..7a5b073 100755
--- a/apps/bletiny/src/main.c
+++ b/apps/bletiny/src/main.c
@@ -41,6 +41,7 @@
 #include "host/ble_att.h"
 #include "host/ble_gap.h"
 #include "host/ble_gatt.h"
+#include "host/ble_store.h"
 #include "controller/ble_ll.h"
 
 /* XXX: An app should not include private headers from a library.  The bletiny
@@ -169,13 +170,12 @@ bletiny_print_conn_desc(struct ble_gap_conn_desc *desc)
 }
 
 static void
-bletiny_print_key_exchange_parms(uint16_t ediv, uint64_t rand_num, void *ltk,
-                                 int authenticated)
+bletiny_print_key_exchange_parms(struct ble_store_value_ltk *ltk)
 {
-    console_printf("ediv=%u rand=%llu authenticated=%d ", ediv, rand_num,
-                   authenticated);
+    console_printf("ediv=%u rand=%llu authenticated=%d ", ltk->ediv,
+                   ltk->rand_num, ltk->authenticated);
     console_printf("ltk=");
-    bletiny_print_bytes(ltk, 16);
+    bletiny_print_bytes(ltk->key, 16);
     console_printf("\n");
 }
 
@@ -888,8 +888,7 @@ bletiny_store_read(int obj_type, union ble_store_key *key,
          * result.  The nimble stack will use this key if this function returns
          * success.
          */
-        rc = keystore_lookup(key->ltk.ediv, key->ltk.rand_num,
-                             dst->ltk.key, &authenticated);
+        rc = keystore_lookup(&key->ltk, dst->ltk.key, &authenticated);
         if (rc == 0) {
             dst->ltk.authenticated = authenticated;
             console_printf("ltk=");
@@ -912,8 +911,7 @@ bletiny_store_read(int obj_type, union ble_store_key *key,
 }
 
 static int
-bletiny_store_write(int obj_type, union ble_store_key *key,
-                    union ble_store_value *val)
+bletiny_store_write(int obj_type, union ble_store_value *val)
 {
     int rc;
 
@@ -924,10 +922,8 @@ bletiny_store_write(int obj_type, union ble_store_key *key,
          * connections with this peer (as long as bletiny isn't restarted!).
          */
         console_printf("persisting our ltk; ");
-        bletiny_print_key_exchange_parms(key->ltk.ediv, key->ltk.rand_num,
-                                         val->ltk.key, val->ltk.authenticated);
-        rc = keystore_add(key->ltk.ediv, key->ltk.rand_num,
-                          val->ltk.key, val->ltk.authenticated);
+        bletiny_print_key_exchange_parms(&val->ltk);
+        rc = keystore_add(&val->ltk);
         if (rc != 0) {
             console_printf("error persisting ltk; status=%d\n", rc);
         }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/net/nimble/host/include/host/ble_store.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_store.h b/net/nimble/host/include/host/ble_store.h
index 9334acb..d25c238 100644
--- a/net/nimble/host/include/host/ble_store.h
+++ b/net/nimble/host/include/host/ble_store.h
@@ -26,42 +26,53 @@
 #define BLE_STORE_OBJ_TYPE_PEER_LTK     2
 #define BLE_STORE_OBJ_TYPE_CCCD         3
 
-union ble_store_key {
-    struct {
-        uint16_t ediv;
-        uint64_t rand_num;
-    } ltk;
+struct ble_store_key_ltk {
+    uint16_t ediv;
+    uint64_t rand_num;
+};
 
-    struct {
-        uint8_t peer_addr[6];
-        /* XXX: Peer addr type? */
-    } cccd;
+struct ble_store_value_ltk {
+    uint16_t ediv;
+    uint64_t rand_num;
+    uint8_t key[16];
+    unsigned authenticated:1;
 };
 
-union ble_store_value {
-    struct {
-        uint8_t key[16];
-        unsigned authenticated:1;
-    } ltk;
+struct ble_store_key_cccd {
+    uint8_t peer_addr[6];
+    uint8_t peer_addr_type;
+};
 
-    struct {
-        uint16_t flags;
-        unsigned value_changed:1;
-    } cccd;
+struct ble_store_value_cccd {
+    uint8_t peer_addr[6];
+    uint8_t peer_addr_type;
+    uint16_t flags;
+    unsigned value_changed:1;
+};
+
+union ble_store_key {
+    struct ble_store_key_ltk ltk;
+    struct ble_store_key_cccd cccd;
+};
+
+union ble_store_value {
+    struct ble_store_value_ltk ltk;
+    struct ble_store_value_cccd cccd;
 };
 
 typedef int ble_store_read_fn(int obj_type, union ble_store_key *key,
                               union ble_store_value *dst);
 
-typedef int ble_store_write_fn(int obj_type, union ble_store_key *key,
-                               union ble_store_value *val);
+typedef int ble_store_write_fn(int obj_type, union ble_store_value *val);
 
 typedef int ble_store_delete_fn(int obj_type, union ble_store_key *key);
 
 int ble_store_read(int obj_type, union ble_store_key *key,
                    union ble_store_value *val);
-int ble_store_write(int obj_type, union ble_store_key *key,
-                    union ble_store_value *val);
+int ble_store_write(int obj_type, union ble_store_value *val);
 int ble_store_delete(int obj_type, union ble_store_key *key);
 
+int ble_store_write_cccd(struct ble_store_value_cccd *value);
+int ble_store_delete_cccd(struct ble_store_key_cccd *key);
+
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/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 b53a139..62cfe80 100644
--- a/net/nimble/host/src/ble_gatts.c
+++ b/net/nimble/host/src/ble_gatts.c
@@ -22,6 +22,7 @@
 #include "console/console.h"
 #include "nimble/ble.h"
 #include "host/ble_uuid.h"
+#include "host/ble_store.h"
 #include "ble_hs_priv.h"
 
 #define BLE_GATTS_INCLUDE_SZ    6
@@ -526,11 +527,17 @@ ble_gatts_clt_cfg_find(struct ble_gatts_clt_cfg *cfgs,
     }
 }
 
+struct ble_gatts_clt_cfg_record {
+    unsigned write:1;
+    struct ble_store_key_cccd key;
+    struct ble_store_value_cccd value;
+};
+
 static int
 ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
                                 uint8_t *uuid128, uint8_t att_op,
                                 struct ble_att_svr_access_ctxt *ctxt,
-                                int *out_persist_flags)
+                                struct ble_gatts_clt_cfg_record *out_record)
 {
     struct ble_gatts_clt_cfg *clt_cfg;
     uint16_t chr_def_handle;
@@ -539,7 +546,8 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
 
     static uint8_t buf[2];
 
-    *out_persist_flags = -1;
+    /* Assume nothing needs to be persisted. */
+    out_record->write = 0;
 
     /* We always register the client characteristics descriptor with handle
      * (chr_def + 2).
@@ -579,7 +587,15 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
         }
 
         clt_cfg->flags = flags;
-        *out_persist_flags = flags;
+
+        /* Successful writes get persisted for bonded connections. */
+        if (conn->bhc_sec_state.bonded) {
+            out_record->key.peer_addr_type = conn->bhc_addr_type;
+            memcpy(out_record->key.peer_addr, conn->bhc_addr, 6);
+            out_record->value.flags = clt_cfg->flags;
+            out_record->value.value_changed = 0;
+            out_record->write = 1;
+        }
         break;
 
     default:
@@ -596,8 +612,8 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
                          struct ble_att_svr_access_ctxt *ctxt,
                          void *arg)
 {
+    struct ble_gatts_clt_cfg_record persist_record;
     struct ble_hs_conn *conn;
-    int persist_flags;
     int rc;
 
     ble_hs_lock();
@@ -607,13 +623,17 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
         rc = BLE_ATT_ERR_UNLIKELY;
     } else {
         rc = ble_gatts_clt_cfg_access_locked(conn, attr_handle, uuid128, op,
-                                             ctxt, &persist_flags);
+                                             ctxt, &persist_record);
     }
 
     ble_hs_unlock();
 
-    if (rc == 0 && persist_flags != -1) {
-        /* XXX: Persist flags. */
+    if (rc == 0 && persist_record.write) {
+        if (persist_record.value.flags == 0) {
+            rc = ble_store_delete_cccd(&persist_record.key);
+        } else {
+            rc = ble_store_write_cccd(&persist_record.value);
+        }
     }
 
     return rc;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/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 1c9ed4d..18e6b52 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -482,34 +482,28 @@ static void
 ble_l2cap_sm_key_exchange_events(struct ble_l2cap_sm_proc *proc)
 {
     union ble_store_value store_value;
-    union ble_store_key store_key;
 
     if (proc->our_keys.ediv_rand_valid && proc->our_keys.ltk_valid) {
-        store_key.ltk.ediv = proc->our_keys.ediv;
-        store_key.ltk.rand_num = proc->our_keys.rand_val;
+        store_value.ltk.ediv = proc->our_keys.ediv;
+        store_value.ltk.rand_num = proc->our_keys.rand_val;
         memcpy(store_value.ltk.key, proc->our_keys.ltk,
                sizeof store_value.ltk.key);
         store_value.ltk.authenticated =
             !!(proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED);
-        ble_store_write(BLE_STORE_OBJ_TYPE_OUR_LTK, &store_key, &store_value);
+        ble_store_write(BLE_STORE_OBJ_TYPE_OUR_LTK, &store_value);
     }
 
     if (proc->peer_keys.ediv_rand_valid && proc->peer_keys.ltk_valid) {
-        store_key.ltk.ediv = proc->peer_keys.ediv;
-        store_key.ltk.rand_num = proc->peer_keys.rand_val;
+        store_value.ltk.ediv = proc->peer_keys.ediv;
+        store_value.ltk.rand_num = proc->peer_keys.rand_val;
         memcpy(store_value.ltk.key, proc->peer_keys.ltk,
                sizeof store_value.ltk.key);
         store_value.ltk.authenticated =
             !!(proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED);
-        ble_store_write(BLE_STORE_OBJ_TYPE_PEER_LTK, &store_key, &store_value);
+        ble_store_write(BLE_STORE_OBJ_TYPE_PEER_LTK, &store_value);
     }
 
     /* XXX: Persist other key data. */
-
-    //proc->our_keys.is_ours = 1;
-    //proc->peer_keys.is_ours = 0;
-    //ble_gap_key_exchange_event(proc->conn_handle, &proc->our_keys);
-    //ble_gap_key_exchange_event(proc->conn_handle, &proc->peer_keys);
 }
 
 static void

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/net/nimble/host/src/ble_store.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_store.c b/net/nimble/host/src/ble_store.c
index dcd0699..de4cc7a 100644
--- a/net/nimble/host/src/ble_store.c
+++ b/net/nimble/host/src/ble_store.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -29,22 +29,21 @@ ble_store_read(int obj_type, union ble_store_key *key,
     if (ble_hs_cfg.store_read_cb == NULL) {
         rc = BLE_HS_ENOTSUP;
     } else {
-        rc = ble_hs_cfg.store_read_cb(obj_type, key, val); 
+        rc = ble_hs_cfg.store_read_cb(obj_type, key, val);
     }
 
     return rc;
 }
 
 int
-ble_store_write(int obj_type, union ble_store_key *key,
-                union ble_store_value *val)
+ble_store_write(int obj_type, union ble_store_value *val)
 {
     int rc;
 
     if (ble_hs_cfg.store_write_cb == NULL) {
         rc = BLE_HS_ENOTSUP;
     } else {
-        rc = ble_hs_cfg.store_write_cb(obj_type, key, val); 
+        rc = ble_hs_cfg.store_write_cb(obj_type, val);
     }
 
     return rc;
@@ -63,3 +62,25 @@ ble_store_delete(int obj_type, union ble_store_key *key)
 
     return rc;
 }
+
+int
+ble_store_write_cccd(struct ble_store_value_cccd *value)
+{
+    union ble_store_value *store_value;
+    int rc;
+
+    store_value = (void *)value;
+    rc = ble_store_write(BLE_STORE_OBJ_TYPE_CCCD, store_value);
+    return rc;
+}
+
+int
+ble_store_delete_cccd(struct ble_store_key_cccd *key)
+{
+    union ble_store_key *store_key;
+    int rc;
+
+    store_key = (void *)key;
+    rc = ble_store_delete(BLE_STORE_OBJ_TYPE_CCCD, store_key);
+    return rc;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/net/nimble/host/src/test/ble_hs_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test.c b/net/nimble/host/src/test/ble_hs_test.c
index 19d5e38..aaaf19f 100644
--- a/net/nimble/host/src/test/ble_hs_test.c
+++ b/net/nimble/host/src/test/ble_hs_test.c
@@ -47,7 +47,6 @@ int
 main(void)
 {
     tu_config.tc_print_results = 1;
-    tu_config.tc_system_assert = 1;
     tu_init();
 
     ble_att_clt_test_all();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ddd76b6b/net/nimble/host/src/test/ble_l2cap_sm_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_l2cap_sm_test.c b/net/nimble/host/src/test/ble_l2cap_sm_test.c
index 111d66e..1159028 100644
--- a/net/nimble/host/src/test/ble_l2cap_sm_test.c
+++ b/net/nimble/host/src/test/ble_l2cap_sm_test.c
@@ -161,15 +161,14 @@ ble_l2cap_sm_test_util_store_read(int obj_type, union ble_store_key *key,
 }
 
 static int
-ble_l2cap_sm_test_util_store_write(int obj_type, union ble_store_key *key,
-                                   union ble_store_value *val)
+ble_l2cap_sm_test_util_store_write(int obj_type, union ble_store_value *val)
 {
     ble_l2cap_sm_test_store_obj_type = obj_type;
 
     switch (obj_type) {
     case BLE_STORE_OBJ_TYPE_OUR_LTK:
-        ble_l2cap_sm_test_saved_ediv = key->ltk.ediv;
-        ble_l2cap_sm_test_saved_rand = key->ltk.rand_num;
+        ble_l2cap_sm_test_saved_ediv = val->ltk.ediv;
+        ble_l2cap_sm_test_saved_rand = val->ltk.rand_num;
         memcpy(ble_l2cap_sm_test_saved_ltk, val->ltk.key, sizeof val->ltk.key);
         ble_l2cap_sm_test_saved_authenticated = val->ltk.authenticated;
         ble_l2cap_sm_test_saved_present = 1;