Saving #BluetoothMesh Provisioning & Configuration related data on flash of nRF52 using NFFS #bluetoothmesh


Vikrant More <vikrant8051@...>
 

Hello World !!

By including NFFS support into #BluetoothMesh project, now I can access flash of nRF52.

{
  Some useful links:

  http://docs.zephyrproject.org/api/file_system.html
  https://lists.zephyrproject.org/pipermail/zephyr-devel/2018-January/thread.html (threads related to NFFS will be helpful to others )
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I've edited prov_data( ) function which is available at $zephyr_base/subssy/bluetooth/host/mesh/prov.c as follow,

static void prov_data(const u8_t *data)
{
    struct net_buf_simple *msg = PROV_BUF(1);
    u8_t session_key[16];
    u8_t nonce[13];
    u8_t dev_key[16];
    u8_t pdu[25];
    u8_t flags;
    u32_t iv_index;
    u16_t addr;
    u16_t net_idx;
    int err;

    BT_DBG("");

    err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key);
    if (err) {
        BT_ERR("Unable to generate session key");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("SessionKey: %s", bt_hex(session_key, 16));

    err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce);
    if (err) {
        BT_ERR("Unable to generate session nonce");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("Nonce: %s", bt_hex(nonce, 13));

    err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu);
    if (err) {
        BT_ERR("Unable to decrypt provisioning data");
        close_link(PROV_ERR_DECRYPT, CLOSE_REASON_FAILED);
        return;
    }

    err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key);
    if (err) {
        BT_ERR("Unable to generate device key");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("DevKey: %s", bt_hex(dev_key, 16));

    net_idx = sys_get_be16(&pdu[16]);
    flags = pdu[18];
    iv_index = sys_get_be32(&pdu[19]);
    addr = sys_get_be16(&pdu[23]);

    BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x",
           net_idx, iv_index, addr);

    prov_buf_init(msg, PROV_COMPLETE);
    prov_send(msg);

    /* Ignore any further PDUs on this link */
    link.expect = 0;

    bt_mesh_provision(pdu, net_idx, flags, iv_index, 0, addr, dev_key);


//------------------------------------------------------------------------------------------------------------------------------------------

    struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    };

    union
    {
        unsigned char array[50];
        struct prov_data a;
    }foo;
   
     int i;

    for(i=0;i<=24;i++)
    {
        foo.a.pdu[i]=pdu[i];
    }

    for(i=0;i<=15;i++)
    {
        foo.a.dev_key[i]=dev_key[i];
    }

    foo.a.flags = flags;
    foo.a.net_idx = net_idx;
    foo.a.addr = addr;   
    foo.a.iv_index = iv_index;
 
    fs_file_t fp;   

    err = fs_open(&fp,"/prov.txt");
    if (err != 0)
    {
        printk("\n\rerror %d while opening prov_cfg.txt for write\n\r", err);
    }

    err = fs_write(&fp, foo.array, 50);
    if (err != 50)
    {
        printk("\n\rerror %d while writing PDU\n\r", err);
    }

    err = fs_close(&fp);
    if (err != 0)
    {
        printk("\n\rerror %d while closing prov_cfg.txt after write\n\r", err);
    }

//------------------------------------------------------------------------------------------------------------------------------------------


}


Similarly, edit bt_ready( ) from $zephyr_base/samples/bluetooth/mesh/src/main.c as follow

static void bt_ready(int err)
{
    .
    .
    .
    .
    printk("Mesh initialized\n\r");

    struct fs_dirent entry;

    struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    };

    union
    {
        unsigned char array[50];
        struct prov_data a;
    }test;

    if(fs_stat("/prov.txt",&entry)==0)
    {
        printk("\n\rprov.txt is available\n\r");

        fs_file_t fp;

        err = fs_open(&fp,"/prov.txt");
        if (err != 0) {
            printk("error %d while opening for read\n\r", err);
        }

        err = fs_read(&fp, test.array, 50);
        if (err < 0) {
            printk("error %d while reading\n\r", err);
        }

        err = fs_close(&fp);
        if (err != 0) {
            printk("error %d while closing after read\n\r", err);
        }

        err = bt_mesh_provision(test.a.pdu, test.a.net_idx, test.a.flags, test.a.iv_index, 0, test.a.addr, test.a.dev_key);
   
        if(err)
        {
            printk("Provisioning failed (err %d)\n", err);
            return;
        }

        printk("Provisioning completed\n\r");
   
    }

}

