You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mynewt.apache.org by prasad <pr...@espressif.com> on 2019/02/11 13:40:30 UTC
Storing Bonding information in NVS memory
Hi all,
Are there any pointers/documentation for storing NIMBLE bond information
in NVS memory?
I tried to quickly implement simple application by modifying
'*ble_store_ram.c*'. I modified
/ble_hs_cfg.store_read_cb/store_write_cb/store_delete_cb/ callbacks
according to the requirement. I find this much of change is not
sufficient to get NVS bond stored in NVS as I am continuously getting
disconnect HCI event.
FYI, I am putting snippet of my code for each of these 3 callbacks which
will help you understand the changes I have made.
1.**/*ble_hs_cfg.store_read_cb* :
/
/case BLE_STORE_OBJ_TYPE_OUR_SEC:
nvs_open("nimble_bond", NVS_READWRITE, &nimble_handle);
BLE_HS_LOG(DEBUG, "looking up our sec; ");
err = nvs_get_blob(nimble_handle, "our_sec_key", NULL,
&required_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
if (required_size == 0) {
nvs_close(nimble_handle);
return BLE_HS_ENOENT;
} else {
struct ble_store_key_sec* our_sec_key = malloc(required_size);
err = nvs_get_blob(nimble_handle, "our_sec_key",
our_sec_key, &required_size);
if (err != ESP_OK) {
free(our_sec_key);
return err;
}
if (ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)) {
if (ble_addr_cmp(&our_sec_key->peer_addr,
&key->sec.peer_addr)){
err = nvs_get_blob(nimble_handle, "our_sec", NULL,
&required_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
struct ble_store_value_sec* our_sec = malloc(required_size);
err = nvs_get_blob(nimble_handle, "our_sec", our_sec,
&required_size);
if (err != ESP_OK) {
free(our_sec);
return err;
}
memcpy(&value->sec, our_sec, required_size);
free(our_sec);
}
}
free(our_sec_key);
}
/* NVS Close */
nvs_close(nimble_handle);
/
/2. ///*ble_hs_cfg.store_write_cb
*//
//case BLE_STORE_OBJ_TYPE_OUR_SEC:
ble_store_key_from_value_sec(&key_sec, &val->sec);
required_size = sizeof(struct ble_store_key_sec);
err = nvs_set_blob(nimble_handle, "our_sec_key", &key_sec,
required_size);
required_size = sizeof(struct ble_store_value_sec);
err = nvs_set_blob(nimble_handle, "our_sec", &val->sec,
required_size);
/* NVS Commit */
err = nvs_commit(nimble_handle);
if (err != ESP_OK) return err;
/* NVS Close */
nvs_close(nimble_handle);
return 0;//
Regards
Prasad
Re: Storing Bonding information in NVS memory
Posted by Christopher Collins <ch...@runtime.io>.
Hi Prasad,
On Mon, Feb 11, 2019 at 07:10:30PM +0530, prasad wrote:
> Hi all,
>
> Are there any pointers/documentation for storing NIMBLE bond information
> in NVS memory?
By NVS, do you mean non-volatile storage (e.g., flash)? I believe the
`@apache-mynewt-nimble/nimble/host/store/config` package is what you
want. This package stores bonding records to flash using the
`sys/config` package. Typically, `sys/config` is implemented using a
flash circular buffer (FCB).
The `bleprph` sample app uses the config store, so you might look there
for a source of inspiration.
Chris
Re: Storing Bonding information in NVS memory
Posted by Andrzej Kaczmarek <an...@codecoup.pl>.
Hi Prasad,
On Fri, Feb 15, 2019 at 1:24 PM prasad <pr...@espressif.com> wrote:
> Hi Chris,
>
> Currently I have been able to develop an app which is able to store bond
> information in NVS flash. If my device (ESP32) based on NIMBLE stack is
> rebooted, the bond remains intact. But if the other device is rebooted
> the ` key_sec->peer_addr.val` gets changed based on
> `key_sec->peer_addr.type = 1` (static address, random device address).
>
> As I understand, it is expected of static address type to change to new
> value, generated after each power cycle.
>
It is allowed, but not required - device may use single static address for
its lifetime.
> So in this case how to keep bond between devices intact ?
>
> If in case static address type is not to be used for bonded devices then
> why our NIMBLE stack uses static type of address even after setting
> `bonding` flag to 1 ?
>
Static address can be used to create bond, there's nothing wrong here.
However, if you or any other vendor devices decide that their device will
use new static random address after each power cycle, then it's basically
considered as a "new" device and all bonds created using previous static
address are effectively lost. There's nothing you can do here as this is
"by design". For reference, see Core 5.0 spec, Vol 6, Part B, section 1.3.6.
> Could you help me resolve this issue? Or I am missing on something obvious?
>
> Below is the snippet of code which tries to retrieve index from database
> but fails to do so since the `peer_addr.val` field has been changed.
>
> `
>
> if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) {
> if (*ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr*)) {
> continue;
> `
>
> Regards
>
> Prasad
>
Best,
Andrzej
Re: Storing Bonding information in NVS memory
Posted by prasad <pr...@espressif.com>.
Hi Chris,
Currently I have been able to develop an app which is able to store bond
information in NVS flash. If my device (ESP32) based on NIMBLE stack is
rebooted, the bond remains intact. But if the other device is rebooted
the ` key_sec->peer_addr.val` gets changed based on
`key_sec->peer_addr.type = 1` (static address, random device address).
As I understand, it is expected of static address type to change to new
value, generated after each power cycle.
So in this case how to keep bond between devices intact ?
If in case static address type is not to be used for bonded devices then
why our NIMBLE stack uses static type of address even after setting
`bonding` flag to 1 ?
Could you help me resolve this issue? Or I am missing on something obvious?
Below is the snippet of code which tries to retrieve index from database
but fails to do so since the `peer_addr.val` field has been changed.
`
if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) {
if (*ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr*)) {
continue;
`
Regards
Prasad
On 14/02/19 11:53 AM, prasad wrote:
>
> Hi Chris,
>
> Thank you for your response. As I build my understanding from your
> response,
>
> The `idx` field most probably is useful in searching the case where
> `key.sec.peer_addr = *BLE_ADDR_ANY`, which most probably is useful to
> search our security keys. Correct me if I am wrong.
>
> The reason behind asking use-case of `idx` was, when we are to write
> security keys to database, we call `ble_store_key_from_value_sec`
> which does the following:
>
> {
> out_key->peer_addr = value->peer_addr;
>
> out_key->ediv = value->ediv;
> out_key->rand_num = value->rand_num;
> out_key->ediv_rand_present = 1;
> *o**ut_key->idx = 0;* // /This made me wonder why we need to search
> based on this criteria./
> }
>
> Thank you for response anyways. Really helpful.
>
> Regards
>
> Prasad
>
> On 13/02/19 9:44 PM, Christopher Collins wrote:
>> Hi Prasad,
>>
>> On Wed, Feb 13, 2019 at 03:13:26PM +0530, prasad wrote:
>>> Hi all,
>>>
>>> As it happens, I fixed the bug in my code. It now correctly retrieves
>>> LTKs and bond is maintained even after reboot.
>>>
>>> Apart from this I just wanted to understand reason behind including
>>> 'idx' in structure 'ble_store_key_sec'. Could you please help me
>>> understand use-case behind including 'idx'?
>>>
>>> /** Number of results to skip; 0 means retrieve the first match. */
>>> uint8_t idx;
>> The `idx` field is useful when your search criteria matches several
>> entries and you want to process them one by one. For example, the
>> `ble_store_iterate()` function constructs a `ble_store_key_sec` object
>> with the following values:
>>
>> {
>> /**
>> * Key by peer identity address;
>> * peer_addr=BLE_ADDR_NONE means don't key off peer.
>> */
>> peer_addr = *BLE_ADDR_ANY,
>>
>> /** Key by ediv; ediv_rand_present=0 means don't key off ediv. */
>> ediv = 0,
>>
>> /** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */
>> rand_num = 0
>>
>> ediv_rand_present = 0,
>>
>> /** Number of results to skip; 0 means retrieve the first match. */
>> idx = 0,
>> }
>>
>> Then it repeatedly calls `ble_store_read()`, incrementing the `idx`
>> member each time. This allows all stored bonds to be processed.
>>
>> Chris)
Re: Storing Bonding information in NVS memory
Posted by prasad <pr...@espressif.com>.
Hi Chris,
Thank you for your response. As I build my understanding from your response,
The `idx` field most probably is useful in searching the case where
`key.sec.peer_addr = *BLE_ADDR_ANY`, which most probably is useful to
search our security keys. Correct me if I am wrong.
The reason behind asking use-case of `idx` was, when we are to write
security keys to database, we call `ble_store_key_from_value_sec` which
does the following:
{
out_key->peer_addr = value->peer_addr;
out_key->ediv = value->ediv;
out_key->rand_num = value->rand_num;
out_key->ediv_rand_present = 1;
*o**ut_key->idx = 0;* // /This made me wonder why we need to search
based on this criteria./
}
Thank you for response anyways. Really helpful.
Regards
Prasad
On 13/02/19 9:44 PM, Christopher Collins wrote:
> Hi Prasad,
>
> On Wed, Feb 13, 2019 at 03:13:26PM +0530, prasad wrote:
>> Hi all,
>>
>> As it happens, I fixed the bug in my code. It now correctly retrieves
>> LTKs and bond is maintained even after reboot.
>>
>> Apart from this I just wanted to understand reason behind including
>> 'idx' in structure 'ble_store_key_sec'. Could you please help me
>> understand use-case behind including 'idx'?
>>
>> /** Number of results to skip; 0 means retrieve the first match. */
>> uint8_t idx;
> The `idx` field is useful when your search criteria matches several
> entries and you want to process them one by one. For example, the
> `ble_store_iterate()` function constructs a `ble_store_key_sec` object
> with the following values:
>
> {
> /**
> * Key by peer identity address;
> * peer_addr=BLE_ADDR_NONE means don't key off peer.
> */
> peer_addr = *BLE_ADDR_ANY,
>
> /** Key by ediv; ediv_rand_present=0 means don't key off ediv. */
> ediv = 0,
>
> /** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */
> rand_num = 0
>
> ediv_rand_present = 0,
>
> /** Number of results to skip; 0 means retrieve the first match. */
> idx = 0,
> }
>
> Then it repeatedly calls `ble_store_read()`, incrementing the `idx`
> member each time. This allows all stored bonds to be processed.
>
> Chris)
Re: Storing Bonding information in NVS memory
Posted by Christopher Collins <ch...@runtime.io>.
Hi Prasad,
On Wed, Feb 13, 2019 at 03:13:26PM +0530, prasad wrote:
> Hi all,
>
> As it happens, I fixed the bug in my code. It now correctly retrieves
> LTKs and bond is maintained even after reboot.
>
> Apart from this I just wanted to understand reason behind including
> 'idx' in structure 'ble_store_key_sec'. Could you please help me
> understand use-case behind including 'idx'?
>
> /** Number of results to skip; 0 means retrieve the first match. */
> uint8_t idx;
The `idx` field is useful when your search criteria matches several
entries and you want to process them one by one. For example, the
`ble_store_iterate()` function constructs a `ble_store_key_sec` object
with the following values:
{
/**
* Key by peer identity address;
* peer_addr=BLE_ADDR_NONE means don't key off peer.
*/
peer_addr = *BLE_ADDR_ANY,
/** Key by ediv; ediv_rand_present=0 means don't key off ediv. */
ediv = 0,
/** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */
rand_num = 0
ediv_rand_present = 0,
/** Number of results to skip; 0 means retrieve the first match. */
idx = 0,
}
Then it repeatedly calls `ble_store_read()`, incrementing the `idx`
member each time. This allows all stored bonds to be processed.
Chris
Re: Storing Bonding information in NVS memory
Posted by prasad <pr...@espressif.com>.
Hi all,
As it happens, I fixed the bug in my code. It now correctly retrieves
LTKs and bond is maintained even after reboot.
Apart from this I just wanted to understand reason behind including
'idx' in structure 'ble_store_key_sec'. Could you please help me
understand use-case behind including 'idx'?
/** Number of results to skip; 0 means retrieve the first match. */
uint8_t idx;
Regards
Prasad
On 12/02/19 7:35 PM, prasad wrote:
>
> Hi all,
>
> With further debug effort the disconnect happens with HCI error 0x3d:
> BLE_ERR_CONN_TERM_MIC.
>
> Once the connection is establish, if we disconnect and try to
> reconnect it is disconnecting with said reason.
>
> I am attaching logs with additional prints. Please help me to know if
> I am making any obvious mistake.
>
>
> Regards
>
> Prasad
>
> On 11/02/19 7:10 PM, prasad wrote:
>>
>> Hi all,
>>
>> Are there any pointers/documentation for storing NIMBLE bond
>> information in NVS memory?
>>
>> I tried to quickly implement simple application by modifying
>> '*ble_store_ram.c*'. I modified
>> /ble_hs_cfg.store_read_cb/store_write_cb/store_delete_cb/ callbacks
>> according to the requirement. I find this much of change is not
>> sufficient to get NVS bond stored in NVS as I am continuously getting
>> disconnect HCI event.
>>
>> FYI, I am putting snippet of my code for each of these 3 callbacks
>> which will help you understand the changes I have made.
>>
>> 1.**/*ble_hs_cfg.store_read_cb* :
>> /
>>
>> /case BLE_STORE_OBJ_TYPE_OUR_SEC:
>> nvs_open("nimble_bond", NVS_READWRITE, &nimble_handle);
>>
>> BLE_HS_LOG(DEBUG, "looking up our sec; ");
>> err = nvs_get_blob(nimble_handle, "our_sec_key", NULL,
>> &required_size);
>> if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
>> if (required_size == 0) {
>> nvs_close(nimble_handle);
>> return BLE_HS_ENOENT;
>> } else {
>> struct ble_store_key_sec* our_sec_key =
>> malloc(required_size);
>> err = nvs_get_blob(nimble_handle, "our_sec_key",
>> our_sec_key, &required_size);
>> if (err != ESP_OK) {
>> free(our_sec_key);
>> return err;
>> }
>>
>> if (ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)) {
>> if (ble_addr_cmp(&our_sec_key->peer_addr,
>> &key->sec.peer_addr)){
>> err = nvs_get_blob(nimble_handle, "our_sec", NULL,
>> &required_size);
>> if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return
>> err;
>>
>> struct ble_store_value_sec* our_sec = malloc(required_size);
>> err = nvs_get_blob(nimble_handle, "our_sec", our_sec,
>> &required_size);
>> if (err != ESP_OK) {
>> free(our_sec);
>> return err;
>> }
>>
>> memcpy(&value->sec, our_sec, required_size);
>> free(our_sec);
>> }
>> }
>>
>> free(our_sec_key);
>> }
>> /* NVS Close */
>> nvs_close(nimble_handle);
>>
>> /
>>
>> /2. ///*ble_hs_cfg.store_write_cb
>> *//
>>
>> //case BLE_STORE_OBJ_TYPE_OUR_SEC:
>> ble_store_key_from_value_sec(&key_sec, &val->sec);
>>
>> required_size = sizeof(struct ble_store_key_sec);
>> err = nvs_set_blob(nimble_handle, "our_sec_key", &key_sec,
>> required_size);
>> required_size = sizeof(struct ble_store_value_sec);
>> err = nvs_set_blob(nimble_handle, "our_sec", &val->sec,
>> required_size);
>>
>> /* NVS Commit */
>> err = nvs_commit(nimble_handle);
>> if (err != ESP_OK) return err;
>> /* NVS Close */
>> nvs_close(nimble_handle);
>>
>> return 0;//
>>
>> Regards
>>
>> Prasad
>>
Re: Storing Bonding information in NVS memory
Posted by prasad <pr...@espressif.com>.
Hi all,
With further debug effort the disconnect happens with HCI error 0x3d:
BLE_ERR_CONN_TERM_MIC.
Once the connection is establish, if we disconnect and try to reconnect
it is disconnecting with said reason.
I am attaching logs with additional prints. Please help me to know if I
am making any obvious mistake.
Regards
Prasad
On 11/02/19 7:10 PM, prasad wrote:
>
> Hi all,
>
> Are there any pointers/documentation for storing NIMBLE bond
> information in NVS memory?
>
> I tried to quickly implement simple application by modifying
> '*ble_store_ram.c*'. I modified
> /ble_hs_cfg.store_read_cb/store_write_cb/store_delete_cb/ callbacks
> according to the requirement. I find this much of change is not
> sufficient to get NVS bond stored in NVS as I am continuously getting
> disconnect HCI event.
>
> FYI, I am putting snippet of my code for each of these 3 callbacks
> which will help you understand the changes I have made.
>
> 1.**/*ble_hs_cfg.store_read_cb* :
> /
>
> /case BLE_STORE_OBJ_TYPE_OUR_SEC:
> nvs_open("nimble_bond", NVS_READWRITE, &nimble_handle);
>
> BLE_HS_LOG(DEBUG, "looking up our sec; ");
> err = nvs_get_blob(nimble_handle, "our_sec_key", NULL,
> &required_size);
> if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
> if (required_size == 0) {
> nvs_close(nimble_handle);
> return BLE_HS_ENOENT;
> } else {
> struct ble_store_key_sec* our_sec_key = malloc(required_size);
> err = nvs_get_blob(nimble_handle, "our_sec_key",
> our_sec_key, &required_size);
> if (err != ESP_OK) {
> free(our_sec_key);
> return err;
> }
>
> if (ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)) {
> if (ble_addr_cmp(&our_sec_key->peer_addr,
> &key->sec.peer_addr)){
> err = nvs_get_blob(nimble_handle, "our_sec", NULL,
> &required_size);
> if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
>
> struct ble_store_value_sec* our_sec = malloc(required_size);
> err = nvs_get_blob(nimble_handle, "our_sec", our_sec,
> &required_size);
> if (err != ESP_OK) {
> free(our_sec);
> return err;
> }
>
> memcpy(&value->sec, our_sec, required_size);
> free(our_sec);
> }
> }
>
> free(our_sec_key);
> }
> /* NVS Close */
> nvs_close(nimble_handle);
>
> /
>
> /2. ///*ble_hs_cfg.store_write_cb
> *//
>
> //case BLE_STORE_OBJ_TYPE_OUR_SEC:
> ble_store_key_from_value_sec(&key_sec, &val->sec);
>
> required_size = sizeof(struct ble_store_key_sec);
> err = nvs_set_blob(nimble_handle, "our_sec_key", &key_sec,
> required_size);
> required_size = sizeof(struct ble_store_value_sec);
> err = nvs_set_blob(nimble_handle, "our_sec", &val->sec,
> required_size);
>
> /* NVS Commit */
> err = nvs_commit(nimble_handle);
> if (err != ESP_OK) return err;
> /* NVS Close */
> nvs_close(nimble_handle);
>
> return 0;//
>
> Regards
>
> Prasad
>