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/19 06:33:17 UTC

[06/12] incubator-mynewt-core git commit: bletiny - Copy bleprph's gatt_svr code.

bletiny - Copy bleprph's gatt_svr code.


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

Branch: refs/heads/develop
Commit: e404f064fce8784133f3f05a1090a02015d82779
Parents: 47a1ead
Author: Christopher Collins <cc...@apache.org>
Authored: Wed May 18 14:43:20 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Wed May 18 14:43:20 2016 -0700

----------------------------------------------------------------------
 apps/bletiny/src/bletiny_priv.h |  20 +-
 apps/bletiny/src/gatt_svr.c     | 457 +++++++++++++++++++++++++++++++++++
 apps/bletiny/src/keystore.c     | 100 ++++++++
 apps/bletiny/src/main.c         | 119 ++++-----
 apps/bletiny/src/periph.c       | 344 --------------------------
 5 files changed, 621 insertions(+), 419 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e404f064/apps/bletiny/src/bletiny_priv.h
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/bletiny_priv.h b/apps/bletiny/src/bletiny_priv.h
index fc85bc8..279f96b 100644
--- a/apps/bletiny/src/bletiny_priv.h
+++ b/apps/bletiny/src/bletiny_priv.h
@@ -115,7 +115,6 @@ int parse_arg_uuid(char *name, uint8_t *dst_uuid128);
 int parse_err_too_few_args(char *cmd_name);
 int parse_arg_all(int argc, char **argv);
 int cmd_init(void);
-void periph_init(void);
 int nm_chr_access(uint16_t conn_handle, uint16_t attr_handle,
                   uint8_t op, union ble_gatt_access_ctxt *ctxt,
                   void *arg);
