Re: Storing Bonding information in NVS memory
Hi Prasad, On Fri, Feb 15, 2019 at 1:24 PM prasad 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
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
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
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
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
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 disconnect; reason=531 handle=0 our_ota_addr_type=0 our_ota_addr=24:0a:c4:23:be:76 our_id_addr_type=0 our_id_addr=24:0a:c4:23:be:76 peer_ota_addr_type=1 peer_ota_addr=4c:fb:ae:cb:1e:d0 peer_id_addr_type=1 peer_id_addr=4c:fb:ae:cb:1e:d0 conn_itvl=36 conn_latency=0 supervision_timeout=500 encrypted=1 authenticated=1 bonded=1 ble_hs_hci_cmd_send: ogf=0x08 ocf=0x0007 len=0 0x07 0x20 0x00 ble_hs_hci_cmd_send: ogf=0x08 ocf=0x0008 len=32 0x08 0x20 0x20 0x1f 0x02 0x01 0x06 0x03 0x03 0x11 0x18 0x14 0x09 0x42 0x4f 0x4e 0x44 0x5f 0x6e 0x69 0x6d 0x62 0x6c 0x65 0x2d 0x62 0x6c 0x65 0x70 0x72 0x70 0x68 0x02 0x0a 0x03 GAP procedure initiated: advertise; disc_mode=2 adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0 ble_hs_hci_cmd_send: ogf=0x08 ocf=0x0006 len=15 0x06 0x20 0x0f 0x30 0x00 0x60 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x07 0x00 ble_hs_hci_cmd_send: ogf=0x08 ocf=0x000a len=1 0x0a 0x20 0x01 0x01 * ble_hs_hci_evt_process:: Data=003e * I (31215) NIMBLE_BLE_PRPH: Entered event BLE_GAP_EVENT_CONNECT *Entered ble_sm_slave_initiate...* *proc result called from ble_SM_SLAVE_initiate * ** Entered into ble_sm_process_result ** ** res->exec=1, res->app_status=0, proc->state=8, ** -* Entered into ble_sm_sec_req_exec * - ble_sm_sec_req:: auth_req:: 13 sm_sm_sc_sm_MITM_^_sm_bondinghost tx hci data; handle=0 length=6 ble_hs_hci_acl_tx(): 0x00 0x00 0x06 0x00 0x02 0x00 0x06 0x00 0x0b 0x0d connection established; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=24:0a:c4:23:be:76 our_id_addr_type=0 our_id_addr=24:0a:c4:23:be:76 peer_ota_addr_type=1 peer_ota_addr=4c:fb:ae:cb:1e:d0 peer_id_addr_type=1 peer_id_addr=4c:fb:ae:cb:1e:d0 conn_itvl=36 conn_latency=0 supervision_timeout=500 encrypted=0 authenticated=0 bonded=0 ble_hs_hci_cmd_send: ogf=0x08 ocf=0x0016 len=2 0x16 0x20 0x02 0x00 0x00 * ble_hs_hci_evt_process:: Data=00
Re: Storing Bonding information in NVS memory
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
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