Summary
I'm running into an issue where in certain cases peer manager reports the presence of peers, but when those peers are added to a whitelist I get an NRF_ERROR_NOT_FOUND return code.
Versions
- MCU: nRF52832, on custom hardware
- SDK: 14.2.0
- Softdevice: S132 5.0.0
- Central: iPhone X, running iOS 12.3.1
Details
My application is a BLE peripheral that, when bonded to a central, does not allow further connections until that bond is deleted. As part of this, the device imposes a single-device whitelist consisting of just the bonded peer.
This works well in most common cases, but I'm finding some issues when exploring corner cases. Specifically, the peer manager seems to get in an inconsistent state when the bond is cleared only on my peripheral.
In summary, I can enter the state I describe using the following steps:
- Perform a successful bond between my central and a peripheral
- Disconnect the devices
- Clear the bond information on my peripheral
- Attempt to bond between the devices again, but don't accept the pairing request
After several failed attempts to secure the connection, the peripheral gives up, disconnects, and returns to advertising. As part of this, we attempt to compute and install a whitelist using code below:
static void peer_list_get(pm_peer_id_t * p_peers, uint32_t * p_size) { pm_peer_id_t peer_id; uint32_t peers_to_copy; peers_to_copy = (*p_size < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) ? *p_size : BLE_GAP_WHITELIST_ADDR_MAX_COUNT; peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID); *p_size = 0; while ((peer_id != PM_PEER_ID_INVALID) && (peers_to_copy--)) { p_peers[(*p_size)++] = peer_id; peer_id = pm_next_peer_id_get(peer_id); } } static void advertising_start(void) { uint32_t err_code; memset(m_whitelist_peers, PM_PEER_ID_INVALID, sizeof(m_whitelist_peers)); m_whitelist_peer_cnt = 1; peer_list_get(m_whitelist_peers, &m_whitelist_peer_cnt); err_code = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt); APP_ERROR_CHECK(err_code); // Setup the device identies list. // Some SoftDevices do not support this feature. err_code = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt); if (err_code != NRF_ERROR_NOT_SUPPORTED) { APP_ERROR_CHECK(err_code); } if (m_whitelist_peer_cnt > 0) { NRF_LOG_INFO("Advertising with whitelist"); } else { NRF_LOG_INFO("Advertising WITHOUT whitelist"); } APP_ERROR_CHECK(ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST)); }
At this point, peer_list_get() finds a single peer ID. However, pm_whitelist_set() rejects that peer with NRF_ERROR_NOT_FOUND.
Before the failed bonding occurs, there are no stored peers. If the central does not have a previous bond in place, the bonding still fails in the same way, but peer_list_get() returns zero peers as expected, causing the device to advertise without its whitelist.
Could this be corruption within the peer manager? My naive expectation is that after any failed bonding attempt the peer manager will not retain any information. Is there a valid state a peer can be in which does not allow it to be whitelisted? I'm digging through the peer manager code to try to answer these questions myself, but am wondering if anyone has the knowledge to tell me off the top of their heads.