So after reset if prov.txt is available then DEVICE will automatically provision itself.
And as per my testing it is working perfectly.

But is it right approach since I've dare to touch stack ? 🤔

Now I wanna save data related to configuration which happens just after provisioning.

Where I will find that function ?

I'm aware about bt_mesh_cfg_app_key_add( ) this function but for that we've to enable CONFIG_BT_MESH_CFG_CLI=y
Is it necessary ? ...because even we disable it, provisioner APP trigger some function which does every thing like bt_mesh_cfg_app_key_add( ) does.

So please tell me where I will find that function, so that I can save ALL data related configuration into cfg.txt ?

As per my understanding once we complete, Provisioning & Configuration process, then there is no need to touch prov.txt & cfg.txt
in future for writing ? Am I right ?

Besides prov.txt & cfg.txt , how many files we have to create ?

If there will be standard for creating files for #BluetoothMesh then that will helpful for all.

Thank You !!


Vikrant More <vikrant8051@...>
 

After testing I found that it is necessary to add
__attribute__((packed)) after structure defination
Why ??  This will be helpful --> http://www.avabodh.com/cin/structure.html

So I edit above mentioned structure definition as (in both locations)

struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    }__attribute__((packed));



On Tue, Jan 30, 2018 at 3:49 PM, Vikrant More <vikrant8051@...> wrote:
Hello World !!

By including NFFS support into #BluetoothMesh project, now I can access flash of nRF52.

{
  Some useful links:

  http://docs.zephyrproject.org/api/file_system.html
  https://lists.zephyrproject.org/pipermail/zephyr-devel/2018-January/thread.html (threads related to NFFS will be helpful to others )
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I've edited prov_data( ) function which is available at $zephyr_base/subssy/bluetooth/host/mesh/prov.c as follow,

static void prov_data(const u8_t *data)
{
    struct net_buf_simple *msg = PROV_BUF(1);
    u8_t session_key[16];
    u8_t nonce[13];
    u8_t dev_key[16];
    u8_t pdu[25];
    u8_t flags;
    u32_t iv_index;
    u16_t addr;
    u16_t net_idx;
    int err;

    BT_DBG("");

    err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key);
    if (err) {
        BT_ERR("Unable to generate session key");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("SessionKey: %s", bt_hex(session_key, 16));

    err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce);
    if (err) {
        BT_ERR("Unable to generate session nonce");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("Nonce: %s", bt_hex(nonce, 13));

    err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu);
    if (err) {
        BT_ERR("Unable to decrypt provisioning data");
        close_link(PROV_ERR_DECRYPT, CLOSE_REASON_FAILED);
        return;
    }

    err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key);
    if (err) {
        BT_ERR("Unable to generate device key");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("DevKey: %s", bt_hex(dev_key, 16));

    net_idx = sys_get_be16(&pdu[16]);
    flags = pdu[18];
    iv_index = sys_get_be32(&pdu[19]);
    addr = sys_get_be16(&pdu[23]);

    BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x",
           net_idx, iv_index, addr);

    prov_buf_init(msg, PROV_COMPLETE);
    prov_send(msg);

    /* Ignore any further PDUs on this link */
    link.expect = 0;

    bt_mesh_provision(pdu, net_idx, flags, iv_index, 0, addr, dev_key);


//------------------------------------------------------------------------------------------------------------------------------------------

    struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    };

    union
    {
        unsigned char array[50];
        struct prov_data a;
    }foo;
   
     int i;

    for(i=0;i<=24;i++)
    {
        foo.a.pdu[i]=pdu[i];
    }

    for(i=0;i<=15;i++)
    {
        foo.a.dev_key[i]=dev_key[i];
    }

    foo.a.flags = flags;
    foo.a.net_idx = net_idx;
    foo.a.addr = addr;   
    foo.a.iv_index = iv_index;
 
    fs_file_t fp;   

    err = fs_open(&fp,"/prov.txt");
    if (err != 0)
    {
        printk("\n\rerror %d while opening prov_cfg.txt for write\n\r", err);
    }

    err = fs_write(&fp, foo.array, 50);
    if (err != 50)
    {
        printk("\n\rerror %d while writing PDU\n\r", err);
    }

    err = fs_close(&fp);
    if (err != 0)
    {
        printk("\n\rerror %d while closing prov_cfg.txt after write\n\r", err);
    }

//------------------------------------------------------------------------------------------------------------------------------------------


}


