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

Errors after unpairing devices and further attempts to bond them

I built and run Bluetooth: Peripheral HIDS keyboard example on nRF52840 DK using nRF Connect SDK 1.3.0. I connected and bonded with it from an Android phone. Then I deleted bond information from the Android phone. After it, I wanted to connect and bond again. And it worked properly. Great! It was BT_SECURITY_L4. You can see UART logs below.

*** Booting Zephyr OS build v2.3.0-rc1-ncs1  ***
Starting Bluetooth Peripheral HIDS keyboard example
I: 8 Sectors of 4096 bytes
I: alloc wra: 0, fa0
I: data wra: 0, f4
I: HW Platform: Nordic Semiconductor (0x0002)
I: HW Variant: nRF52x (0x0002)
I: Firmware: Standard Bluetooth controller (0x00) Version 2.3 Build 0
I: No ID address. App must call settings_load()
Bluetooth initialized
E: set-value failure. key: bt/name error(-2)
I: Identity: d6:c4:f9:a2:02:ad (random)
I: HCI: version 5.2 (0x0b) revision 0x0000, manufacturer 0x05f1
I: LMP: version 5.2 (0x0b) subver 0xffff
NFC configuration start
NFC configuration done
Advertising successfully started
Advertising continued
Connected 20:47:da:12:f4:e8 (public)
Passkey for 20:47:da:12:f4:e8 (public): 800540
Press Button 1 to confirm, Button 2 to reject.
Numeric Match, conn 0x2000177c
Key report send error: -13
Security changed: 20:47:da:12:f4:e8 (public) level 4
Pairing completed: 20:47:da:12:f4:e8 (public), bonded: 1
Disconnected from 20:47:da:12:f4:e8 (public) (reason 19)
Advertising successfully started
Advertising continued
Connected 20:47:da:12:f4:e8 (public)
Passkey for 20:47:da:12:f4:e8 (public): 379671
Press Button 1 to confirm, Button 2 to reject.
Numeric Match, conn 0x2000177c
Security changed: 20:47:da:12:f4:e8 (public) level 4
Pairing completed: 20:47:da:12:f4:e8 (public), bonded: 1
Disconnected from 20:47:da:12:f4:e8 (public) (reason 19)


Now I want to do the same with BT_SECURITY_L2 without any numeric comparison. What should I do? I set passkey_display and passkey_confirm callbacks to NULL:

static struct bt_conn_auth_cb conn_auth_callbacks = {
	.passkey_display = NULL,
	.passkey_confirm = NULL,
	.cancel = auth_cancel,
	.pairing_confirm = pairing_confirm,
#if CONFIG_NFC_OOB_PAIRING
	.oob_data_request = auth_oob_data_request,
#endif
	.pairing_complete = pairing_complete,
	.pairing_failed = pairing_failed
};


Is it right?

And I built and run the program. And I did the same steps of connecting/disconnecting and bonding/deleting bond information twice. And you can see in below UART logs that I couldn't bond the second time:

Security failed: 20:47:da:12:f4:e8 (public) level 1 err 4
Pairing failed conn: 20:47:da:12:f4:e8 (public), reason 4

*** Booting Zephyr OS build v2.3.0-rc1-ncs1  ***
Starting Bluetooth Peripheral HIDS keyboard example
I: 8 Sectors of 4096 bytes
I: alloc wra: 0, ff0
I: data wra: 0, 0
I: HW Platform: Nordic Semiconductor (0x0002)
I: HW Variant: nRF52x (0x0002)
I: Firmware: Standard Bluetooth controller (0x00) Version 2.3 Build 0
I: No ID address. App must call settings_load()
Bluetooth initialized
I: Identity: d6:c4:f9:a2:02:ad (random)
I: HCI: version 5.2 (0x0b) revision 0x0000, manufacturer 0x05f1
I: LMP: version 5.2 (0x0b) subver 0xffff
NFC configuration start
NFC configuration done
Advertising successfully started
Advertising continued
Connected 48:ef:30:6f:b3:db (random)
Pairing confirmed: 48:ef:30:6f:b3:db (random)
Security changed: 48:ef:30:6f:b3:db (random) level 2
Pairing completed: 20:47:da:12:f4:e8 (public), bonded: 1
Disconnected from 20:47:da:12:f4:e8 (public) (reason 19)
Advertising successfully started
Advertising continued
Connected 20:47:da:12:f4:e8 (public)
Security failed: 20:47:da:12:f4:e8 (public) level 1 err 4
Pairing failed conn: 20:47:da:12:f4:e8 (public), reason 4
Disconnected from 20:47:da:12:f4:e8 (public) (reason 19)

Logs from nRF Connect SDK:

nRF Connect, 2020-08-07
Nordic_HIDS_keyboard (D6:C4:F9:A2:02:AD)
V	02:32:15.042	Connecting to D6:C4:F9:A2:02:AD...
D	02:32:15.042	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	02:32:15.922	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	02:32:15.922	Connected to D6:C4:F9:A2:02:AD
D	02:32:15.922	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
V	02:32:15.946	Discovering services...
D	02:32:15.946	gatt.discoverServices()
D	02:32:15.954	[Callback] Services discovered with status: 0
I	02:32:15.954	Services discovered
V	02:32:15.991	Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Client Supported Features [R W] (0x2B29)
- Database Hash [R] (0x2B2A)
Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
- Peripheral Preferred Connection Parameters [R] (0x2A04)
Battery Service (0x180F)
- Battery Level [N R] (0x2A19)
   Client Characteristic Configuration (0x2902)
Device Information (0x180A)
- Model Number String [R] (0x2A24)
- Manufacturer Name String [R] (0x2A29)
- PnP ID [R] (0x2A50)
Human Interface Device (0x1812)
- Protocol Mode [R WNR] (0x2A4E)
- Report [N R] (0x2A4D)
   Client Characteristic Configuration (0x2902)
   Report Reference (0x2908)
- Report [R W WNR] (0x2A4D)
   Report Reference (0x2908)
- Report Map [R] (0x2A4B)
- Boot Keyboard Input Report [N R] (0x2A22)
   Client Characteristic Configuration (0x2902)
