This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How To Enforce Only 1:1 Bonded Connections?

I am having trouble getting peer manager bonding to work, wonder if you can help.

I'm using nRF52840 (on PAN1780 eval boards), SDK 17.0.2, Nordic SES 5.30a

First a summary of my goals. I am trying to establish a 1:1 link between two BLE nodes, just to send 4 bytes of data back an forth on a regular basis (e.g. once a second). The 1:1 "pairing" is set at the factory (though can be re-paired in the field should a node need replacing), and must not allow any other connections at either end (e.g. by bored students). I chose a simple peripheral-central connection, using the NUS (Nordic UART Services) module. I got this working nicely, initially using address filtering for the 1:1 connection. I decided to use peer manager bonding and whitelists at both ends, to provide a reliable 1:1 connection, which I believe is the proper way to do this?

Initially I tried copying code into my app from the heart rate examples ble_app_hrs and ble_app_hrs_c (which use peer manager bonding, and whitelisting at central end), but could not get it to work. See my post https://devzone.nordicsemi.com/f/nordic-q-a/73528/peer-manager-bonding---no-pm-events-when-connecting/303605

I started again with vanilla copies of ble_app_hrs and ble_app_hrs_c. First I added whitelisting to the ble_app_hrs peripheral end, copied from the HID Keyboard Example ble_app_hids_keyboard. Whilst this has some rough edges it is basically working, see these "snap1" project snapshots (peripheral and central)
https://www.dropbox.com/s/1nts5yisttgc80n/snap1-periph-hrs-bonding.zip
https://www.dropbox.com/s/b4x16u0du9htqc1/snap1-central-hrs-bonding.zip
Note these projects have absolute paths to the SDK (Z:\dev\libraries\Nordic\nRF5_SDK_17.0.2_d674dde\), do a search&replace to suit your environment.

I then replaced the HRS/BAS/DIS services with the NUS service, and this broke things, the nodes now connect without any security, no pm events, no bonding or whitelisting.
https://www.dropbox.com/s/ym1t9unbchzju75/snap3-periph-nus-bonding-broken.zip
https://www.dropbox.com/s/c7znuwisu4d94e9/snap3-central-nus-bonding-broken.zip
If bonds are in flash already (e.g. if I run snap1 first, then run snap3 without deleting bonds), then it works OK, but if I delete those bonds then the nodes just connect with no peer manager interaction.

Here are some logs to illustrate the problem (with PM_LOG_LEVEL 4 debug)
Starting with an existing bond entry, periph logs:

<info> app: BLE started
<info> app:     whitelist_set() peer_cnt 1, MAX_PEERS 8
<info> app: Fast advertising with whitelist.
<info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update, no change
<warning> peer_manager_gcm: The local database has changed, so some subscriptions to notifications and indications could not be restored for conn_handle 0
<warning> peer_manager_handler: Local DB could not be applied: conn_handle: 0, peer_id: 0
<info> app: Connected.
<info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Encryption
<info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update, no change
<info> app: GATT ATT MTU, handle 0x0 new MTU 247, data_len 244.
<info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
<info> app: SBLE TX (this is where the nodes start tx/rx NUS data)
<info> app: SBLE RX

Central logs:

<info> app: BLE started
<info> app: Starting scan.
<info> app:     whitelist_load() peer_cnt 1, MAX_PEERS 8
<info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update, no change
<info> app: Connected.
<info> peer_manager_handler: Connection secured: role: Central, conn_handle: 0, procedure: Encryption
<info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update, no change
<info> app: Data length for connection 0x0 updated to 251.
<info> app: GATT ATT MTU on connection 0x0 changed to 247.
<info> app: Discovery complete.
<info> app: Connected to device with Nordic UART Service.
<info> app: SBLE RX
<info> app: SBLE TX

There are some warnings (I guess because the services have changed), but both ends get a "peer_manager_handler: Connection secured"

But starting without any bond entries, periph logs:

<info> app: BLE started
<info> app:     whitelist_set() peer_cnt 0, MAX_PEERS 8
<info> app: Fast advertising.
<info> app: Connected.
<info> app: GATT ATT MTU, handle 0x0 new MTU 247, data_len 244.
<info> app: SBLE TX (this is where the nodes start tx/rx NUS data)
<info> app: SBLE RX

Central logs:

<info> app: Starting scan.
<info> app: Connected.
<info> app: GATT ATT MTU on connection 0x0 changed to 247.
<info> app: Data length for connection 0x0 updated to 251.
<info> app: Discovery complete.
<info> app: Connected to device with Nordic UART Service.
<info> app: SBLE RX
<info> app: SBLE TX

As you can see, connected without a peep from the peer manager....

I then spotted this thread https://devzone.nordicsemi.com/f/nordic-q-a/43221/how-to-make-pairing-mandatory
and I changed ble_nus_init() read&write_access from SEC_OPEN to SEC_JUST_WORKS - this does at least stop the unbonded TX/RX connections, but the central and periph still don't attempt to bond when they connect the first time (i.e. without whitelisted bonded entries). Nothing from peer manager...

So my main QUESTION - what am I doing wrong here? Why don't the nodes attempt to bond when they connect the first time? How do I enforce ONLY 1:1 bonded connections?
I'm sorry but I clearly don't understand how to do this properly, any pointers welcome.

While on the subject of peer managed bonding, couple of other rough edges I'd appreciate help with;
Firstly, I want a single-entry whitelist (to ensure 1:1 connection), but when pairing I don't want to forget old peer until the new one is fully bonded (just in case the node was accidentally put in pairing mode). To achieve this, I tried using "allow_repairing", see this post, but that has got a bit messy, is there a cleaner way?
https://devzone.nordicsemi.com/f/nordic-q-a/73538/hid-keyboard-example---how-to-create-new-bond-without-deleting-old-bond

Secondly, with the basic ble_app_hrs_c bonding & whitelisting, another unauthorised central could still connect to the peer. I stopped this by adding case PM_EVT_CONN_SEC_FAILED to pm_evt_handler(), which calls sd_ble_gap_disconnect(). This works in snap1, but of course is of no use in snap3 as a connection is made without even calling pm_evt_handler()! Is there a better way to do this? I guess this relates to my main question - how do I enforce ONLY 1:1 bonded connections?

Stepping back, am I taking the right approach? All I want is a secure reliable 1:1 connection to send 4 bytes payload back and forth. I didn't expect it to be this bespoke. Are there any other examples I should be looking at? HRS and HID keyboard seem to be the ones most often mentioned in discussions about this.

I would really appreciate some help - I have spent weeks on this, and I am struggling to fully understand how the peer manager interacts with connections. Many thanks

Parents
  • Hi Benmack, 

    The central side needs initial bonding. You could initial bonding in nus_c_evt_handler as

    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
        ret_code_t err_code;
    
        switch (p_ble_nus_evt->evt_type)
        {
            case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Discovery complete.");
                err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
                APP_ERROR_CHECK(err_code);
    
                // Initiate bonding.
                err_code = pm_conn_secure(p_ble_nus_evt->conn_handle, false);
                if (err_code != NRF_ERROR_BUSY)
                {
                    APP_ERROR_CHECK(err_code);
                }
    
                err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("Connected to device with Nordic UART Service.");
                break;

    -Amanda H.

  • Thanks Amanda, much appreciated

    Do you know where I would find any documentation on this? I.e. listing the things I need to do to force a bonded connection? I feel like I'm searching for pieces of a puzzle...

    And stepping back a bit, is this the best way to establish a secure reliable 1:1 connection?

    Thanks again, Ben

Reply Children
Related