Taksh 59cd29ee25 fix(ble): make the GATT broadcast subscription idempotent
Writing the CCCD is the one GATT operation a peer can repeat freely on an
open connection: no authentication, no Noise session, no announcement, and
the Bluetooth spec puts no limit on how often a client may rewrite the
descriptor. onDescriptorWriteRequest attached two non-idempotent effects
to it.

Each ENABLE_NOTIFICATION write appended to subscribedDevices with no
contains() check, so N writes put N entries in the list one address owns.
broadcastSinglePacketInternal iterates that list and notifies per entry,
so every broadcast the mesh produces is then transmitted to that address N
times.

Each write also scheduled onDeviceConnected, which calls
sendBroadcastAnnounce(). That is unthrottled and floods at maxTtl, so a
peer could drive a mesh-wide ANNOUNCE at whatever rate it wrote the
descriptor.

Subscribe by address and return whether the device was newly subscribed,
run the peer-connect side effects only on that transition, and honour
DISABLE_NOTIFICATION_VALUE instead of keeping a peer on the broadcast feed
until it disconnects. Removal now matches on address like the connection
cleanup paths, so an unsubscribe cannot miss because the framework handed
us a different BluetoothDevice instance for the same address.

Refs #901
2026-08-24 20:16:15 +05:30
..
2025-09-14 03:32:10 +02:00
2026-07-28 20:58:17 +02:00