Continuous issues with Bluetooth Pairing with Apple Devices, while Android works flawlessly

Hello, 

Since our Product Launch we have gotten feedback that pairing with some (but not all) Apple devices is a significant problem. Even through several attempted fixes we haven't gotten this to work. 

We use the BT FTMS Profile, implemented on top of the S313 ANT+ and BLE Softdevice. There, our pairing setup looks like this: 

1. Device connects, might read preferred connection parameters or not, which are: 

ble_gap_conn_params_t {
    min_conn_interval: 12, // 12 * 1.25ms = 15ms  (ios-compatible min)
    max_conn_interval: 24, // 24 * 1.25ms = 30ms  (common "safe" max for iOS)
    slave_latency: 0,      // no slave latency
    conn_sup_timeout: 500, // 500 * 10ms = 5s
};

2. (generally) discovers GATT services and such

3. One second after connection, our firmware sets the connection params itself (which are the same as above, and generally succeeds according to nrf-connect)

4. 800ms after that, our firmware triggers pairing. This generally shows a notification or confirmation window on devices, and tends to work as expected. 

For all devices I have available from multiple manufacturers and with multiple OSses (Linux, Windows, Android, iOS including an iPhone 14 and an iPad Air), this works just fine. However, we've heard from several people that there's behavior like this: 

1. Device gets selected in the fitness app or whereever, connects, pairing window pops up, connection works

