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

Whitelist, SDK 14.0.0, bonded peer can't connect

Hi.

I want my peripheral, an nRF52832, to accept a connection from the first peer it sees and bond with that peer, and thereafter accept connections only from that peer (but still be visible to other centrals scanning). I need this to work for both Android and iOS centrals.

Here's my whitelist reply code, running on the BLE_ADV_EVT_WHITELIST_REQUEST event, but only when we're bonded already:

void whitelist_reply(void)
{
	ret_code_t err_code = 0;

	// Get the first and only peer ID. We must have one by now, because we only send a whitelist reply when we're bonded.
	pm_peer_id_t peer_ids[1];
	pm_peer_id_t peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);

	if (peer_id == PM_PEER_ID_INVALID)
	{
		// We should never call whitelist_reply() unless we're bonded and therefore have a peer ID.
		NRF_LOG_WARNING("whitelist_reply(): No peer ID. Not sending whitelist.");
		return;
	}

	// What we have now is a single pm_peer_id_t. But what we need to pass to ble_advertising_whitelist_reply() is a list of ble_gap_addr_t. To get from one to the other, use pm_whitelist_set(), then pm_whitelist_get().
	peer_ids[0] = peer_id;
	err_code = pm_whitelist_set(peer_ids, 1);
	APP_ERROR_CHECK(err_code);

	ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
	ble_gap_irk_t whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
	uint32_t addr_cnt = 1;
	uint32_t irk_cnt = 1;

	err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt, whitelist_irks,  &irk_cnt);
	APP_ERROR_CHECK(err_code);

	// Because the NRF_LOG macros only support up to five varargs after the format string, we need to break this into two calls.
	NRF_LOG_RAW_INFO("pm_whitelist_get() returned address: ");
	NRF_LOG_RAW_INFO("%02X:%02X:%02X:", whitelist_addrs[0].addr[0], whitelist_addrs[0].addr[1], whitelist_addrs[0].addr[2]);
	NRF_LOG_RAW_INFO("%02X:%02X:%02X\n", whitelist_addrs[0].addr[3], whitelist_addrs[0].addr[4], whitelist_addrs[0].addr[5]);

	// From BLE_GAP_ADDR_TYPES in ble_gap.h:
	// #define BLE_GAP_ADDR_TYPE_PUBLIC                        0x00 /**< Public address. */
	// #define BLE_GAP_ADDR_TYPE_RANDOM_STATIC                 0x01 /**< Random static address. */
	// #define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE     0x02 /**< Random private resolvable address. */
	// #define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */
	NRF_LOG_INFO("pm_whitelist_get() returned address type: %d", whitelist_addrs[0].addr_type);

	// The IRK size is BLE_GAP_SEC_KEY_LEN = 16.
	NRF_LOG_RAW_INFO("pm_whitelist_get() returned IRK: ");
	NRF_LOG_RAW_INFO("%02X\n", whitelist_irks[0].irk);

	// Apply the whitelist.
	err_code = ble_advertising_whitelist_reply(&m_advertising, whitelist_addrs, addr_cnt, whitelist_irks, irk_cnt);
	APP_ERROR_CHECK(err_code);
}

This code does seem to have found the address for my bonded Android central:

D ble_periph Adv event: Whitelist requested
pm_whitelist_get() returned address: 46:1D:36:6D:1B:04
pm_whitelist_get() returned IRK: 2000FDD0
D ble_periph Adv event: Slow (whitelist)

The byte order of the address logged above is the reverse of what I see on the UI in the Android Bluetooth Settings app: 04:1B:6D:36:1D:46. I presume this is harmless - it's just the way it's being logged and not the way it's being stored and used in the whitelist?

I see this in the logcat on the Android app side:

com.android.bluetooth E/bt_btm: btm_ble_read_remote_features_complete: failed for handle: 0x0006, status 0x3e

And here's the logcat from the nRFConnect Android app, if I use that instead to make the second connection attempt.