- Boot Keyboard Output Report [R W WNR] (0x2A32)
- HID Information [R] (0x2A4A)
- HID Control Point [WNR] (0x2A4C)
D	02:32:15.991	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	02:32:15.993	gatt.setCharacteristicNotification(00002a19-0000-1000-8000-00805f9b34fb, true)
D	02:32:15.994	gatt.setCharacteristicNotification(00002a4d-0000-1000-8000-00805f9b34fb, true)
D	02:32:15.995	gatt.setCharacteristicNotification(00002a22-0000-1000-8000-00805f9b34fb, true)
V	02:32:17.786	Starting pairing...
D	02:32:17.786	device.createBond()
D	02:32:17.809	[Broadcast] Action received: android.bluetooth.device.action.BOND_STATE_CHANGED, bond state changed to: BOND_BONDING (11)
I	02:32:18.619	Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
D	02:32:19.158	[Broadcast] Action received: android.bluetooth.device.action.BOND_STATE_CHANGED, bond state changed to: BOND_BONDED (12)
I	02:32:19.158	Device bonded
I	02:32:19.696	Connection parameters updated (interval: 45.0ms, latency: 0, timeout: 5000ms)
I	02:32:21.226	Connection parameters updated (interval: 45.0ms, latency: 0, timeout: 420ms)
V	02:32:28.559	Removing bond information...
D	02:32:28.559	device.removeBond() (hidden)
D	02:32:28.608	[Callback] Connection state changed with status: 22 and new state: DISCONNECTED (0)
E	02:32:28.609	Error 22 (0x16): GATT CONN TERMINATE LOCAL HOST
I	02:32:28.609	Disconnected
D	02:32:28.628	[Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED
D	02:32:29.218	[Broadcast] Action received: android.bluetooth.device.action.BOND_STATE_CHANGED, bond state changed to: BOND_NONE (10)
I	02:32:29.218	Bond information deleted
D	02:32:36.404	gatt.close()
D	02:32:36.406	wait(200)
V	02:32:36.608	Connecting to D6:C4:F9:A2:02:AD...
D	02:32:36.608	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	02:32:37.564	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
D	02:32:37.569	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	02:32:37.569	Connected to D6:C4:F9:A2:02:AD
V	02:32:37.594	Discovering services...
D	02:32:37.594	gatt.discoverServices()
D	02:32:37.601	[Callback] Services discovered with status: 0
I	02:32:37.601	Services discovered
V	02:32:37.617	Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Client Supported Features [R W] (0x2B29)
- Database Hash [R] (0x2B2A)
Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
- Peripheral Preferred Connection Parameters [R] (0x2A04)
Battery Service (0x180F)
- Battery Level [N R] (0x2A19)
   Client Characteristic Configuration (0x2902)
Device Information (0x180A)
- Model Number String [R] (0x2A24)
- Manufacturer Name String [R] (0x2A29)
- PnP ID [R] (0x2A50)
Human Interface Device (0x1812)
- Protocol Mode [R WNR] (0x2A4E)
- Report [N R] (0x2A4D)
   Client Characteristic Configuration (0x2902)
   Report Reference (0x2908)
- Report [R W WNR] (0x2A4D)
   Report Reference (0x2908)
- Report Map [R] (0x2A4B)
- Boot Keyboard Input Report [N R] (0x2A22)
   Client Characteristic Configuration (0x2902)
- Boot Keyboard Output Report [R W WNR] (0x2A32)
- HID Information [R] (0x2A4A)
- HID Control Point [WNR] (0x2A4C)
D	02:32:37.617	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	02:32:37.619	gatt.setCharacteristicNotification(00002a19-0000-1000-8000-00805f9b34fb, true)
D	02:32:37.621	gatt.setCharacteristicNotification(00002a4d-0000-1000-8000-00805f9b34fb, true)
D	02:32:37.624	gatt.setCharacteristicNotification(00002a22-0000-1000-8000-00805f9b34fb, true)
V	02:32:40.512	Starting pairing...
D	02:32:40.512	device.createBond()
D	02:32:40.541	[Broadcast] Action received: android.bluetooth.device.action.BOND_STATE_CHANGED, bond state changed to: BOND_BONDING (11)
D	02:32:40.589	[Broadcast] Action received: android.bluetooth.device.action.BOND_STATE_CHANGED, bond state changed to: BOND_NONE (10)
I	02:32:40.589	Bonding failed
I	02:32:41.072	Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
D	02:32:43.644	[Callback] Connection state changed with status: 22 and new state: DISCONNECTED (0)
E	02:32:43.644	Error 22 (0x16): GATT CONN TERMINATE LOCAL HOST
I	02:32:43.644	Disconnected
D	02:32:43.708	[Broadcast] Action received: android.bluetooth.device.action.ACL_DISCONNECTED

As I understood, I had to add unpairing on the side of peripherals. And I added bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY) call in a disconnected callback. Then I built and run the program again and I tried the same steps of connecting/disconnecting and bonding/deleting bond information twice. And everything worked fine!

So, I want to ask you about the unpairing stage. In which callback should I call bt_unpair function?

Is there a way to distinguish ordinary disconnection from deleting bond information on a remote device? I think that no. So, I want to ask how to properly avoid the error with the second attempt to bond, when there's not a numeric comparison. It's an ordinary case when the bond information was deleted on the remote device and it tries to connect the second time. So I have to handle such bonding properly. Please, explain to me, how to cope with it.

Why don't provided examples have such unpairing functions?

And why did a security level changed to 1 during the second bonding without calling bt_unpair function, although it was 2 after the first attempt?