2. Data gets received (no security on all the rx parts, so that makes sense), no control commands to e.g. set power get sent (which makes sense assuming the pairing didn't work, as writing to it requires just works security)

3. After 30-45ish seconds a new pairing prompt gets displayed. Same behavior loops after pressing pair again. 

We've tried quite a few different ways to fix that, but nothing we found until now works so far, so we're kind of at a loss as to what we're doing wrong. 

Some more info: 

- io_caps are set to BLE_GAP_IO_CAPS_NONE, and the MITM flag is 0. Also, min_key_size = 7 and max_key_size = 16. 

- Advertising interval is the Apple-recommended 20ms (32). Discoverability never was a problem, but can't hurt. 

- Bonding is only triggered after 1.8s if and only if the device is not yet bonded, it's not just slammed down indiscriminately. 

- LESC is not supported by our firmware (and it indicates this properly)

- Devices that don't work seem to be some macbooks, quite a few iPads, the iPhone 17 Pro, and the Apple TV. Pretty often people report that it works on some of their devices, but not on e.g. an iPad. 

- The only other problematic device we saw is a Lenovo tablet that (according to what I think) doesn't accept pairing without LESC due to some bluetooth stack regression, but nothing we have in our hands allows us to replicate the issue until now.

- Some devices failed silently in the past, never showing a pairing prompt while just refusing to write to the Control Point behind the JustWorks security

- The device has the DIS service implemented, which is explicitly required by Apple. I have no idea if its presence has any relation on this problem, but it can't hurt I think.

I'd really appreciate any ideas or tips as to how to proceed here. This seems to be a consistent problem across some versions of Apple Bluetooth stacks, but it's hard to see a pattern for now. Any help would really be much appreciated!

Parents
  • Hello,

    I don't think I have seen other reports similar to this. Have you been able to consistently reproduce this issue locally using these Apple devices? If you are able to do this you can also capture a sniffer trace which may help troubleshoot this further: https://www.nordicsemi.com/Products/Development-tools/nRF-Sniffer-for-Bluetooth-LE

    Data gets received (no security on all the rx parts, so that makes sense), no control commands to e.g. set power get sent (which makes sense assuming the pairing didn't work, as writing to it requires just works security

    The pairing prompt should appear as soon as the iOS app tries to access a characteristic that requires security. 

    One second after connection, our firmware sets the connection params itself (which are the same as above, and generally succeeds according to nrf-connect)

    What happens if the phone were to reject the connection parameters update request, will it terminate the connection?

    Best regards,

    Vidar

  • Hello Vidar, thanks for the quick answer!

    Firstly, I am completely unable to repro this locally. That's the major roadblock I've hit aswell, so there's no real way for me to figure out what exactly is going wrong. I think I'll just have to commit to buying Apple devices until I hit one that doesn't work or something like that :/

    The pairing prompt should appear as soon as the iOS app tries to access a characteristic that requires security. 

    It does. It appears, gets confirmed, and still the pairing is unsuccessful. I don't know why. Then, the pairing prompt reappears a few seconds later, generally 30-40 (but always the exact same time interval per device)

    What happens if the phone were to reject the connection parameters update request, will it terminate the connection?

    Nothing. If the phone rejects, the device accepts that fact, and proceeds with the active pairing request 800ms later, while keeping the GATT server available at all times since the start of the connection of course. 

  • Hi,

    Vidar is away, so I am taking a look instead. I can't think of anything in specific, but maybe you can share some of the kconfig options you have from the .config file in the build folder?

    I am in specific interested for instance in:

    CONFIG_BT_GATT_AUTO_SEC_REQ
    CONFIG_BT_AUTO_DATA_LEN_UPDATE
    CONFIG_BT_AUTO_PHY_UPDATE
    CONFIG_BT_GATT_AUTO_UPDATE_MTU
    CONFIG_BT_KEYS_OVERWRITE_OLDEST
    CONFIG_BT_ID_UNPAIR_MATCHING_BONDS
    CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE
    CONFIG_BT_ID_ALLOW_UNAUTH_OVERWRITE
    CONFIG_ASSERT

    If I were to wild guess anything I can see that the connection interval is rather short (20ms), while the slave latency is 0. I would prefer that you use some slave latency with this short interval, the reasoning behind that is a bit technical, but the problem is that if the application needs to perform any flash erase operations to store bonding data to flash, then it will need to reserve about 100ms for this to complete. However at the same time the softdevice need to ensure that it can handle any LL procedures within a connection interval * (6 + slave latency), so I can see that it will have difficult to schedule this to occur with the connection parameters settings you have chosen unless you enable to some slave latency.

    Kenneth

  • Hi Kenneth, thanks for the answer!

    We adjusted the connection parameters because apparently you need the very specific Apple-recommended ones if you want to not be kicked out of the connection with some apple devices (apparently this worked for some people, not for us tho). They should now fit the Apple Recommendations perfectly, according to their design gudelines. I added in a slave latency of 10, which should be ample time to do anything else in the background like flash writes without worrying about a timeout now I hope (Side note: The reason I don't think slave latency 0 is a problem is because in our setup, flash writes (and potential erases) are queued and executed later at a way lower priority than the connection task or the softdevice, and can be preempted by the higher priority stuff) 

    I unfortunately can't share kconfig options as we don't use the nRF Connect SDK but the Softdevice directly. I can answer what those are according to our implementation though, as good as possible: 

    FIrstly, our bonder implementation does override the oldest key on new pair. 

    CONFIG_BT_GATT_AUTO_SEC_REQ-equivalent is implemented, although there's no secured notifications / indications, so not super necessary. 

    CONFIG_BT_AUTO_PHY_UPDATE-equivalent is not implemented, so the peer manually needs to set the phy.

     Our max MTU is 256, but CONFIG_BT_GATT_AUTO_UPDATE_MTU-equivalent is not on. We don't actively ask for a data length extension. 

    CONFIG_BT_ID_UNPAIR_MATCHING_BONDS equivalent is implemented. If a device with a matching ID connects, it replaces that old bonds ID, to prevent limitations (effectively this: CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE, and not this: CONFIG_BT_ID_ALLOW_UNAUTH_OVERWRITE if I understand these correctly)

    CONFIG_ASSERT is not really relevant considering the firmware is written in Rust and uses panic-probe as well as pretty deep trace logging, so any errors, interactions and crashes should be apparent. 

    Sorry for being a more atypical case here. I hope this helps you understand the firmware behavior a bit better. I'll also let you know if the higher slave latency did work once we get feedback on that. 

    Best regards,

    Yannik

  • Hi,

    Yandrik said:
    CONFIG_BT_GATT_AUTO_SEC_REQ-equivalent is implemented, although there's no secured notifications / indications, so not super necessary. 

    I suspect this may be the culprit, I have seen in the past that if both peers try to trigger the same LL procedures at the same time, then some peers may not "like" this, and miss to respond to the LL procedure if self also have initiated it. This may also explain why the pairing prompt appear again after 30-40seconds, since I do believe the timeout for any LL procedure that is not responded is 40 seconds. In general as a peripheral device I recommend to disable this type of functionality, since any central device will automatically do this if required by any characteristic or description value. Also, Apple is not overenthusiastic about triggering bonding from a peripheral device as you can find indirectly in chapter 11.10 Pairing.

    Kenneth

  • Hi Kenneth, 

    unfortunately I'm pretty sure that isn't it. I have an Apple device here that doesn't work without (our equivalent of) this, but does work with it, and we've heard the issues before we implemented this in an attempt to maybe fix this, and didn't hear of any devices that worked without it but not with. Really sorry that I can't give you anything further in data, but do you maybe have any other ideas of what it could be? Any other ideas would really be much appreciated! 

    Best regards,

    Yannik

  • I unfortunately don't think we are able to get further without more details. In specific an on-air BLE sniffer log so we can check the difference between working and failing would be the absolute best in this case.

    Kenneth

Reply Children
No Data
Related