@@ -174,4 +173,23 @@ int bletiny_sec_restart(uint16_t conn_handle, uint8_t *ltk, uint16_t ediv,
 #define BLETINY_LOG(lvl, ...) \
     LOG_ ## lvl(&bletiny_log, BLETINY_LOG_MODULE, __VA_ARGS__)
 
+/** GATT server. */
+#define GATT_SVR_SVC_ALERT_UUID               0x1811
+#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID   0x2A47
+#define GATT_SVR_CHR_NEW_ALERT                0x2A46
+#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID   0x2A48
+#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID      0x2A45
+#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT        0x2A44
+extern const uint8_t gatt_svr_svc_bleprph[16];
+extern const uint8_t gatt_svr_chr_bleprph_read[16];
+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);
+
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e404f064/apps/bletiny/src/gatt_svr.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/gatt_svr.c b/apps/bletiny/src/gatt_svr.c
new file mode 100644
index 0000000..71df9b0
--- /dev/null
+++ b/apps/bletiny/src/gatt_svr.c
@@ -0,0 +1,457 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * 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,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "bsp/bsp.h"
+#include "console/console.h"
+#include "host/ble_hs.h"
+#include "bletiny_priv.h"
+
+/**
+ * The vendor specific "bleprph" service consists of two characteristics:
+ *     o "read": a single-byte characteristic that can only be read of an
+ *       encryptted connection.
+ *     o "write": a single-byte characteristic that can always be read, but
+ *       can only be written over an encrypted connection.
+ */
+
+/* 59462f12-9543-9999-12c8-58b459a2712d */
+const uint8_t gatt_svr_svc_bleprph[16] = {
+    0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
+    0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59
+};
+
+/* 5c3a659e-897e-45e1-b016-007107c96df6 */
+const uint8_t gatt_svr_chr_bleprph_read[16] = {
+    0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
+    0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c
+};
+
+/* 5c3a659e-897e-45e1-b016-007107c96df7 */
+const uint8_t gatt_svr_chr_bleprph_write[16] = {
+    0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
+    0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c
+};
+
+static uint8_t gatt_svr_nimble_test_read_val;
+static uint8_t gatt_svr_nimble_test_write_val;
+
+static int
+gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
+                        union ble_gatt_access_ctxt *ctxt, void *arg);
+static int
+gatt_svr_chr_access_gatt(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
+                         union ble_gatt_access_ctxt *ctxt, void *arg);
+static int
+gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
+                          uint8_t op, union ble_gatt_access_ctxt *ctxt,
+                          void *arg);
+
+static int
+gatt_svr_chr_access_bleprph(uint16_t conn_handle, uint16_t attr_handle,
+                                uint8_t op, union ble_gatt_access_ctxt *ctxt,
+                                void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+    {
+        /*** Service: GAP. */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(BLE_GAP_SVC_UUID16),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            /*** Characteristic: Device Name. */
+            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_DEVICE_NAME),
+            .access_cb = gatt_svr_chr_access_gap,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            /*** Characteristic: Appearance. */
+            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_APPEARANCE),
+            .access_cb = gatt_svr_chr_access_gap,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            /*** Characteristic: Peripheral Privacy Flag. */
+            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG),
+            .access_cb = gatt_svr_chr_access_gap,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            /*** Characteristic: Reconnection Address. */
+            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_RECONNECT_ADDR),
+            .access_cb = gatt_svr_chr_access_gap,
+            .flags = BLE_GATT_CHR_F_WRITE,
+        }, {
+            /*** Characteristic: Peripheral Preferred Connection Parameters. */
+            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS),
+            .access_cb = gatt_svr_chr_access_gap,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            0, /* No more characteristics in this service. */
+        } },
+    },
+
+    {
+        /*** Service: GATT */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(BLE_GATT_SVC_UUID16),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(BLE_GATT_CHR_SERVICE_CHANGED_UUID16),
+            .access_cb = gatt_svr_chr_access_gatt,
+            .flags = BLE_GATT_CHR_F_INDICATE,
+        }, {
+            0, /* No more characteristics in this service. */
+        } },
+    },
+
+    {
+        /*** Alert Notification Service. */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(GATT_SVR_SVC_ALERT_UUID),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_NEW_ALERT),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_NOTIFY,
+        }, {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_UNR_ALERT_STAT_UUID),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_NOTIFY,
+        }, {
+            .uuid128 = BLE_UUID16(GATT_SVR_CHR_ALERT_NOT_CTRL_PT),
+            .access_cb = gatt_svr_chr_access_alert,
+            .flags = BLE_GATT_CHR_F_WRITE,
+        }, {
+            0, /* No more characteristics in this service. */
+        } },
+    },
+
+    {
+        /*** Service: bleprph. */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = (void *)gatt_svr_svc_bleprph,
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            /*** Characteristic: Read. */
+            .uuid128 = (void *)gatt_svr_chr_bleprph_read,
+            .access_cb = gatt_svr_chr_access_bleprph,
+            .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
+        }, {
+            /*** Characteristic: Write. */
+            .uuid128 = (void *)gatt_svr_chr_bleprph_write,
+            .access_cb = gatt_svr_chr_access_bleprph,
+            .flags = BLE_GATT_CHR_F_READ |
+                     BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
+        }, {
+            0, /* No more characteristics in this service. */
+        } },
+    },
+
+    {
+        0, /* No more services. */
+    },
+};
+
+static int
+gatt_svr_chr_write(uint8_t op, union ble_gatt_access_ctxt *ctxt,
+                   uint16_t min_len, uint16_t max_len, void *dst,
+                   uint16_t *len)
+{
+    assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
+    if (ctxt->chr_access.len < min_len ||
+        ctxt->chr_access.len > max_len) {
+        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+    }
+    memcpy(dst, ctxt->chr_access.data, ctxt->chr_access.len);
+    if (len != NULL) {
+        *len = ctxt->chr_access.len;
+    }
+
+    return 0;
+}
+
+static int
+gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
+                        union ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    uint16_t uuid16;
+
+    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
+    assert(uuid16 != 0);
+
+    switch (uuid16) {
+    case BLE_GAP_CHR_UUID16_DEVICE_NAME:
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = (void *)bletiny_device_name;
+        ctxt->chr_access.len = strlen(bletiny_device_name);
+        break;
+
+    case BLE_GAP_CHR_UUID16_APPEARANCE:
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = (void *)&bletiny_appearance;
+        ctxt->chr_access.len = sizeof bletiny_appearance;
+        break;
+
+    case BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG:
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = (void *)&bletiny_privacy_flag;
+        ctxt->chr_access.len = sizeof bletiny_privacy_flag;
+        break;
+
+    case BLE_GAP_CHR_UUID16_RECONNECT_ADDR:
+        assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
+        if (ctxt->chr_access.len != sizeof bletiny_reconnect_addr) {
+            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+        }
+        memcpy(bletiny_reconnect_addr, ctxt->chr_access.data,
+               sizeof bletiny_reconnect_addr);
+        break;
+
+    case BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS:
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = (void *)&bletiny_pref_conn_params;
+        ctxt->chr_access.len = sizeof bletiny_pref_conn_params;
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+
+    return 0;
+}
+
+static int
+gatt_svr_chr_access_gatt(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
+                         union ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    uint16_t uuid16;
+
+    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
+    assert(uuid16 != 0);
+
+    switch (uuid16) {
+    case BLE_GATT_CHR_SERVICE_CHANGED_UUID16:
+        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+            if (ctxt->chr_access.len != sizeof bletiny_gatt_service_changed) {
+                return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+            }
+            memcpy(bletiny_gatt_service_changed, ctxt->chr_access.data,
+                   sizeof bletiny_gatt_service_changed);
+        } else if (op == BLE_GATT_ACCESS_OP_READ_CHR) {
+            ctxt->chr_access.data = (void *)&bletiny_gatt_service_changed;
+            ctxt->chr_access.len = sizeof bletiny_gatt_service_changed;
+        }
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+
+    return 0;
+}
+
+#define GATT_SVR_NEW_ALERT_VAL_MAX_LEN    64
+
+static const uint8_t gatt_svr_new_alert_cat = 0x01; /* Simple alert. */
+static uint8_t gatt_svr_new_alert_val[GATT_SVR_NEW_ALERT_VAL_MAX_LEN];
+static uint16_t gatt_svr_new_alert_val_len;
+static const uint8_t gatt_svr_unr_alert_cat = 0x01; /* Simple alert. */
+static uint16_t gatt_svr_unr_alert_stat;
+static uint16_t gatt_svr_alert_not_ctrl_pt;
+
+static int
+gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
+                          uint8_t op, union ble_gatt_access_ctxt *ctxt,
+                          void *arg)
+{
+    uint16_t uuid16;
+    int rc;
+
+    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
+    assert(uuid16 != 0);
+
+    switch (uuid16) {
+    case GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID:
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = (void *)&gatt_svr_new_alert_cat;
+        ctxt->chr_access.len = sizeof gatt_svr_new_alert_cat;
+        return 0;
+
+    case GATT_SVR_CHR_NEW_ALERT:
+        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+            rc = gatt_svr_chr_write(op, ctxt, 0, sizeof gatt_svr_new_alert_val,
+                                  gatt_svr_new_alert_val,
+                                  &gatt_svr_new_alert_val_len);
+            return rc;
+        } else if (op == BLE_GATT_ACCESS_OP_READ_CHR) {
+            ctxt->chr_access.data = (void *)&gatt_svr_new_alert_val;
+            ctxt->chr_access.len = sizeof gatt_svr_new_alert_val;
+            return 0;
+        }
+
+    case GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID:
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = (void *)&gatt_svr_unr_alert_cat;
+        ctxt->chr_access.len = sizeof gatt_svr_unr_alert_cat;
+        return 0;
+
+    case GATT_SVR_CHR_UNR_ALERT_STAT_UUID:
+        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+            rc = gatt_svr_chr_write(op, ctxt, 2, 2, &gatt_svr_unr_alert_stat,
+                                    NULL);
+        } else {
+            ctxt->chr_access.data = (void *)&gatt_svr_unr_alert_stat;
+            ctxt->chr_access.len = sizeof gatt_svr_unr_alert_stat;
+            rc = 0;
+        }
+        return rc;
+
+    case GATT_SVR_CHR_ALERT_NOT_CTRL_PT:
+        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+            rc = gatt_svr_chr_write(op, ctxt, 2, 2,
+                                    &gatt_svr_alert_not_ctrl_pt, NULL);
+        } else {
+            rc = BLE_ATT_ERR_UNLIKELY;
+        }
+        return rc;
+
+    default:
+        assert(0);
+        return BLE_ATT_ERR_UNLIKELY;
+    }
+}
+
+static int
+gatt_svr_chr_access_bleprph(uint16_t conn_handle, uint16_t attr_handle,
+                            uint8_t op, union ble_gatt_access_ctxt *ctxt,
+                            void *arg)
+{
+    void *uuid128;
+    int rc;
+
+    uuid128 = ctxt->chr_access.chr->uuid128;
+
+    /* Determine which characteristic is being accessed by examining its
+     * 128-bit UUID.
+     */
+
+    if (memcmp(uuid128, gatt_svr_chr_bleprph_read, 16) == 0) {
+        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+        ctxt->chr_access.data = &gatt_svr_nimble_test_read_val;
+        ctxt->chr_access.len = sizeof gatt_svr_nimble_test_read_val;
+        return 0;
+    }
+
+    if (memcmp(uuid128, gatt_svr_chr_bleprph_write, 16) == 0) {
+        switch (op) {
+        case BLE_GATT_ACCESS_OP_READ_CHR:
+            ctxt->chr_access.data = &gatt_svr_nimble_test_write_val;
+            ctxt->chr_access.len = sizeof gatt_svr_nimble_test_write_val;
+            return 0;
+
+        case BLE_GATT_ACCESS_OP_WRITE_CHR:
+            rc = gatt_svr_chr_write(op, ctxt,
+                                    sizeof gatt_svr_nimble_test_write_val,
+                                    sizeof gatt_svr_nimble_test_write_val,
+                                    &gatt_svr_nimble_test_write_val, NULL);
+            return rc;
+
+        default:
+            assert(0);
+            return BLE_ATT_ERR_UNLIKELY;
+        }
+    }
+
+    /* Unknown characteristic; the nimble stack should not have called this
+     * function.
+     */
+    assert(0);
+    return BLE_ATT_ERR_UNLIKELY;
+}
+
+static char *
+gatt_svr_uuid_to_s(void *uuid128, char *dst)
+{
+    uint16_t uuid16;
+    uint8_t *u8p;
+
+    uuid16 = ble_uuid_128_to_16(uuid128);
+    if (uuid16 != 0) {
+        sprintf(dst, "0x%04x", uuid16);
+        return dst;
+    }
+
+    u8p = uuid128;
+
+    sprintf(dst,      "%02x%02x%02x%02x-", u8p[15], u8p[14], u8p[13], u8p[12]);
+    sprintf(dst + 9,  "%02x%02x-%02x%02x-", u8p[11], u8p[10], u8p[9], u8p[8]);
+    sprintf(dst + 19, "%02x%02x%02x%02x%02x%02x%02x%02x",
+            u8p[7], u8p[6], u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
+
+    return dst;
+}
+
+static void
+gatt_svr_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, void *arg)
+{
+    char buf[40];
+
+    switch (op) {
+    case BLE_GATT_REGISTER_OP_SVC:
+        BLETINY_LOG(DEBUG, "registered service %s with handle=%d\n",
+                    gatt_svr_uuid_to_s(ctxt->svc_reg.svc->uuid128, buf),
+                    ctxt->svc_reg.handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_CHR:
+        BLETINY_LOG(DEBUG, "registering characteristic %s with "
+                           "def_handle=%d val_handle=%d\n",
+                    gatt_svr_uuid_to_s(ctxt->chr_reg.chr->uuid128, buf),
+                    ctxt->chr_reg.def_handle,
+                    ctxt->chr_reg.val_handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_DSC:
+        BLETINY_LOG(DEBUG, "registering descriptor %s with handle=%d "
+                           "chr_handle=%d\n",
+                    gatt_svr_uuid_to_s(ctxt->dsc_reg.dsc->uuid128, buf),
+                    ctxt->dsc_reg.dsc_handle,
+                    ctxt->dsc_reg.chr_def_handle);
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+}
+
+void
+gatt_svr_init(void)
+{
+    int rc;
+
+    rc = ble_gatts_register_svcs(gatt_svr_svcs, gatt_svr_register_cb, NULL);
+    assert(rc == 0);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e404f064/apps/bletiny/src/keystore.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/keystore.c b/apps/bletiny/src/keystore.c
new file mode 100644
index 0000000..5f3ff55
--- /dev/null
+++ b/apps/bletiny/src/keystore.c
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * 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,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * This file implements a simple in-RAM key database for long-term keys.  A key
+ * is inserted into the database immediately after a successful pairing
+ * procedure.  A key is retrieved from the database when the central performs
+ * the encryption procedure (bonding).
+ *
+ * As this database is only stored in RAM, its contents are lost if bleprph is
+ * restarted.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+#include "host/ble_hs.h"
+
+#define KEYSTORE_MAX_ENTRIES   4
+
+struct keystore_entry {
+    uint64_t rand_num;
+    uint16_t ediv;
+    uint8_t ltk[16];
+
+    unsigned authenticated:1;
+
+    /* XXX: authreq. */
+};
+
+static struct keystore_entry keystore_entries[KEYSTORE_MAX_ENTRIES];
+static int keystore_num_entries;
+
+/**
+ * Searches the database for a long-term key matching the specified criteria.
+ *
+ * @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)
+{
+    struct keystore_entry *entry;
+    int i;
+
+    for (i = 0; i < keystore_num_entries; i++) {
+        entry = keystore_entries + i;
+
+        if (entry->ediv == ediv && entry->rand_num == rand_num) {
+            memcpy(out_ltk, entry->ltk, sizeof entry->ltk);
+            *out_authenticated = entry->authenticated;
+
+            return 0;
+        }
+    }
+
+    return BLE_HS_ENOENT;
+}
+
+/**
+ * Adds the specified key to the database.
+ *
+ * @return                      0 on success; BLE_HS_ENOMEM if the database is
+ *                                  full.
+ */
+int
+keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *ltk, int authenticated)
+{
+    struct keystore_entry *entry;
+
+    if (keystore_num_entries >= KEYSTORE_MAX_ENTRIES) {
+        return BLE_HS_ENOMEM;
+    }
+
+    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;
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e404f064/apps/bletiny/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/main.c b/apps/bletiny/src/main.c
index 9c07f76..7e84792 100755
--- a/apps/bletiny/src/main.c
+++ b/apps/bletiny/src/main.c
@@ -96,8 +96,6 @@ struct os_mempool default_mbuf_mpool;
 #define BLETINY_MAX_DSCS               1
 #endif
 
-#define BLETINY_MAX_LTKS                4
-
 struct os_eventq bletiny_evq;
 struct os_task bletiny_task;
 bssnz_t os_stack_t bletiny_stack[BLETINY_STACK_SIZE];
@@ -130,9 +128,6 @@ uint8_t bletiny_reconnect_addr[6];
 uint8_t bletiny_pref_conn_params[8];
 uint8_t bletiny_gatt_service_changed[4];
 
-struct ble_gap_ltk_params bletiny_ltks[BLETINY_MAX_LTKS];
-int bletiny_num_ltks;
-
 #define XSTR(s) STR(s)
 #define STR(s) #s
 
@@ -878,54 +873,10 @@ bletiny_on_notify(uint16_t conn_handle, uint16_t attr_handle,
 }
 
 static int
-bletiny_ltk_lookup(struct ble_gap_ltk_params *ltk_params)
-{
-    struct ble_gap_ltk_params *ltk;
-    int i;
-
-    for (i = 0; i < bletiny_num_ltks; i++) {
-        ltk = bletiny_ltks + i;
-
-        if (ltk->ediv == ltk_params->ediv &&
-            ltk->rand_num == ltk_params->rand_num) {
-
-            memcpy(ltk_params->ltk, ltk->ltk, sizeof ltk_params->ltk);
-            ltk_params->authenticated = ltk->authenticated;
-
-            return 0;
-        }
-    }
-
-    return BLE_HS_ENOENT;
-}
-
-static int
-bletiny_ltk_add(uint16_t ediv, uint64_t rand_num, uint8_t *key,
-                int authenticated)
-{
-    struct ble_gap_ltk_params *ltk;
-
-    if (bletiny_num_ltks >= BLETINY_MAX_LTKS) {
-        return BLE_HS_ENOMEM;
-    }
-
-    ltk = bletiny_ltks + bletiny_num_ltks;
-    bletiny_num_ltks++;
-
-    ltk->ediv = ediv;
-    ltk->rand_num = rand_num;
-    memcpy(ltk->ltk, key, sizeof ltk->ltk);
-    ltk->authenticated = authenticated;
-
-    return 0;
-}
-
-/* XXX: LTK clear. */
-
-static int
-bletiny_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
+bletiny_gap_event(int event, int status, struct ble_gap_conn_ctxt *ctxt,
                    void *arg)
 {
+    int authenticated;
     int conn_idx;
     int rc;
 
@@ -967,22 +918,23 @@ bletiny_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
         *ctxt->update.self_params = *ctxt->update.peer_params;
         return 0;
 
-    case BLE_GAP_EVENT_SECURITY:
-        console_printf("security event; status=%d ", status);
-        bletiny_print_conn_desc(ctxt->desc);
-        console_printf("\n");
-        return 0;
-
-    case BLE_GAP_EVENT_PASSKEY_ACTION:
-        console_printf("passkey action event; status=%d ", status);
-        bletiny_print_passkey_action_parms(ctxt->passkey_action);
-        return 0;
-
     case BLE_GAP_EVENT_LTK_REQUEST:
+        /* An encryption procedure (bonding) is being attempted.  The nimble
+         * stack is asking us to look in our key database for a long-term key
+         * corresponding to the specified ediv and random number.
+         */
         console_printf("looking up ltk with ediv=0x%02x rand=0x%llx\n",
                        ctxt->ltk_params->ediv, ctxt->ltk_params->rand_num);
-        rc = bletiny_ltk_lookup(ctxt->ltk_params);
+
+        /* Perform a key lookup and populate the context object with the
+         * result.  The nimble stack will use this key if this function returns
+         * success.
+         */
+        rc = keystore_lookup(ctxt->ltk_params->ediv,
+                             ctxt->ltk_params->rand_num, ctxt->ltk_params->ltk,
+                             &authenticated);
         if (rc == 0) {
+            ctxt->ltk_params->authenticated = authenticated;
             console_printf("ltk=");
             bletiny_print_bytes(ctxt->ltk_params->ltk,
                                 sizeof ctxt->ltk_params->ltk);
@@ -990,26 +942,45 @@ bletiny_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
         } else {
             console_printf("no matching ltk\n");
         }
+
+        /* Indicate whether we were able to find an appropriate key. */
         return rc;
 
     case BLE_GAP_EVENT_KEY_EXCHANGE:
         console_printf("key exchange event; status=%d ", status);
         bletiny_print_key_exchange_parms(ctxt->key_params);
 
+        /* The central is sending us key information or vice-versa.  If the
+         * central is doing the sending, save the long-term key in the in-RAM
+         * database.  This permits bonding to occur on subsequent connections
+         * with this peer (as long as bletiny isn't restarted!).
+         */
+
         if (ctxt->key_params->is_ours   &&
             ctxt->key_params->ltk_valid &&
             ctxt->key_params->ediv_rand_valid) {
 
-            rc = bletiny_ltk_add(ctxt->key_params->ediv,
-                                 ctxt->key_params->rand_val,
-                                 ctxt->key_params->ltk,
-                                 ctxt->desc->sec_state.authenticated);
+            rc = keystore_add(ctxt->key_params->ediv,
+                              ctxt->key_params->rand_val,
+                              ctxt->key_params->ltk,
+                              ctxt->desc->sec_state.authenticated);
             if (rc != 0) {
                 console_printf("error persisting LTK; status=%d\n", rc);
             }
         }
         return 0;
 
+    case BLE_GAP_EVENT_PASSKEY_ACTION:
+        console_printf("passkey action event; status=%d ", status);
+        bletiny_print_passkey_action_parms(ctxt->passkey_action);
+        return 0;
+
+    case BLE_GAP_EVENT_SECURITY:
+        console_printf("security event; status=%d ", status);
+        bletiny_print_conn_desc(ctxt->desc);
+        console_printf("\n");
+        return 0;
+
     default:
         return 0;
     }
@@ -1230,7 +1201,7 @@ bletiny_adv_start(int disc, int conn, uint8_t *peer_addr, int addr_type,
     int rc;
 
     rc = ble_gap_adv_start(disc, conn, peer_addr, addr_type, params,
-                           bletiny_on_connect, NULL);
+                           bletiny_gap_event, NULL);
     return rc;
 }
 
@@ -1240,7 +1211,7 @@ bletiny_conn_initiate(int addr_type, uint8_t *peer_addr,
 {
     int rc;
 
-    rc = ble_gap_conn_initiate(addr_type, peer_addr, NULL, bletiny_on_connect,
+    rc = ble_gap_conn_initiate(addr_type, peer_addr, NULL, bletiny_gap_event,
                                params);
     return rc;
 }
@@ -1499,11 +1470,11 @@ main(void)
     /* Initialize the BLE host. */
     cfg = ble_hs_cfg_dflt;
     cfg.max_hci_bufs = 3;
-    cfg.max_attrs = 32;
-    cfg.max_services = 4;
-    cfg.max_client_configs = 6;
+    cfg.max_attrs = 36;
+    cfg.max_services = 5;
+    cfg.max_client_configs = (NIMBLE_OPT(MAX_CONNECTIONS) + 1) * 3;
     cfg.max_gattc_procs = 2;
-    cfg.max_l2cap_chans = 3;
+    cfg.max_l2cap_chans = NIMBLE_OPT(MAX_CONNECTIONS) * 3;
     cfg.max_l2cap_sig_procs = 2;
 
     rc = ble_hs_init(&bletiny_evq, &cfg);
@@ -1522,7 +1493,7 @@ main(void)
     htole16(bletiny_pref_conn_params + 4, 0);
     htole16(bletiny_pref_conn_params + 6, BSWAP16(0x100));
 
-    periph_init();
+    gatt_svr_init();
 
     /* Start the OS */
     os_start();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e404f064/apps/bletiny/src/periph.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/periph.c b/apps/bletiny/src/periph.c
deleted file mode 100644
index d0f97e5..0000000
--- a/apps/bletiny/src/periph.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * 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,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <assert.h>
-#include <string.h>
-#include "bsp/bsp.h"
-#include "console/console.h"
-#include "host/ble_hs.h"
-#include "bletiny_priv.h"
-
-#define CHR_F_FULL_ACCESS       (BLE_GATT_CHR_F_READ                |   \
-                                 BLE_GATT_CHR_F_WRITE_NO_RSP        |   \
-                                 BLE_GATT_CHR_F_WRITE               |   \
-                                 BLE_GATT_CHR_F_NOTIFY              |   \
-                                 BLE_GATT_CHR_F_INDICATE)
-
-#define PERIPH_SVC_ALERT_UUID               0x1811
-#define PERIPH_CHR_SUP_NEW_ALERT_CAT_UUID   0x2A47
-#define PERIPH_CHR_NEW_ALERT                0x2A46
-#define PERIPH_CHR_SUP_UNR_ALERT_CAT_UUID   0x2A48
-#define PERIPH_CHR_UNR_ALERT_STAT_UUID      0x2A45
-#define PERIPH_CHR_ALERT_NOT_CTRL_PT        0x2A44
-
-static int
-periph_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                      union ble_gatt_access_ctxt *ctxt, void *arg);
-static int
-periph_chr_access_gatt(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                       union ble_gatt_access_ctxt *ctxt, void *arg);
-static int
-periph_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                        union ble_gatt_access_ctxt *ctxt, void *arg);
-
-static const struct ble_gatt_svc_def periph_svcs[] = {
-    [0] = {
-        /*** Service: GAP. */
-        .type = BLE_GATT_SVC_TYPE_PRIMARY,
-        .uuid128 = BLE_UUID16(BLE_GAP_SVC_UUID16),
-        .characteristics = (struct ble_gatt_chr_def[]) { {
-            /*** Characteristic: Device Name. */
-            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_DEVICE_NAME),
-            .access_cb = periph_chr_access_gap,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            /*** Characteristic: Appearance. */
-            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_APPEARANCE),
-            .access_cb = periph_chr_access_gap,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            /*** Characteristic: Peripheral Privacy Flag. */
-            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG),
-            .access_cb = periph_chr_access_gap,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            /*** Characteristic: Reconnection Address. */
-            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_RECONNECT_ADDR),
-            .access_cb = periph_chr_access_gap,
-            .flags = BLE_GATT_CHR_F_WRITE,
-        }, {
-            /*** Characteristic: Peripheral Preferred Connection Parameters. */
-            .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS),
-            .access_cb = periph_chr_access_gap,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            0, /* No more characteristics in this service. */
-        } },
-    },
-
-    [1] = {
-        /*** Service: GATT */
-        .type = BLE_GATT_SVC_TYPE_PRIMARY,
-        .uuid128 = BLE_UUID16(BLE_GATT_SVC_UUID16),
-        .characteristics = (struct ble_gatt_chr_def[]) { {
-            .uuid128 = BLE_UUID16(BLE_GATT_CHR_SERVICE_CHANGED_UUID16),
-            .access_cb = periph_chr_access_gatt,
-            .flags = BLE_GATT_CHR_F_INDICATE,
-        }, {
-            0, /* No more characteristics in this service. */
-        } },
-    },
-
-    [2] = {
-        /*** Alert Notification Service. */
-        .type = BLE_GATT_SVC_TYPE_PRIMARY,
-        .uuid128 = BLE_UUID16(PERIPH_SVC_ALERT_UUID),
-        .characteristics = (struct ble_gatt_chr_def[]) { {
-            .uuid128 = BLE_UUID16(PERIPH_CHR_SUP_NEW_ALERT_CAT_UUID),
-            .access_cb = periph_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            .uuid128 = BLE_UUID16(PERIPH_CHR_NEW_ALERT),
-            .access_cb = periph_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_NOTIFY,
-        }, {
-            .uuid128 = BLE_UUID16(PERIPH_CHR_SUP_UNR_ALERT_CAT_UUID),
-            .access_cb = periph_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_READ,
-        }, {
-            .uuid128 = BLE_UUID16(PERIPH_CHR_UNR_ALERT_STAT_UUID),
-            .access_cb = periph_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_NOTIFY,
-        }, {
-            .uuid128 = BLE_UUID16(PERIPH_CHR_ALERT_NOT_CTRL_PT),
-            .access_cb = periph_chr_access_alert,
-            .flags = BLE_GATT_CHR_F_WRITE,
-        }, {
-            0, /* No more characteristics in this service. */
-        } },
-    },
-
-    {
-        0, /* No more services. */
-    },
-};
-
-static int
-periph_chr_write(uint8_t op, union ble_gatt_access_ctxt *ctxt,
-                 uint16_t min_len, uint16_t max_len, void *dst, uint16_t *len)
-{
-    assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-    if (ctxt->chr_access.len < min_len ||
-        ctxt->chr_access.len > max_len) {
-        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
-    }
-    memcpy(dst, ctxt->chr_access.data, ctxt->chr_access.len);
-    if (len != NULL) {
-        *len = ctxt->chr_access.len;
-    }
-
-    return 0;
-}
-
-static int
-periph_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                      union ble_gatt_access_ctxt *ctxt, void *arg)
-{
-    uint16_t uuid16;
-
-    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
-    assert(uuid16 != 0);
-
-    switch (uuid16) {
-    case BLE_GAP_CHR_UUID16_DEVICE_NAME:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)bletiny_device_name;
-        ctxt->chr_access.len = strlen(bletiny_device_name);
-        break;
-
-    case BLE_GAP_CHR_UUID16_APPEARANCE:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&bletiny_appearance;
-        ctxt->chr_access.len = sizeof bletiny_appearance;
-        break;
-
-    case BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&bletiny_privacy_flag;
-        ctxt->chr_access.len = sizeof bletiny_privacy_flag;
-        break;
-
-    case BLE_GAP_CHR_UUID16_RECONNECT_ADDR:
-        assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-        if (ctxt->chr_access.len != sizeof bletiny_reconnect_addr) {
-            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
-        }
-        memcpy(bletiny_reconnect_addr, ctxt->chr_access.data,
-               sizeof bletiny_reconnect_addr);
-        break;
-
-    case BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&bletiny_pref_conn_params;
-        ctxt->chr_access.len = sizeof bletiny_pref_conn_params;
-        break;
-
-    default:
-        assert(0);
-        break;
-    }
-
-    return 0;
-}
-
-static int
-periph_chr_access_gatt(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                       union ble_gatt_access_ctxt *ctxt, void *arg)
-{
-    uint16_t uuid16;
-
-    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
-    assert(uuid16 != 0);
-
-    switch (uuid16) {
-    case BLE_GATT_CHR_SERVICE_CHANGED_UUID16:
-        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            if (ctxt->chr_access.len != sizeof bletiny_gatt_service_changed) {
-                return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
-            }
-            memcpy(bletiny_gatt_service_changed, ctxt->chr_access.data,
-                   sizeof bletiny_gatt_service_changed);
-        } else if (op == BLE_GATT_ACCESS_OP_READ_CHR) {
-            ctxt->chr_access.data = (void *)&bletiny_gatt_service_changed;
-            ctxt->chr_access.len = sizeof bletiny_gatt_service_changed;
-        }
-        break;
-
-    default:
-        assert(0);
-        break;
-    }
-
-    return 0;
-}
-
-#define PERIPH_NEW_ALERT_VAL_MAX_LEN    64
-
-static const uint8_t periph_new_alert_cat = 0x01; /* Simple alert. */
-static uint8_t periph_new_alert_val[PERIPH_NEW_ALERT_VAL_MAX_LEN];
-static uint16_t periph_new_alert_val_len;
-static const uint8_t periph_unr_alert_cat = 0x01; /* Simple alert. */
-static uint16_t periph_unr_alert_stat;
-static uint16_t periph_alert_not_ctrl_pt;
-
-static int
-periph_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
-                        union ble_gatt_access_ctxt *ctxt, void *arg)
-{
-    uint16_t uuid16;
-    int rc;
-
-    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
-    assert(uuid16 != 0);
-
-    switch (uuid16) {
-    case PERIPH_CHR_SUP_NEW_ALERT_CAT_UUID:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&periph_new_alert_cat;
-        ctxt->chr_access.len = sizeof periph_new_alert_cat;
-        return 0;
-
-    case PERIPH_CHR_NEW_ALERT:
-        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = periph_chr_write(op, ctxt, 0, sizeof periph_new_alert_val,
-                                  periph_new_alert_val,
-                                  &periph_new_alert_val_len);
-            return rc;
-        } else if (op == BLE_GATT_ACCESS_OP_READ_CHR) {
-            ctxt->chr_access.data = (void *)&periph_new_alert_val;
-            ctxt->chr_access.len = sizeof periph_new_alert_val;
-            return 0;
-        }
-
-    case PERIPH_CHR_SUP_UNR_ALERT_CAT_UUID:
-        assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->chr_access.data = (void *)&periph_unr_alert_cat;
-        ctxt->chr_access.len = sizeof periph_unr_alert_cat;
-        return 0;
-
-    case PERIPH_CHR_UNR_ALERT_STAT_UUID:
-        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = periph_chr_write(op, ctxt, 2, 2, &periph_unr_alert_stat, NULL);
-        } else {
-            ctxt->chr_access.data = (void *)&periph_unr_alert_stat;
-            ctxt->chr_access.len = sizeof periph_unr_alert_stat;
-            rc = 0;
-        }
-        return rc;
-
-    case PERIPH_CHR_ALERT_NOT_CTRL_PT:
-        if (op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = periph_chr_write(op, ctxt, 2, 2, &periph_alert_not_ctrl_pt,
-                                  NULL);
-        } else {
-            rc = BLE_ATT_ERR_UNLIKELY;
-        }
-        return rc;
-
-    default:
-        assert(0);
-        return BLE_ATT_ERR_UNLIKELY;
-    }
-}
-
-static void
-periph_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, void *arg)
-{
-    uint16_t uuid16;
-
-    switch (op) {
-    case BLE_GATT_REGISTER_OP_SVC:
-        uuid16 = ble_uuid_128_to_16(ctxt->svc_reg.svc->uuid128);
-        assert(uuid16 != 0);
-        BLETINY_LOG(DEBUG, "registered service 0x%04x with handle=%d\n",
-                    uuid16, ctxt->svc_reg.handle);
-        break;
-
-    case BLE_GATT_REGISTER_OP_CHR:
-        uuid16 = ble_uuid_128_to_16(ctxt->chr_reg.chr->uuid128);
-        assert(uuid16 != 0);
-        BLETINY_LOG(DEBUG, "registering characteristic 0x%04x with "
-                           "def_handle=%d val_handle=%d\n",
-                    uuid16, ctxt->chr_reg.def_handle,
-                    ctxt->chr_reg.val_handle);
-        break;
-
-    case BLE_GATT_REGISTER_OP_DSC:
-        uuid16 = ble_uuid_128_to_16(ctxt->dsc_reg.dsc->uuid128);
-        assert(uuid16 != 0);
-        BLETINY_LOG(DEBUG, "registering descriptor 0x%04x with handle=%d "
-                           "chr_handle=%d\n",
-                    uuid16, ctxt->dsc_reg.dsc_handle,
-                    ctxt->dsc_reg.chr_def_handle);
-        break;
-
-    default:
-        assert(0);
-        break;
-    }
-}
-
-void
-periph_init(void)
-{
-    int rc;
-
-    rc = ble_gatts_register_svcs(periph_svcs, periph_register_cb, NULL);
-    assert(rc == 0);
-}