Similarly, edit bt_ready( ) from $zephyr_base/samples/bluetooth/mesh/src/main.c as follow

static void bt_ready(int err)
{
    .
    .
    .
    .
    printk("Mesh initialized\n\r");

    struct fs_dirent entry;

    struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    };

    union
    {
        unsigned char array[50];
        struct prov_data a;
    }test;

    if(fs_stat("/prov.txt",&entry)==0)
    {
        printk("\n\rprov.txt is available\n\r");

        fs_file_t fp;

        err = fs_open(&fp,"/prov.txt");
        if (err != 0) {
            printk("error %d while opening for read\n\r", err);
        }

        err = fs_read(&fp, test.array, 50);
        if (err < 0) {
            printk("error %d while reading\n\r", err);
        }

        err = fs_close(&fp);
        if (err != 0) {
            printk("error %d while closing after read\n\r", err);
        }

        err = bt_mesh_provision(test.a.pdu, test.a.net_idx, test.a.flags, test.a.iv_index, 0, test.a.addr, test.a.dev_key);
   
        if(err)
        {
            printk("Provisioning failed (err %d)\n", err);
            return;
        }

        printk("Provisioning completed\n\r");
   
    }

}

So after reset if prov.txt is available then DEVICE will automatically provision itself.
And as per my testing it is working perfectly.

But is it right approach since I've dare to touch stack ? 🤔

Now I wanna save data related to configuration which happens just after provisioning.

Where I will find that function ?

I'm aware about bt_mesh_cfg_app_key_add( ) this function but for that we've to enable CONFIG_BT_MESH_CFG_CLI=y
Is it necessary ? ...because even we disable it, provisioner APP trigger some function which does every thing like bt_mesh_cfg_app_key_add( ) does.

So please tell me where I will find that function, so that I can save ALL data related configuration into cfg.txt ?

As per my understanding once we complete, Provisioning & Configuration process, then there is no need to touch prov.txt & cfg.txt
in future for writing ? Am I right ?

Besides prov.txt & cfg.txt , how many files we have to create ?

If there will be standard for creating files for #BluetoothMesh then that will helpful for all.

Thank You !!



Vikrant More <vikrant8051@...>
 

As per this document ....

nrf5_SDK_for_Mesh_v1.0.1_src/doc/introduction/mesh_hw_resources.md

(I've attached this file for reference......very informative)

The mesh stack uses flash to store the following states:
- Encryption keys
- Mesh addresses
- Access model composition
- Access model configuration
- Network message sequence number
- Network IV index state
- DFU metadata (it is not part of #BluetoothMesh Specs)

Link to download latest Nordic Mesh SDK v1.0.1 --> https://www.nordicsemi.com/eng/nordic/download_resource/62377/26/71116706/126781
Is other than this, anything else we have to save on flash  ?

Thank You !!

On Tue, Jan 30, 2018 at 5:22 PM, Vikrant More <vikrant8051@...> wrote:
After testing I found that it is necessary to add
__attribute__((packed)) after structure defination
Why ??  This will be helpful --> http://www.avabodh.com/cin/structure.html

So I edit above mentioned structure definition as (in both locations)

struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    }__attribute__((packed));



On Tue, Jan 30, 2018 at 3:49 PM, Vikrant More <vikrant8051@...> wrote:
Hello World !!

By including NFFS support into #BluetoothMesh project, now I can access flash of nRF52.

{
  Some useful links:

  http://docs.zephyrproject.org/api/file_system.html
  https://lists.zephyrproject.org/pipermail/zephyr-devel/2018-January/thread.html (threads related to NFFS will be helpful to others )
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I've edited prov_data( ) function which is available at $zephyr_base/subssy/bluetooth/host/mesh/prov.c as follow,

static void prov_data(const u8_t *data)
{
    struct net_buf_simple *msg = PROV_BUF(1);
    u8_t session_key[16];
    u8_t nonce[13];
    u8_t dev_key[16];
    u8_t pdu[25];
    u8_t flags;
    u32_t iv_index;
    u16_t addr;
    u16_t net_idx;
    int err;

    BT_DBG("");

    err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key);
    if (err) {
        BT_ERR("Unable to generate session key");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("SessionKey: %s", bt_hex(session_key, 16));

    err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce);
    if (err) {
        BT_ERR("Unable to generate session nonce");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("Nonce: %s", bt_hex(nonce, 13));

    err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu);
    if (err) {
        BT_ERR("Unable to decrypt provisioning data");
        close_link(PROV_ERR_DECRYPT, CLOSE_REASON_FAILED);
        return;
    }

    err = bt_mesh_dev_key(link.dhkey, link.prov_salt, dev_key);
    if (err) {
        BT_ERR("Unable to generate device key");
        close_link(PROV_ERR_UNEXP_ERR, CLOSE_REASON_FAILED);
        return;
    }

    BT_DBG("DevKey: %s", bt_hex(dev_key, 16));

    net_idx = sys_get_be16(&pdu[16]);
    flags = pdu[18];
    iv_index = sys_get_be32(&pdu[19]);
    addr = sys_get_be16(&pdu[23]);

    BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x",
           net_idx, iv_index, addr);

    prov_buf_init(msg, PROV_COMPLETE);
    prov_send(msg);

    /* Ignore any further PDUs on this link */
    link.expect = 0;

    bt_mesh_provision(pdu, net_idx, flags, iv_index, 0, addr, dev_key);


//------------------------------------------------------------------------------------------------------------------------------------------

    struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    };

    union
    {
        unsigned char array[50];
        struct prov_data a;
    }foo;
   
     int i;

    for(i=0;i<=24;i++)
    {
        foo.a.pdu[i]=pdu[i];
    }

    for(i=0;i<=15;i++)
    {
        foo.a.dev_key[i]=dev_key[i];
    }

    foo.a.flags = flags;
    foo.a.net_idx = net_idx;
    foo.a.addr = addr;   
    foo.a.iv_index = iv_index;
 
    fs_file_t fp;   

    err = fs_open(&fp,"/prov.txt");
    if (err != 0)
    {
        printk("\n\rerror %d while opening prov_cfg.txt for write\n\r", err);
    }

    err = fs_write(&fp, foo.array, 50);
    if (err != 50)
    {
        printk("\n\rerror %d while writing PDU\n\r", err);
    }

    err = fs_close(&fp);
    if (err != 0)
    {
        printk("\n\rerror %d while closing prov_cfg.txt after write\n\r", err);
    }

