mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-09-16 14:09:54 +00:00
MYNEWT-743 BLE Host - Persist bonds to sys/config
X-Original-Commit: 858e59595311423deb674959841c3d3b8eb9e100
This commit is contained in:
@@ -72,6 +72,7 @@ struct os_event;
|
||||
#define BLE_HS_EENCRYPT 25
|
||||
#define BLE_HS_EENCRYPT_KEY_SZ 26
|
||||
#define BLE_HS_ESTORE_CAP 27
|
||||
#define BLE_HS_ESTORE_FAIL 28
|
||||
|
||||
#define BLE_HS_ERR_ATT_BASE 0x100 /* 256 */
|
||||
#define BLE_HS_ATT_ERR(x) ((x) ? BLE_HS_ERR_ATT_BASE + (x) : 0)
|
||||
|
||||
@@ -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
|
||||
@@ -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: net/nimble/host/store/config
|
||||
pkg.description: sys/config-based persistence layer for the NimBLE host.
|
||||
pkg.author: "Apache Mynewt <[email protected]>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
- ble
|
||||
- bluetooth
|
||||
- nimble
|
||||
- persistence
|
||||
|
||||
pkg.deps:
|
||||
- encoding/base64
|
||||
- net/nimble/host
|
||||
|
||||
pkg.deps.BLE_STORE_CONFIG_PERSIST:
|
||||
- sys/config
|
||||
|
||||
pkg.init:
|
||||
ble_store_config_init: 500
|
||||
@@ -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 <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
@@ -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 <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#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) */
|
||||
@@ -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
|
||||
@@ -0,0 +1,25 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Package: net/nimble/host
|
||||
|
||||
syscfg.defs:
|
||||
BLE_STORE_CONFIG_PERSIST:
|
||||
description: >
|
||||
Whether to save data to sys/config, or just keep it in RAM.
|
||||
value: 1
|
||||
@@ -18,7 +18,10 @@
|
||||
#
|
||||
|
||||
pkg.name: net/nimble/host/store/ram
|
||||
pkg.description: RAM-based persistence layer for the NimBLE host.
|
||||
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 <[email protected]>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
|
||||
+10
-5
@@ -322,10 +322,15 @@ syscfg.defs:
|
||||
# Store settings.
|
||||
BLE_STORE_MAX_BONDS:
|
||||
description: >
|
||||
Number of bonds to persist before recycling old ones.
|
||||
value: 4
|
||||
Maximum number of bonds that can be persisted. Note: increasing
|
||||
this value may also require increasing the capacity of the
|
||||
underlying storage mechanism.
|
||||
value: 3
|
||||
BLE_STORE_MAX_CCCDS:
|
||||
description: >
|
||||
Number of client characteristic configuration descriptors to
|
||||
persist before recycling old ones.
|
||||
value: 16
|
||||
Maximum number of client characteristic configuration descriptors
|
||||
that can be persisted. Note: increasing this value may also
|
||||
require increasing the capacity of the underlying storage
|
||||
mechanism.
|
||||
|
||||
value: 8
|
||||
|
||||
@@ -25,7 +25,7 @@ pkg.keywords:
|
||||
pkg.deps:
|
||||
- test/testutil
|
||||
- net/nimble/host
|
||||
- net/nimble/host/store/ram
|
||||
- net/nimble/host/store/config
|
||||
|
||||
pkg.deps.SELFTEST:
|
||||
- sys/console/stub
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "nimble/ble_hci_trans.h"
|
||||
#include "host/ble_hs_adv.h"
|
||||
#include "host/ble_hs_id.h"
|
||||
#include "store/ram/ble_store_ram.h"
|
||||
#include "store/config/ble_store_config.h"
|
||||
#include "transport/ram/ble_hci_ram.h"
|
||||
#include "ble_hs_test_util.h"
|
||||
|
||||
@@ -2328,7 +2328,7 @@ ble_hs_test_util_store_read(int obj_type, const union ble_store_key *key,
|
||||
ble_sm_test_store_obj_type = obj_type;
|
||||
ble_sm_test_store_key = *key;
|
||||
|
||||
rc = ble_store_ram_read(obj_type, key, value);
|
||||
rc = ble_store_config_read(obj_type, key, value);
|
||||
ble_sm_test_store_value = *value;
|
||||
|
||||
return rc;
|
||||
@@ -2341,7 +2341,7 @@ ble_hs_test_util_store_write(int obj_type, const union ble_store_value *value)
|
||||
|
||||
ble_sm_test_store_obj_type = obj_type;
|
||||
|
||||
rc = ble_store_ram_write(obj_type, value);
|
||||
rc = ble_store_config_write(obj_type, value);
|
||||
ble_sm_test_store_value = *value;
|
||||
|
||||
return rc;
|
||||
@@ -2355,7 +2355,7 @@ ble_hs_test_util_store_delete(int obj_type, const union ble_store_key *key)
|
||||
ble_sm_test_store_obj_type = obj_type;
|
||||
ble_sm_test_store_key = *key;
|
||||
|
||||
rc = ble_store_ram_delete(obj_type, key);
|
||||
rc = ble_store_config_delete(obj_type, key);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "host/ble_sm.h"
|
||||
#include "host/ble_hs_test.h"
|
||||
#include "host/ble_hs_id.h"
|
||||
#include "store/ram/ble_store_ram.h"
|
||||
#include "ble_hs_test_util.h"
|
||||
#include "ble_sm_test_util.h"
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ ble_store_test_util_overflow_sec(int is_our_sec)
|
||||
|
||||
TEST_CASE(ble_store_test_peers)
|
||||
{
|
||||
struct ble_store_value_sec secs[4] = {
|
||||
struct ble_store_value_sec secs[3] = {
|
||||
{
|
||||
.peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } },
|
||||
.ltk_present = 1,
|
||||
@@ -129,12 +129,8 @@ TEST_CASE(ble_store_test_peers)
|
||||
.peer_addr = { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } },
|
||||
.ltk_present = 1,
|
||||
},
|
||||
{
|
||||
.peer_addr = { BLE_ADDR_RANDOM, { 3, 4, 5, 6, 7, 8 } },
|
||||
.ltk_present = 1,
|
||||
},
|
||||
};
|
||||
ble_addr_t peer_addrs[4];
|
||||
ble_addr_t peer_addrs[3];
|
||||
int num_addrs;
|
||||
int rc;
|
||||
int i;
|
||||
@@ -188,6 +184,9 @@ TEST_CASE(ble_store_test_delete_peer)
|
||||
.chr_val_handle = 5,
|
||||
},
|
||||
};
|
||||
union ble_store_value value;
|
||||
union ble_store_key key;
|
||||
int count;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
@@ -212,6 +211,35 @@ TEST_CASE(ble_store_test_delete_peer)
|
||||
/* Ensure all traces of first peer have been removed. */
|
||||
ble_store_test_util_verify_peer_deleted(&secs[0].peer_addr);
|
||||
|
||||
/* Ensure second peer data is still intact. */
|
||||
ble_store_key_from_value_sec(&key.sec, secs + 1);
|
||||
|
||||
rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC, &count);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(count == 1);
|
||||
|
||||
rc = ble_store_read_our_sec(&key.sec, &value.sec);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(memcmp(&value.sec, secs + 1, sizeof value.sec) == 0);
|
||||
|
||||
rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(count == 1);
|
||||
|
||||
rc = ble_store_read_peer_sec(&key.sec, &value.sec);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(memcmp(&value.sec, secs + 1, sizeof value.sec) == 0);
|
||||
|
||||
ble_store_key_from_value_cccd(&key.cccd, cccds + 2);
|
||||
|
||||
rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_CCCD, &count);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(count == 1);
|
||||
|
||||
rc = ble_store_read_cccd(&key.cccd, &value.cccd);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(memcmp(&value.cccd, cccds + 2, sizeof value.cccd) == 0);
|
||||
|
||||
/* Delete second peer. */
|
||||
rc = ble_store_util_delete_peer(&secs[1].peer_addr);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
@@ -272,15 +300,15 @@ TEST_CASE(ble_store_test_count)
|
||||
|
||||
/* Write some test data. */
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = ble_store_write_our_sec(secs + i);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
rc = ble_store_write_peer_sec(secs + i);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 1; i++) {
|
||||
rc = ble_store_write_cccd(cccds + i);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
}
|
||||
@@ -288,15 +316,15 @@ TEST_CASE(ble_store_test_count)
|
||||
/*** Verify counts after populating store. */
|
||||
rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC, &count);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(count == 4);
|
||||
TEST_ASSERT(count == 3);
|
||||
|
||||
rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(count == 3);
|
||||
TEST_ASSERT(count == 2);
|
||||
|
||||
rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_CCCD, &count);
|
||||
TEST_ASSERT_FATAL(rc == 0);
|
||||
TEST_ASSERT(count == 2);
|
||||
TEST_ASSERT(count == 1);
|
||||
}
|
||||
|
||||
TEST_CASE(ble_store_test_overflow)
|
||||
|
||||
@@ -28,3 +28,4 @@ syscfg.vals:
|
||||
BLE_SM_SC: 1
|
||||
MSYS_1_BLOCK_COUNT: 100
|
||||
BLE_L2CAP_COC_MAX_NUM: 1
|
||||
CONFIG_FCB: 1
|
||||
|
||||
Reference in New Issue
Block a user