12-31 14:30:48.146 28856-28856/no.nordicsemi.android.mcp D/BluetoothGatt: connect() - device: C7:56:60:F0:56:58, auto: false
12-31 14:30:48.146 28856-28856/no.nordicsemi.android.mcp D/BluetoothGatt: registerApp()
12-31 14:30:48.146 28856-28856/no.nordicsemi.android.mcp D/BluetoothGatt: registerApp() - UUID=2f63c9df-a8bd-4c58-bfdd-71cce668bc60
12-31 14:30:48.147 1552-2145/com.android.bluetooth I/bt_stack: [INFO:gatt_api.cc(1004)] GATT_Register
12-31 14:30:48.147 1552-2145/com.android.bluetooth I/bt_stack: [INFO:gatt_api.cc(1027)] allocated gatt_if=10
12-31 14:30:48.147 28856-29057/no.nordicsemi.android.mcp D/BluetoothGatt: onClientRegistered() - status=0 clientIf=10
12-31 14:30:48.148 1552-1603/com.android.bluetooth D/bt_btif_config: btif_get_address_type: Device [c7:56:60:f0:56:58] address type 1
12-31 14:30:48.148 1552-1603/com.android.bluetooth D/bt_btif_config: btif_get_device_type: Device [c7:56:60:f0:56:58] type 2
12-31 14:30:48.148 1552-2145/com.android.bluetooth I/bt_stack: [INFO:gatt_api.cc(1168)] GATT_Connectgatt_if=10 c7:56:60:f0:56:58
12-31 14:30:48.496 1552-2145/com.android.bluetooth E/bt_btm: btm_ble_read_remote_features_complete: failed for handle: 0x0001, status 0x3e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=6 connected=0 conn_id=6 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=7 connected=0 conn_id=7 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=8 connected=0 conn_id=8 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=9 connected=0 conn_id=9 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth W/bt_btif: bta_gattc_conn_cback() - cif=10 connected=0 conn_id=10 reason=0x003e
12-31 14:30:48.497 1552-2145/com.android.bluetooth I/bt_btm_sec: btm_sec_disconnected clearing pending flag handle:1 reason:62
12-31 14:30:48.498 28856-29057/no.nordicsemi.android.mcp D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=10 device=C7:56:60:F0:56:58
12-31 14:30:48.498 28856-29057/no.nordicsemi.android.mcp E/BluetoothLeBasicConn: Connection state changing error: 133

Here's a Wireshark/Sniffer capture that shows the CONNECT_REQ simply being ignored. See packet 947 or so.

bike-tracker-nRF52-whitelist-connection-req-ignored.pcapng

So, why can't the central connect? If I turn the whitelist off, it can connect immediately. With it on, it never connects.

[edit]

Here's the logging of the address and address type on the very first connection:

I ble_periph Connected.
connection from address: B0:77:9A:67:7C:4D
I ble_periph connection from address type: 2

And here's the logging on the whitelist reply:

D ble_periph Adv event: Whitelist requested
pm_whitelist_get() returned address: C6:00:20:D4:C8:00
I ble_periph pm_whitelist_get() returned address type: 90
pm_whitelist_get() returned IRK: 2000FDEC

The address type in the whitelist reply makes no sense - it should be in the range 0 - 3.

[edit 2]

But the address type on the second connection, once we're already bonded and are going to to the whitelist reply, is OK:

connection from address: A3:36:7D:6C:18:70
I ble_periph connection from address type: 2
Parents
  • Thanks Petter.

    Address type: How can I tell? Can I log this somehow? The central is a Pixel 2 running Android O (8.1.0).

    ble_app_hids_keyboard: Yes, I've tested that just now, and it's an improvement on what I had, but still isn't completely working. I found that using that code, the bonded central is able to connect OK on subsequent connections. But another, non-bonded central is also able to connect but not bond. This seems pretty insecure in that an attacker could simply connect a lot and DoS the device. It's be better if the peripheral just ignore the CONNECT_REQ packet, as it used to when this was not working at all. Is that possible?

    (Regarding the peer ID stuff I was doing, it could be that I got confused between what was required for directed advertising on BLE_ADV_EVT_PEER_ADDR_REQUEST and instead added this for the whitelist reply. I don't recall now.)

Reply
  • Thanks Petter.

    Address type: How can I tell? Can I log this somehow? The central is a Pixel 2 running Android O (8.1.0).

    ble_app_hids_keyboard: Yes, I've tested that just now, and it's an improvement on what I had, but still isn't completely working. I found that using that code, the bonded central is able to connect OK on subsequent connections. But another, non-bonded central is also able to connect but not bond. This seems pretty insecure in that an attacker could simply connect a lot and DoS the device. It's be better if the peripheral just ignore the CONNECT_REQ packet, as it used to when this was not working at all. Is that possible?

    (Regarding the peer ID stuff I was doing, it could be that I got confused between what was required for directed advertising on BLE_ADV_EVT_PEER_ADDR_REQUEST and instead added this for the whitelist reply. I don't recall now.)

Children
No Data
Related