//------------------------------------------------------------------------------------------------------------------------------------------


}


Similarly, edit bt_ready( ) from $zephyr_base/samples/bluetooth/mesh/src/main.c as follow

static void bt_ready(int err)
{
    .
    .
    .
    .
    printk("Mesh initialized\n\r");

    struct fs_dirent entry;

    struct prov_data
    {
        u8_t pdu[25];
        u8_t dev_key[16];
        u8_t flags;
        u16_t net_idx;
        u16_t addr;
        u32_t iv_index;
    };

    union
    {
        unsigned char array[50];
        struct prov_data a;
    }test;

    if(fs_stat("/prov.txt",&entry)==0)
    {
        printk("\n\rprov.txt is available\n\r");

        fs_file_t fp;

        err = fs_open(&fp,"/prov.txt");
        if (err != 0) {
            printk("error %d while opening for read\n\r", err);
        }

        err = fs_read(&fp, test.array, 50);
        if (err < 0) {
            printk("error %d while reading\n\r", err);
        }

        err = fs_close(&fp);
        if (err != 0) {
            printk("error %d while closing after read\n\r", err);
        }

        err = bt_mesh_provision(test.a.pdu, test.a.net_idx, test.a.flags, test.a.iv_index, 0, test.a.addr, test.a.dev_key);
   
        if(err)
        {
            printk("Provisioning failed (err %d)\n", err);
            return;
        }

        printk("Provisioning completed\n\r");
   
    }

}

So after reset if prov.txt is available then DEVICE will automatically provision itself.
And as per my testing it is working perfectly.

But is it right approach since I've dare to touch stack ? 🤔

Now I wanna save data related to configuration which happens just after provisioning.

Where I will find that function ?

I'm aware about bt_mesh_cfg_app_key_add( ) this function but for that we've to enable CONFIG_BT_MESH_CFG_CLI=y
Is it necessary ? ...because even we disable it, provisioner APP trigger some function which does every thing like bt_mesh_cfg_app_key_add( ) does.

So please tell me where I will find that function, so that I can save ALL data related configuration into cfg.txt ?

As per my understanding once we complete, Provisioning & Configuration process, then there is no need to touch prov.txt & cfg.txt
in future for writing ? Am I right ?

Besides prov.txt & cfg.txt , how many files we have to create ?

If there will be standard for creating files for #BluetoothMesh then that will helpful for all.

Thank You !!