Thank you in advance for any assistance!

  • As I understood, I had to add unpairing on the side of peripherals.

     That's correct! The device won't be able to connect and pair again to a device it thinks it is already paired with. If you'd like to delete bonding information upon a disconnect, it would be correct to add the bt_unpair function in the disconnected callback.

    Is there a way to distinguish ordinary disconnection from deleting bond information on a remote device?

     No, the peripheral won't be able to distinguish this as far as I know.

    The reason our examples don't do this by default is that you'd generally like to keep bonding information even though the devices disconnect from one another so that reconnections are easier. You can call the bt_unpair() by I.E. pressing a button if you'd like to delete the bonding information manually instead. This is just a suggestion, and I'm sure there are multiple clever solutions on how you could do this.

    Best regards,

    Simon

  • Thank you very much for your response!

    I would like to clarify, is it possible to correctly handle the second attempt to bond, when a central device has deleted bond information, whereas a peripheral device still stores it? In a security_changed callback we can see an error, when the central device tries to bond again after deleting the bond information. Can the peripheral device delete outdated bond information, when during the second attempt it raises the error and bond again successfully within the second bonding?

    So, I will try to rephrase. Central and peripheral devices are bonded. After it, the central device deletes bond information, and the peripheral device still stores it. Then the central device tries to bond again to the peripheral device. Now it raises an error, because the peripheral device thinks it is already paired. If I don't want to delete to bond information after each disconnection, and I want to delete it only it becomes not corresponding to the central device bond information. So, how should the central device handle the second attempt of bonding? Can you specify callbacks, when the central device recognises that bond information is wrong, so it should delete it and bond again and not just break the connection?

  • Hi Roman

    This should be possible I guess, however the error message we get when trying to pair with an "already paired" device is not specific to that particular error. Reason 19 points to "No such device", and reason 4 points to "Interrupted system call" in the errno.h file located here ...\ncs\v1.3.0\zephyr\lib\libc\minimal\include\errno.h. These error codes are not specific to this issue though as far as I know, so the device would delete bonding information whenever one of these occur, whether it's related to the bonding discrepancy or not. You will have to decide if this would be okay or not in your application or put the bt_unpair function somewhere else that makes sense in your application.

    Best regards,

    Simon

  • Simon, thank you for your response!


    Did you mean that bond information should be deleted automatically in the case of error reason 4 (Interrupted system call) in pairing_failed callback? I didn't notice such behaviour. I needed to reset microcontroller or erase flash in the case of persistent settings in order to delete bond information and pair again.


    If to talk about an explicit call of bt_unpair to delete bond information, then I try to find an appropriate place to delete bond information. As I understood, there's no specific error code for "already paired" devices, but even if it existed I would receive this error only in pairing_failed or security_changed callback. But it's already too late to make the connection with this device within the current pairing. So, tell me, please, how can I delete bond information about a device, which was paired, but it has deleted bond information on its side, and now it's trying to pair again? I want to know how to delete bond information for this device and pair it again within the second pairing, and not to delete bond information within the second pairing and pair them again within the third pairing. I am sure that there's a straightforward way how to delete bond information within the failed pairing and merely pair again within the current pairing. Maybe I can hook failed pairing before pairing_failed or security_changed callback, then delete outdated bond information about this device and pair again with them. I don't know exactly about your pairing flow, but I want to ask you about the place, where should I delete bond information about the device, if we understand that it's outdated and we have to pair again, and pair with this device again within the same pairing process, and not a new one. I also cannot understand why when the second attempt to pair was failed I received a security level equal to 1 in security_changed callback, and not equal to 2, as it was during the previous successful connection.

    Do you know the place, function, callback, whatever,  where I can check during a pairing process, that devices were already paired, but bond information is outdated, and delete outdated bond information (using bt_unpair function or anything else) and pair again from scratch?

  • RAlexeev said:
    Did you mean that bond information should be deleted automatically in the case of error reason 4

     No, the nRF will not delete bonding information automatically at any point by default. I meant that you may implement a bt_unpair() function whenever this error occurs yourself, however, this error is not specific to the nRF thinking it is already bonded with a device, so I'm not sure if that might cause it to delete bonding information in some corner cases where you wouldn't want it to.

    I understand what you mean, and there was an allow_repair function in the nRF5 SDK, where you would get an event saying that a peer tries pairing even though the bonding information is already stored, and would then return a struct with allow_repair = true. As far as I can see, this has not been added to NCS yet, but I have asked the developers for confirmation. I will get back to you when I hear something from them.

    Best regards,

    Simon

    UPDATE: Here's what the developers had to say about this. It's allowed to re-pair if the existing bond information is authenticated, and the new pair procedure also is. Allowing unauthenticated pairing to overwrite the bond information is a security issue, so that's not allowed. There is an option to override this though, using BT_SMP_ALLOW_UNAUTH_OVERWRITE, but this is not recommended due to the security issue mentioned.

Related