-
-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow only certain bonded client to connect to NimBLEServer. Whitelist in advertising does not work for already bonded peers #651
Comments
This should now be resolved in the master branch, use the new |
@h2zero Thanks for the hint that the new I pair the ESP32 as a HID to a client, let's say a Windows machine. My server callback But even if it fired, what should I do in the callback? My problem is, that if a client connects for the first time, it is automatically added to the list of bonded peers. And whenever I start advertising again (with a whitelist), the whitelist is not used if an already bonded client connects. The whitelist only works for not already bonded clients. How does the new callback help here? |
The use case for this callback is when bonding with devices that use a random resolvable address and you want to add the id address to the whitelist. The onAuthenticationComplete callback did not provide the correct identity address so adding it to the whitelist there wouldn't have the desired effect. To answer your question though, it doesn't help your case please ignore my previous comment as I thought this was a different issue and didn't read it again. Have you tried clearing the whitelist and then adding the device you want? Alternatively you could try using directed advertising. |
Directed advertising sounds good. I tried this: BTW, clearing the whitelist of course would work, but this is not want I need. I need two clients bonded at the same time. I need to switch the connection between these two bonded clients at runtime. |
What I meant was you could just change the whitelist before advertising to have one or the other device in it instead of both. Directed advertising sadly does not have an API but you can use custom data like so:
|
Thanks for the snippet. I tried it, with the following result:
I think the Unable to advertise - Duration too long should not be there. At least the already bonded client does not reconnect. |
I think the duration is limited to 2 seconds for directed advertising, so you would have to restart it every time it ends with that duration. |
Got it working. But not with your snippet. I think it cannot work.
Why it is not working: when calling In In So for directed advertising to work, you must provide the peer address when calling
So thanks for your support, for me this is now working. I tested it with public and random addresses. |
Glad you got it working, I completely forgot about that parameter being added to advertising start call 👍 |
Hey all - I was trying to get the directed advertising method outlined by @KlausMu to work with an Android phone but it doesn't seem to be accepting the direct advertising request. Does this have something to do with RPA from Android? The Bond being stored in Nimble is just the regular device address so I tried to direct the advertisement with that address, but no luck.. Upon initial bonding, I saw 2 addresses logged (the other looks to be random). I did try to set that random address like this:
Android DID respond with that, but it just deleted the bond, saying can't communicate with the device.. |
The directed address should be the static id address of the device, which is what is stored when bonded. |
If you are not sure which is the static id address, you can use
or
(assuming that you have only one device bonded and connected). Then this should work
But I also struggled with direct advertisement to devices with random addresses.
I believe directed advertising worked even if the phone used RPA. Since phones are not my use case, but only media devices which are not using RPA, I don't have a lot of experience with devices using RPA. |
OK I did a few more tests with different devices and can see a pattern.. If the static address in your check above MATCHES the ID address An Android TV device with no RPA (Id address == address), works just fine with direct advertising. An Android phone with RPA (Id address != address), is causing issues. Switching the directed address to I looked into some other Bluetooth API's that also support direct advertising and saw Zephyr - they have 2 different directed advertising modes: Zephyr. Does that suggest there's some else lower in stack that needs to support devices that use RPA? |
It would t make sense to direct advertising to an RPA because it could change at any time, most phones change their address every 15 minutes. I think this may be resolved in the master branch which provides a callback when the identity address is received. |
Another detail: it seems only 2 bonds can be saved in the NVS (I'm using an ESP32). If I bond the third peer, one of the older two is deleted. I saw a lot uses of "BLE_STORE_MAX_BONDS" in the code, but I cannot find where it is defined or where it can be changed. |
@rac146 which version of NimBLE are you using? Currently for me directed advertising only works with master branch, not with 1.4.2 ... |
I've been using master branch.. |
NimBLE-Arduino/src/nimconfig.h Line 120 in f68bb5f
If you're using the master branch you should obtain the ID address in this new callback: NimBLE-Arduino/src/NimBLEServer.h Line 207 in f68bb5f
|
@h2zero thanks for pointing me to |
@rac146 Do you think you could repeat the test with version 1.4.2, just to be sure that direct advertising is really not working in the latest official release? Your code should almost stay the same. Only the callbacks for onConnect and onDisconnect changed. If I understand everything correctly, the situation is:
✓ working Unfortunately I cannot switch in my published project to the master branch, as long as there are still breaking changes. I ran into at least one between March and October. That's totally fine for a master branch, but I cannot use this in a published project which could break when the NimBLE master changed. |
So apologies here - I've been running the esp-nimble-cpp branch, as I'm building an ESP-IDF project. I know the branches are similar, but might not give you the answer you're looking for in regards to the NimBLE-Arduino branch. Here's the table as it stands, we can fill in as we test.. I'll update this with my esp-nimble-cpp 1.4.1 findings
|
🗙from my posting above means NO. So with NimBLE-Arduino, only public addresses on master works. The three other combinations didn't work, at least in my tests. |
I would like to reopen this issue, because direct advertisement only works in 2.0.0, not in 1.4.2 |
Just dropping by to verify that directed advertising is not working with 1.4.2. |
Just tested with iOS 17.6.1 and following code for directed advertising after bonding a device:
The result of this is, that my phone cannot even see my BLE server, let alone connect to it. I verified that the address used 60:7e:c9:7b:65:10 is indeed the BLE MAC Address of my iPhone. Used master, commit: c388672 Currently at a loss as to what I should change/fix in my code. Same code also does not work in 1.4.2 either. If anyone has any suggestion, I'll be happy to test/try them out. |
I have a suspicion this is the cause of some trouble, try changing |
@h2zero will try this asap and get back to you! |
@h2zero tried with BLE_ADDR_RANDOM. Still invisible to my phones. Will try deleting everything and rebonding. |
Can you provide the specific address? |
@h2zero I tried following:
What do u mean by specific address? Like |
No change. Also my config is like this:
|
I also repeated the test, with ESP32-S3, with this setup and result from yesterday: NimBLE-Arduino 2.0.0:
Windows (only has public address): does not work, neither with BLE_ADDR_PUBLIC nor with BLE_ADDR_RANDOM Android (which provides both public and private address)_
So test nr. 4 works, and test nr 6 not, although the data provided was the same. I really have a headache now ... Then I deleted all bonds and repeated steps 1 to 6. This time 4 failed. I don't understand what is going on :-) |
I'll see what I can find later this week, hopefully there is something easy to fix. |
I believe I have found the cause, and it is not an issue with this library. Basically it comes down to lack of support for directed advertising by some device (all Apple devices for sure). Take a read of this: https://developer.apple.com/accessories/Accessory-Design-Guidelines.pdf specifically page 236. |
Interesting. At least this gives an explanation for iOS. But why does direct advertisement from ESP32 to Windows work with 2.0.0 (and is indeed really reliable) and not with 1.4.2? Why does it not work at all from ESP32-S3 to Windows (not with 2.0.0 and not with 1.4.2)? And why does it sometimes work with Android? It's a mystery ... |
Still investigating, using this for testing:
If you would like to use this for your own testing please do and report back your findings. Don't bother trying against apple devices though 😄. I have verified with a sniffer that this does indeed advertise directed to the address provided on an esp32 dev board using release v1.4.2. |
Hm, ok so assuming iOS doesn't support this and whitelisting is broken in ESP32 completely plus switching on / off encrypted attributes on the fly also has issues I see no way to provide truly secure communications between ESP and all kinds of smartphones. So I am guessing time to switch ECU on my side. But still thanks a lot for all your efforts @h2zero and @KlausMu ! |
@sanastasiou Yes, the esp32 is not an option for your purposes and I would suggest a c3 or s3 variant. |
@h2zero thanks, is whitelisting supposed to be working in S3/C3 ? |
Yes @sanastasiou, they have controller based privacy and can manage the RPA's correctly. |
Another interesting find: https://devzone.nordicsemi.com/f/nordic-q-a/42111/android-and-directed-advertising |
Just rewrote the code and tested with C3 device. Works with iOS perfectly. Does not work with Android. Android does not see the device after the bonded address is added to the whitelist. Without whitelist everything works. With active whitelist nothing works for android. As usual used master branch of the library plus latest espressiff/arduino versions. Can provide logs if you're interested. |
Hm, after doing a reset on the ECU it works with both devices. Investigating further. |
So found the Android issue.. During bonding a check is done to see if the device has bonded already in the authentication callback. This code which works in 1.4.2 now fails:
This is printed:
Although the bonding itself succeeds. After a reset the whitelist is populated with the bonded addresses and everything works fine. It just doesn't work exactly after bonding.. but I can work around this. In any case, it's inconsistent behavior that peer size is 1 but |
Can you share more code details? |
Sure. So in the server callbacks:
When this is true and we are bonding for the first time there is no way to actually check if the device has bonded outside of this function. This used to work with the code above ( peer[0].isBonded ) with 1.4.2 but it now no longer works because for whatever reason size == 1 but peer[0] does not exist. Also disconnecting at this line: What I now do is, blindly accepting that a device has bonded when the authentication callback is called without looking at bonded devices / peer info at all. Tested that and it works fine. I also have a question. When I bond with my Android phone and then disconnect I can see during scan the device and I can reconnect ( ✔️ ). If I scan however with my unbonded iOS phone I still can see the device ( ❌ ) but I cannot connect to it ( ✔️ ). I would have thought that when whitelisting for scan response and connect are both true, the device would be invisible to non whitelisted peers. Is that not the case? |
So, what appears to happen is that callback is called before the bonded state is set for the peer in the stack, all good though, just check for authentication and or encryption. Whitelist does not prevent other devices from reporting them as seen, only prevents any connection attempt, which scan response is a pseudo connection, so it cannot get the data in the scan response and cannot connect. All devices can see your advertisements, BLE wouldn't work otherwise, but you can control the sensitive data, though not encrypted in the scan response. |
I am not sure if this code snippet can reveal the problem. My test case was always
With your code snippet no available device at all shows up in Windows when trying to pair, so I cannot even bond the device. As said earlier, Android and iOS are not really my use case, but of course I can contribute test results. What I am more afraid of:
If there is anything I can do to provide more test results, please let me know. Currently I don't know what to do. |
Just adding my 2 cents here for master branch. Although whitelisting works with C3 with master I have observed following behavior.
I could reproduce the latter in master branch 100%. I switched back to 1.4.2 where the above scenario works perfectly without any issues. Imo master branch needs some work. |
There are no changes in the master branch that would affect this as far as I can see. |
Well I could reproduce it 100% tried several times. The exact same steps work flawlessly in 1.4.2. Also I am pretty sure something change from 1.4.2 to master regarding NV storage of bonds. Having bonded devices stored into NV from master and going back to 1.4.2 results 100% reproducible exception during loading of bonds. |
Could you please try with the release/1.5 branch? I wonder if this is a core issue. |
@h2zero sure, the bonds thing or the other issue as well? The latter would take some time. |
Let's start with the bonds issue as that seems to be what changed with the master branch |
In my tests, both directions did not work: going to master (silent failure) and going back to 1.4.2 (crash). please see this issue |
Hi, first of all thanks a lot for this library! So much better than the bluedroid based library. Solved a lot of issues.
I want an ESP32 to act as a server, to be precise as an HID bluetooth keyboard.
I need to connect to different clients (in my case a FireTV and an AppleTV) and to switch the connection to them at runtime. Only one should be connected at the same time.
I am able to pair and bond both of them. One after the other. In the list of bonded peers I have two peers afterwards.
Remark: It is possible to connect both of them at the same time, if advertising is not stopped after the first connect. But it does not make sense because both devices would receive the same keyboard keys. I cannot force certain keys to be send to a certain peer.
So to achieve switching between the two peers, I tried to:
NimBLEDevice::getServer()->disconnect(...)
// the currently connected peeradvertising->setScanFilter(true, true);
The whitelist filter works in principle (bonding is only possible based on the whitelist). But if a client is already bonded, it can reconnect no matter if there is a whitelist set in advertising or not.
So how can I force only a certain bonded client to connect to the NimBLEServer?
I tried to pair the HID without bonding,
NimBLEDevice::setSecurityAuth(false, false, false);
, but when doing so, reconnects completely fail. It seems that keyboards always need to be bonded, not only to be paired.The text was updated successfully, but these errors were encountered: