From bdc10744fb338ae197692713a0b48a7ccc36f566 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Apr 2020 10:25:59 +0200 Subject: Add Nimble in libs directory --- .../config/include/store/config/ble_store_config.h | 39 ++ .../mynewt-nimble/nimble/host/store/config/pkg.yml | 38 ++ .../host/store/config/src/ble_store_config.c | 533 +++++++++++++++++++++ .../host/store/config/src/ble_store_config_conf.c | 231 +++++++++ .../host/store/config/src/ble_store_config_priv.h | 59 +++ .../nimble/host/store/config/syscfg.yml | 27 ++ .../store/ram/include/store/ram/ble_store_ram.h | 39 ++ .../mynewt-nimble/nimble/host/store/ram/pkg.yml | 37 ++ .../nimble/host/store/ram/src/ble_store_ram.c | 497 +++++++++++++++++++ .../mynewt-nimble/nimble/host/store/ram/syscfg.yml | 23 + 10 files changed, 1523 insertions(+) create mode 100644 src/libs/mynewt-nimble/nimble/host/store/config/include/store/config/ble_store_config.h create mode 100644 src/libs/mynewt-nimble/nimble/host/store/config/pkg.yml create mode 100644 src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config.c create mode 100644 src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_conf.c create mode 100644 src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_priv.h create mode 100644 src/libs/mynewt-nimble/nimble/host/store/config/syscfg.yml create mode 100644 src/libs/mynewt-nimble/nimble/host/store/ram/include/store/ram/ble_store_ram.h create mode 100644 src/libs/mynewt-nimble/nimble/host/store/ram/pkg.yml create mode 100644 src/libs/mynewt-nimble/nimble/host/store/ram/src/ble_store_ram.c create mode 100644 src/libs/mynewt-nimble/nimble/host/store/ram/syscfg.yml (limited to 'src/libs/mynewt-nimble/nimble/host/store') diff --git a/src/libs/mynewt-nimble/nimble/host/store/config/include/store/config/ble_store_config.h b/src/libs/mynewt-nimble/nimble/host/store/config/include/store/config/ble_store_config.h new file mode 100644 index 00000000..1b3f8e6c --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/config/include/store/config/ble_store_config.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef H_BLE_STORE_CONFIG_ +#define H_BLE_STORE_CONFIG_ + +#ifdef __cplusplus +extern "C" { +#endif + +union ble_store_key; +union ble_store_value; + +int ble_store_config_read(int obj_type, const union ble_store_key *key, + union ble_store_value *value); +int ble_store_config_write(int obj_type, const union ble_store_value *val); +int ble_store_config_delete(int obj_type, const union ble_store_key *key); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/store/config/pkg.yml b/src/libs/mynewt-nimble/nimble/host/store/config/pkg.yml new file mode 100644 index 00000000..db80d1df --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/config/pkg.yml @@ -0,0 +1,38 @@ +# +# 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. +# + +pkg.name: nimble/host/store/config +pkg.description: sys/config-based persistence layer for the NimBLE host. +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - nimble + - persistence + +pkg.deps: + - "@apache-mynewt-core/encoding/base64" + - nimble/host + +pkg.deps.BLE_STORE_CONFIG_PERSIST: + - "@apache-mynewt-core/sys/config" + +pkg.init: + ble_store_config_init: 'MYNEWT_VAL(BLE_STORE_SYSINIT_STAGE)' diff --git a/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config.c b/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config.c new file mode 100644 index 00000000..ce60d1fb --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config.c @@ -0,0 +1,533 @@ +/* + * 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 +#include + +#include "sysinit/sysinit.h" +#include "syscfg/syscfg.h" +#include "host/ble_hs.h" +#include "config/config.h" +#include "base64/base64.h" +#include "store/config/ble_store_config.h" +#include "ble_store_config_priv.h" + +struct ble_store_value_sec + ble_store_config_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +int ble_store_config_num_our_secs; + +struct ble_store_value_sec + ble_store_config_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +int ble_store_config_num_peer_secs; + +struct ble_store_value_cccd + ble_store_config_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)]; +int ble_store_config_num_cccds; + +/***************************************************************************** + * $sec * + *****************************************************************************/ + +static void +ble_store_config_print_value_sec(const struct ble_store_value_sec *sec) +{ + if (sec->ltk_present) { + BLE_HS_LOG(DEBUG, "ediv=%u rand=%llu authenticated=%d ltk=", + sec->ediv, sec->rand_num, sec->authenticated); + ble_hs_log_flat_buf(sec->ltk, 16); + BLE_HS_LOG(DEBUG, " "); + } + if (sec->irk_present) { + BLE_HS_LOG(DEBUG, "irk="); + ble_hs_log_flat_buf(sec->irk, 16); + BLE_HS_LOG(DEBUG, " "); + } + if (sec->csrk_present) { + BLE_HS_LOG(DEBUG, "csrk="); + ble_hs_log_flat_buf(sec->csrk, 16); + BLE_HS_LOG(DEBUG, " "); + } + + BLE_HS_LOG(DEBUG, "\n"); +} + +static void +ble_store_config_print_key_sec(const struct ble_store_key_sec *key_sec) +{ + if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + BLE_HS_LOG(DEBUG, "peer_addr_type=%d peer_addr=", + key_sec->peer_addr.type); + ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); + BLE_HS_LOG(DEBUG, " "); + } + if (key_sec->ediv_rand_present) { + BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", + key_sec->ediv, key_sec->rand_num); + } +} + +static int +ble_store_config_find_sec(const struct ble_store_key_sec *key_sec, + const struct ble_store_value_sec *value_secs, + int num_value_secs) +{ + const struct ble_store_value_sec *cur; + int skipped; + int i; + + skipped = 0; + + for (i = 0; i < num_value_secs; i++) { + cur = value_secs + i; + + if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { + continue; + } + } + + if (key_sec->ediv_rand_present) { + if (cur->ediv != key_sec->ediv) { + continue; + } + + if (cur->rand_num != key_sec->rand_num) { + continue; + } + } + + if (key_sec->idx > skipped) { + skipped++; + continue; + } + + return i; + } + + return -1; +} + +static int +ble_store_config_read_our_sec(const struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_sec) +{ + int idx; + + idx = ble_store_config_find_sec(key_sec, ble_store_config_our_secs, + ble_store_config_num_our_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_sec = ble_store_config_our_secs[idx]; + return 0; +} + + +static int +ble_store_config_write_our_sec(const struct ble_store_value_sec *value_sec) +{ + struct ble_store_key_sec key_sec; + int idx; + int rc; + + BLE_HS_LOG(DEBUG, "persisting our sec; "); + ble_store_config_print_value_sec(value_sec); + + ble_store_key_from_value_sec(&key_sec, value_sec); + idx = ble_store_config_find_sec(&key_sec, ble_store_config_our_secs, + ble_store_config_num_our_secs); + if (idx == -1) { + if (ble_store_config_num_our_secs >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + BLE_HS_LOG(DEBUG, "error persisting our sec; too many entries " + "(%d)\n", ble_store_config_num_our_secs); + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_config_num_our_secs; + ble_store_config_num_our_secs++; + } + + ble_store_config_our_secs[idx] = *value_sec; + + rc = ble_store_config_persist_our_secs(); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_config_delete_obj(void *values, int value_size, int idx, + int *num_values) +{ + uint8_t *dst; + uint8_t *src; + int move_count; + + (*num_values)--; + if (idx < *num_values) { + dst = values; + dst += idx * value_size; + src = dst + value_size; + + move_count = *num_values - idx; + memmove(dst, src, move_count * value_size); + } + + return 0; +} + +static int +ble_store_config_delete_sec(const struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_secs, + int *num_value_secs) +{ + int idx; + int rc; + + idx = ble_store_config_find_sec(key_sec, value_secs, *num_value_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + rc = ble_store_config_delete_obj(value_secs, sizeof *value_secs, idx, + num_value_secs); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_config_delete_our_sec(const struct ble_store_key_sec *key_sec) +{ + int rc; + + rc = ble_store_config_delete_sec(key_sec, ble_store_config_our_secs, + &ble_store_config_num_our_secs); + if (rc != 0) { + return rc; + } + + rc = ble_store_config_persist_our_secs(); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_config_delete_peer_sec(const struct ble_store_key_sec *key_sec) +{ + int rc; + + rc = ble_store_config_delete_sec(key_sec, ble_store_config_peer_secs, + &ble_store_config_num_peer_secs); + if (rc != 0) { + return rc; + } + + rc = ble_store_config_persist_peer_secs(); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_config_read_peer_sec(const struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_sec) +{ + int idx; + + idx = ble_store_config_find_sec(key_sec, ble_store_config_peer_secs, + ble_store_config_num_peer_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_sec = ble_store_config_peer_secs[idx]; + return 0; +} + +static int +ble_store_config_write_peer_sec(const struct ble_store_value_sec *value_sec) +{ + struct ble_store_key_sec key_sec; + int idx; + int rc; + + BLE_HS_LOG(DEBUG, "persisting peer sec; "); + ble_store_config_print_value_sec(value_sec); + + ble_store_key_from_value_sec(&key_sec, value_sec); + idx = ble_store_config_find_sec(&key_sec, ble_store_config_peer_secs, + ble_store_config_num_peer_secs); + if (idx == -1) { + if (ble_store_config_num_peer_secs >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + BLE_HS_LOG(DEBUG, "error persisting peer sec; too many entries " + "(%d)\n", ble_store_config_num_peer_secs); + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_config_num_peer_secs; + ble_store_config_num_peer_secs++; + } + + ble_store_config_peer_secs[idx] = *value_sec; + + rc = ble_store_config_persist_peer_secs(); + if (rc != 0) { + return rc; + } + + return 0; +} + +/***************************************************************************** + * $cccd * + *****************************************************************************/ + +static int +ble_store_config_find_cccd(const struct ble_store_key_cccd *key) +{ + struct ble_store_value_cccd *cccd; + int skipped; + int i; + + skipped = 0; + for (i = 0; i < ble_store_config_num_cccds; i++) { + cccd = ble_store_config_cccds + i; + + if (ble_addr_cmp(&key->peer_addr, BLE_ADDR_ANY)) { + if (ble_addr_cmp(&cccd->peer_addr, &key->peer_addr)) { + continue; + } + } + + if (key->chr_val_handle != 0) { + if (cccd->chr_val_handle != key->chr_val_handle) { + continue; + } + } + + if (key->idx > skipped) { + skipped++; + continue; + } + + return i; + } + + return -1; +} + +static int +ble_store_config_delete_cccd(const struct ble_store_key_cccd *key_cccd) +{ + int idx; + int rc; + + idx = ble_store_config_find_cccd(key_cccd); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + rc = ble_store_config_delete_obj(ble_store_config_cccds, + sizeof *ble_store_config_cccds, + idx, + &ble_store_config_num_cccds); + if (rc != 0) { + return rc; + } + + rc = ble_store_config_persist_cccds(); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_config_read_cccd(const struct ble_store_key_cccd *key_cccd, + struct ble_store_value_cccd *value_cccd) +{ + int idx; + + idx = ble_store_config_find_cccd(key_cccd); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_cccd = ble_store_config_cccds[idx]; + return 0; +} + +static int +ble_store_config_write_cccd(const struct ble_store_value_cccd *value_cccd) +{ + struct ble_store_key_cccd key_cccd; + int idx; + int rc; + + ble_store_key_from_value_cccd(&key_cccd, value_cccd); + idx = ble_store_config_find_cccd(&key_cccd); + if (idx == -1) { + if (ble_store_config_num_cccds >= MYNEWT_VAL(BLE_STORE_MAX_CCCDS)) { + BLE_HS_LOG(DEBUG, "error persisting cccd; too many entries (%d)\n", + ble_store_config_num_cccds); + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_config_num_cccds; + ble_store_config_num_cccds++; + } + + ble_store_config_cccds[idx] = *value_cccd; + + rc = ble_store_config_persist_cccds(); + if (rc != 0) { + return rc; + } + + return 0; +} + +/***************************************************************************** + * $api * + *****************************************************************************/ + +/** + * Searches the database for an object matching the specified criteria. + * + * @return 0 if a key was found; else BLE_HS_ENOENT. + */ +int +ble_store_config_read(int obj_type, const union ble_store_key *key, + union ble_store_value *value) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + /* 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. + * + * Perform a key lookup and populate the context object with the + * result. The nimble stack will use this key if this function returns + * success. + */ + BLE_HS_LOG(DEBUG, "looking up peer sec; "); + ble_store_config_print_key_sec(&key->sec); + BLE_HS_LOG(DEBUG, "\n"); + rc = ble_store_config_read_peer_sec(&key->sec, &value->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + BLE_HS_LOG(DEBUG, "looking up our sec; "); + ble_store_config_print_key_sec(&key->sec); + BLE_HS_LOG(DEBUG, "\n"); + rc = ble_store_config_read_our_sec(&key->sec, &value->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_config_read_cccd(&key->cccd, &value->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +/** + * Adds the specified object to the database. + * + * @return 0 on success; + * BLE_HS_ESTORE_CAP if the database is full. + */ +int +ble_store_config_write(int obj_type, const union ble_store_value *val) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + rc = ble_store_config_write_peer_sec(&val->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + rc = ble_store_config_write_our_sec(&val->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_config_write_cccd(&val->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +int +ble_store_config_delete(int obj_type, const union ble_store_key *key) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + rc = ble_store_config_delete_peer_sec(&key->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + rc = ble_store_config_delete_our_sec(&key->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_config_delete_cccd(&key->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +void +ble_store_config_init(void) +{ + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + ble_hs_cfg.store_read_cb = ble_store_config_read; + ble_hs_cfg.store_write_cb = ble_store_config_write; + ble_hs_cfg.store_delete_cb = ble_store_config_delete; + + /* Re-initialize BSS values in case of unit tests. */ + ble_store_config_num_our_secs = 0; + ble_store_config_num_peer_secs = 0; + ble_store_config_num_cccds = 0; + + ble_store_config_conf_init(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_conf.c b/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_conf.c new file mode 100644 index 00000000..e74127ae --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_conf.c @@ -0,0 +1,231 @@ +/* + * 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 "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) + +#include +#include + +#include "sysinit/sysinit.h" +#include "host/ble_hs.h" +#include "config/config.h" +#include "base64/base64.h" +#include "store/config/ble_store_config.h" +#include "ble_store_config_priv.h" + +static int +ble_store_config_conf_set(int argc, char **argv, char *val); +static int +ble_store_config_conf_export(void (*func)(char *name, char *val), + enum conf_export_tgt tgt); + +static struct conf_handler ble_store_config_conf_handler = { + .ch_name = "ble_hs", + .ch_get = NULL, + .ch_set = ble_store_config_conf_set, + .ch_commit = NULL, + .ch_export = ble_store_config_conf_export +}; + +#define BLE_STORE_CONFIG_SEC_ENCODE_SZ \ + BASE64_ENCODE_SIZE(sizeof (struct ble_store_value_sec)) + +#define BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ \ + (MYNEWT_VAL(BLE_STORE_MAX_BONDS) * BLE_STORE_CONFIG_SEC_ENCODE_SZ + 1) + +#define BLE_STORE_CONFIG_CCCD_ENCODE_SZ \ + BASE64_ENCODE_SIZE(sizeof (struct ble_store_value_cccd)) + +#define BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ \ + (MYNEWT_VAL(BLE_STORE_MAX_CCCDS) * BLE_STORE_CONFIG_CCCD_ENCODE_SZ + 1) + +static void +ble_store_config_serialize_arr(const void *arr, int obj_sz, int num_objs, + char *out_buf, int buf_sz) +{ + int arr_size; + + arr_size = obj_sz * num_objs; + assert(arr_size <= buf_sz); + + base64_encode(arr, arr_size, out_buf, 1); +} + +static int +ble_store_config_deserialize_arr(const char *enc, + void *out_arr, + int obj_sz, + int *out_num_objs) +{ + int len; + + len = base64_decode(enc, out_arr); + if (len < 0) { + return OS_EINVAL; + } + + *out_num_objs = len / obj_sz; + return 0; +} + +static int +ble_store_config_conf_set(int argc, char **argv, char *val) +{ + int rc; + + if (argc == 1) { + if (strcmp(argv[0], "our_sec") == 0) { + rc = ble_store_config_deserialize_arr( + val, + ble_store_config_our_secs, + sizeof *ble_store_config_our_secs, + &ble_store_config_num_our_secs); + return rc; + } else if (strcmp(argv[0], "peer_sec") == 0) { + rc = ble_store_config_deserialize_arr( + val, + ble_store_config_peer_secs, + sizeof *ble_store_config_peer_secs, + &ble_store_config_num_peer_secs); + return rc; + } else if (strcmp(argv[0], "cccd") == 0) { + rc = ble_store_config_deserialize_arr( + val, + ble_store_config_cccds, + sizeof *ble_store_config_cccds, + &ble_store_config_num_cccds); + return rc; + } + } + return OS_ENOENT; +} + +static int +ble_store_config_conf_export(void (*func)(char *name, char *val), + enum conf_export_tgt tgt) +{ + union { + char sec[BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ]; + char cccd[BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ]; + } buf; + + ble_store_config_serialize_arr(ble_store_config_our_secs, + sizeof *ble_store_config_our_secs, + ble_store_config_num_our_secs, + buf.sec, + sizeof buf.sec); + func("ble_hs/our_sec", buf.sec); + + ble_store_config_serialize_arr(ble_store_config_peer_secs, + sizeof *ble_store_config_peer_secs, + ble_store_config_num_peer_secs, + buf.sec, + sizeof buf.sec); + func("ble_hs/peer_sec", buf.sec); + + ble_store_config_serialize_arr(ble_store_config_cccds, + sizeof *ble_store_config_cccds, + ble_store_config_num_cccds, + buf.cccd, + sizeof buf.cccd); + func("ble_hs/cccd", buf.cccd); + + return 0; +} + +static int +ble_store_config_persist_sec_set(const char *setting_name, + const struct ble_store_value_sec *secs, + int num_secs) +{ + char buf[BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ]; + int rc; + + ble_store_config_serialize_arr(secs, sizeof *secs, num_secs, + buf, sizeof buf); + rc = conf_save_one(setting_name, buf); + if (rc != 0) { + return BLE_HS_ESTORE_FAIL; + } + + return 0; +} + +int +ble_store_config_persist_our_secs(void) +{ + int rc; + + rc = ble_store_config_persist_sec_set("ble_hs/our_sec", + ble_store_config_our_secs, + ble_store_config_num_our_secs); + if (rc != 0) { + return rc; + } + + return 0; +} + +int +ble_store_config_persist_peer_secs(void) +{ + int rc; + + rc = ble_store_config_persist_sec_set("ble_hs/peer_sec", + ble_store_config_peer_secs, + ble_store_config_num_peer_secs); + if (rc != 0) { + return rc; + } + + return 0; +} + +int +ble_store_config_persist_cccds(void) +{ + char buf[BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ]; + int rc; + + ble_store_config_serialize_arr(ble_store_config_cccds, + sizeof *ble_store_config_cccds, + ble_store_config_num_cccds, + buf, + sizeof buf); + rc = conf_save_one("ble_hs/cccd", buf); + if (rc != 0) { + return BLE_HS_ESTORE_FAIL; + } + + return 0; +} + +void +ble_store_config_conf_init(void) +{ + int rc; + + rc = conf_register(&ble_store_config_conf_handler); + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register ble_store_config conf"); +} + +#endif /* MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) */ diff --git a/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_priv.h b/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_priv.h new file mode 100644 index 00000000..bae90e97 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/config/src/ble_store_config_priv.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef H_BLE_STORE_CONFIG_PRIV_ +#define H_BLE_STORE_CONFIG_PRIV_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct ble_store_value_sec + ble_store_config_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +extern int ble_store_config_num_our_secs; + +extern struct ble_store_value_sec + ble_store_config_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +extern int ble_store_config_num_peer_secs; + +extern struct ble_store_value_cccd + ble_store_config_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)]; +extern int ble_store_config_num_cccds; + +#if MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) + +int ble_store_config_persist_our_secs(void); +int ble_store_config_persist_peer_secs(void); +int ble_store_config_persist_cccds(void); +void ble_store_config_conf_init(void); + +#else + +static inline int ble_store_config_persist_our_secs(void) { return 0; } +static inline int ble_store_config_persist_peer_secs(void) { return 0; } +static inline int ble_store_config_persist_cccds(void) { return 0; } +static inline void ble_store_config_conf_init(void) { } + +#endif /* MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/store/config/syscfg.yml b/src/libs/mynewt-nimble/nimble/host/store/config/syscfg.yml new file mode 100644 index 00000000..ff0689c6 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/config/syscfg.yml @@ -0,0 +1,27 @@ +# 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. +# + +syscfg.defs: + BLE_STORE_CONFIG_PERSIST: + description: > + Whether to save data to sys/config, or just keep it in RAM. + value: 1 + BLE_STORE_SYSINIT_STAGE: + description: > + Sysinit stage for BLE host store. + value: 500 diff --git a/src/libs/mynewt-nimble/nimble/host/store/ram/include/store/ram/ble_store_ram.h b/src/libs/mynewt-nimble/nimble/host/store/ram/include/store/ram/ble_store_ram.h new file mode 100644 index 00000000..842fb5f3 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/ram/include/store/ram/ble_store_ram.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef H_BLE_STORE_RAM_ +#define H_BLE_STORE_RAM_ + +#ifdef __cplusplus +extern "C" { +#endif + +union ble_store_key; +union ble_store_value; + +int ble_store_ram_read(int obj_type, const union ble_store_key *key, + union ble_store_value *value); +int ble_store_ram_write(int obj_type, const union ble_store_value *val); +int ble_store_ram_delete(int obj_type, const union ble_store_key *key); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/store/ram/pkg.yml b/src/libs/mynewt-nimble/nimble/host/store/ram/pkg.yml new file mode 100644 index 00000000..68765fdd --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/ram/pkg.yml @@ -0,0 +1,37 @@ +# +# 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. +# + +pkg.name: nimble/host/store/ram +pkg.description: > + DEPRECATED; for a RAM-only BLE store, use store/config and set + BLE_STORE_CONFIG_PERSIST to 0. RAM-based persistence layer for the NimBLE + host. +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - nimble + - persistence + +pkg.deps: + - nimble/host + +pkg.init: + ble_store_ram_init: 'MYNEWT_VAL(BLE_STORE_RAM_SYSINIT_STAGE)' diff --git a/src/libs/mynewt-nimble/nimble/host/store/ram/src/ble_store_ram.c b/src/libs/mynewt-nimble/nimble/host/store/ram/src/ble_store_ram.c new file mode 100644 index 00000000..ab5cdb9f --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/ram/src/ble_store_ram.c @@ -0,0 +1,497 @@ +/* + * 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 BLE host security + * material and CCCDs. As this database is only ble_store_ramd in RAM, its + * contents are lost when the application terminates. + */ + +#include +#include + +#include "sysinit/sysinit.h" +#include "syscfg/syscfg.h" +#include "host/ble_hs.h" +#include "store/ram/ble_store_ram.h" + +static struct ble_store_value_sec + ble_store_ram_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +static int ble_store_ram_num_our_secs; + +static struct ble_store_value_sec + ble_store_ram_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +static int ble_store_ram_num_peer_secs; + +static struct ble_store_value_cccd + ble_store_ram_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)]; +static int ble_store_ram_num_cccds; + +/***************************************************************************** + * $sec * + *****************************************************************************/ + +static void +ble_store_ram_print_value_sec(const struct ble_store_value_sec *sec) +{ + if (sec->ltk_present) { + BLE_HS_LOG(DEBUG, "ediv=%u rand=%llu authenticated=%d ltk=", + sec->ediv, sec->rand_num, sec->authenticated); + ble_hs_log_flat_buf(sec->ltk, 16); + BLE_HS_LOG(DEBUG, " "); + } + if (sec->irk_present) { + BLE_HS_LOG(DEBUG, "irk="); + ble_hs_log_flat_buf(sec->irk, 16); + BLE_HS_LOG(DEBUG, " "); + } + if (sec->csrk_present) { + BLE_HS_LOG(DEBUG, "csrk="); + ble_hs_log_flat_buf(sec->csrk, 16); + BLE_HS_LOG(DEBUG, " "); + } + + BLE_HS_LOG(DEBUG, "\n"); +} + +static void +ble_store_ram_print_key_sec(const struct ble_store_key_sec *key_sec) +{ + if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + BLE_HS_LOG(DEBUG, "peer_addr_type=%d peer_addr=", + key_sec->peer_addr.type); + ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); + BLE_HS_LOG(DEBUG, " "); + } + if (key_sec->ediv_rand_present) { + BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", + key_sec->ediv, key_sec->rand_num); + } +} + +static int +ble_store_ram_find_sec(const struct ble_store_key_sec *key_sec, + const struct ble_store_value_sec *value_secs, + int num_value_secs) +{ + const struct ble_store_value_sec *cur; + int skipped; + int i; + + skipped = 0; + + for (i = 0; i < num_value_secs; i++) { + cur = value_secs + i; + + if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { + continue; + } + } + + if (key_sec->ediv_rand_present) { + if (cur->ediv != key_sec->ediv) { + continue; + } + + if (cur->rand_num != key_sec->rand_num) { + continue; + } + } + + if (key_sec->idx > skipped) { + skipped++; + continue; + } + + return i; + } + + return -1; +} + +static int +ble_store_ram_read_our_sec(const struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_sec) +{ + int idx; + + idx = ble_store_ram_find_sec(key_sec, ble_store_ram_our_secs, + ble_store_ram_num_our_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_sec = ble_store_ram_our_secs[idx]; + return 0; +} + +static int +ble_store_ram_write_our_sec(const struct ble_store_value_sec *value_sec) +{ + struct ble_store_key_sec key_sec; + int idx; + + BLE_HS_LOG(DEBUG, "persisting our sec; "); + ble_store_ram_print_value_sec(value_sec); + + ble_store_key_from_value_sec(&key_sec, value_sec); + idx = ble_store_ram_find_sec(&key_sec, ble_store_ram_our_secs, + ble_store_ram_num_our_secs); + if (idx == -1) { + if (ble_store_ram_num_our_secs >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + BLE_HS_LOG(DEBUG, "error persisting our sec; too many entries " + "(%d)\n", ble_store_ram_num_our_secs); + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_ram_num_our_secs; + ble_store_ram_num_our_secs++; + } + + ble_store_ram_our_secs[idx] = *value_sec; + return 0; +} + +static int +ble_store_ram_delete_obj(void *values, int value_size, int idx, + int *num_values) +{ + uint8_t *dst; + uint8_t *src; + int move_count; + + (*num_values)--; + if (idx < *num_values) { + dst = values; + dst += idx * value_size; + src = dst + value_size; + + move_count = *num_values - idx; + memmove(dst, src, move_count); + } + + return 0; +} + +static int +ble_store_ram_delete_sec(const struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_secs, + int *num_value_secs) +{ + int idx; + int rc; + + idx = ble_store_ram_find_sec(key_sec, value_secs, *num_value_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + rc = ble_store_ram_delete_obj(value_secs, sizeof *value_secs, idx, + num_value_secs); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_ram_delete_our_sec(const struct ble_store_key_sec *key_sec) +{ + int rc; + + rc = ble_store_ram_delete_sec(key_sec, ble_store_ram_our_secs, + &ble_store_ram_num_our_secs); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_ram_delete_peer_sec(const struct ble_store_key_sec *key_sec) +{ + int rc; + + rc = ble_store_ram_delete_sec(key_sec, ble_store_ram_peer_secs, + &ble_store_ram_num_peer_secs); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_ram_read_peer_sec(const struct ble_store_key_sec *key_sec, + struct ble_store_value_sec *value_sec) +{ + int idx; + + idx = ble_store_ram_find_sec(key_sec, ble_store_ram_peer_secs, + ble_store_ram_num_peer_secs); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_sec = ble_store_ram_peer_secs[idx]; + return 0; +} + +static int +ble_store_ram_write_peer_sec(const struct ble_store_value_sec *value_sec) +{ + struct ble_store_key_sec key_sec; + int idx; + + BLE_HS_LOG(DEBUG, "persisting peer sec; "); + ble_store_ram_print_value_sec(value_sec); + + ble_store_key_from_value_sec(&key_sec, value_sec); + idx = ble_store_ram_find_sec(&key_sec, ble_store_ram_peer_secs, + ble_store_ram_num_peer_secs); + if (idx == -1) { + if (ble_store_ram_num_peer_secs >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + BLE_HS_LOG(DEBUG, "error persisting peer sec; too many entries " + "(%d)\n", ble_store_ram_num_peer_secs); + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_ram_num_peer_secs; + ble_store_ram_num_peer_secs++; + } + + ble_store_ram_peer_secs[idx] = *value_sec; + return 0; +} + +/***************************************************************************** + * $cccd * + *****************************************************************************/ + +static int +ble_store_ram_find_cccd(const struct ble_store_key_cccd *key) +{ + struct ble_store_value_cccd *cccd; + int skipped; + int i; + + skipped = 0; + for (i = 0; i < ble_store_ram_num_cccds; i++) { + cccd = ble_store_ram_cccds + i; + + if (ble_addr_cmp(&key->peer_addr, BLE_ADDR_ANY)) { + if (ble_addr_cmp(&cccd->peer_addr, &key->peer_addr)) { + continue; + } + } + + if (key->chr_val_handle != 0) { + if (cccd->chr_val_handle != key->chr_val_handle) { + continue; + } + } + + if (key->idx > skipped) { + skipped++; + continue; + } + + return i; + } + + return -1; +} + +static int +ble_store_ram_delete_cccd(const struct ble_store_key_cccd *key_cccd) +{ + int idx; + int rc; + + idx = ble_store_ram_find_cccd(key_cccd); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + rc = ble_store_ram_delete_obj(ble_store_ram_cccds, + sizeof *ble_store_ram_cccds, + idx, + &ble_store_ram_num_cccds); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int +ble_store_ram_read_cccd(const struct ble_store_key_cccd *key_cccd, + struct ble_store_value_cccd *value_cccd) +{ + int idx; + + idx = ble_store_ram_find_cccd(key_cccd); + if (idx == -1) { + return BLE_HS_ENOENT; + } + + *value_cccd = ble_store_ram_cccds[idx]; + return 0; +} + +static int +ble_store_ram_write_cccd(const struct ble_store_value_cccd *value_cccd) +{ + struct ble_store_key_cccd key_cccd; + int idx; + + ble_store_key_from_value_cccd(&key_cccd, value_cccd); + idx = ble_store_ram_find_cccd(&key_cccd); + if (idx == -1) { + if (ble_store_ram_num_cccds >= MYNEWT_VAL(BLE_STORE_MAX_CCCDS)) { + BLE_HS_LOG(DEBUG, "error persisting cccd; too many entries (%d)\n", + ble_store_ram_num_cccds); + return BLE_HS_ESTORE_CAP; + } + + idx = ble_store_ram_num_cccds; + ble_store_ram_num_cccds++; + } + + ble_store_ram_cccds[idx] = *value_cccd; + return 0; +} + +/***************************************************************************** + * $api * + *****************************************************************************/ + +/** + * Searches the database for an object matching the specified criteria. + * + * @return 0 if a key was found; else BLE_HS_ENOENT. + */ +int +ble_store_ram_read(int obj_type, const union ble_store_key *key, + union ble_store_value *value) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + /* 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. + * + * Perform a key lookup and populate the context object with the + * result. The nimble stack will use this key if this function returns + * success. + */ + BLE_HS_LOG(DEBUG, "looking up peer sec; "); + ble_store_ram_print_key_sec(&key->sec); + BLE_HS_LOG(DEBUG, "\n"); + rc = ble_store_ram_read_peer_sec(&key->sec, &value->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + BLE_HS_LOG(DEBUG, "looking up our sec; "); + ble_store_ram_print_key_sec(&key->sec); + BLE_HS_LOG(DEBUG, "\n"); + rc = ble_store_ram_read_our_sec(&key->sec, &value->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_ram_read_cccd(&key->cccd, &value->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +/** + * Adds the specified object to the database. + * + * @return 0 on success; BLE_HS_ESTORE_CAP if the database + * is full. + */ +int +ble_store_ram_write(int obj_type, const union ble_store_value *val) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + rc = ble_store_ram_write_peer_sec(&val->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + rc = ble_store_ram_write_our_sec(&val->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_ram_write_cccd(&val->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +int +ble_store_ram_delete(int obj_type, const union ble_store_key *key) +{ + int rc; + + switch (obj_type) { + case BLE_STORE_OBJ_TYPE_PEER_SEC: + rc = ble_store_ram_delete_peer_sec(&key->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_OUR_SEC: + rc = ble_store_ram_delete_our_sec(&key->sec); + return rc; + + case BLE_STORE_OBJ_TYPE_CCCD: + rc = ble_store_ram_delete_cccd(&key->cccd); + return rc; + + default: + return BLE_HS_ENOTSUP; + } +} + +void +ble_store_ram_init(void) +{ + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + ble_hs_cfg.store_read_cb = ble_store_ram_read; + ble_hs_cfg.store_write_cb = ble_store_ram_write; + ble_hs_cfg.store_delete_cb = ble_store_ram_delete; + + /* Re-initialize BSS values in case of unit tests. */ + ble_store_ram_num_our_secs = 0; + ble_store_ram_num_peer_secs = 0; + ble_store_ram_num_cccds = 0; +} diff --git a/src/libs/mynewt-nimble/nimble/host/store/ram/syscfg.yml b/src/libs/mynewt-nimble/nimble/host/store/ram/syscfg.yml new file mode 100644 index 00000000..442211dd --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/store/ram/syscfg.yml @@ -0,0 +1,23 @@ +# 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. + +syscfg.defs: + BLE_STORE_RAM_SYSINIT_STAGE: + description: > + Sysinit stage for the RAM BLE store. + value: 500 + -- cgit v1.2.3