| ... | @@ -91,14 +91,14 @@ The availability of Bluetooth APIs on most modern day smartphones makes Bluetoot |
... | @@ -91,14 +91,14 @@ The availability of Bluetooth APIs on most modern day smartphones makes Bluetoot |
|
|
Background information about Bluetooth:
|
|
Background information about Bluetooth:
|
|
|
|
|
|
|
|
- Bluetooth Low Energy
|
|
- Bluetooth Low Energy
|
|
|
- <https://punchthrough.com/how-gap-and-gatt-work/>
|
|
- <https://punchthrough.com/how-gap-and-gatt-work/>
|
|
|
- <https://www.oreilly.com/library/view/getting-started-with/9781491900550/ch04.html>
|
|
- <https://www.oreilly.com/library/view/getting-started-with/9781491900550/ch04.html>
|
|
|
- <https://github.com/weliem/blessed-android>
|
|
- <https://github.com/weliem/blessed-android>
|
|
|
- <https://software-dl.ti.com/lprf/simplelink_cc2640r2_sdk/1.35.00.33/exports/docs/ble5stack/ble_user_guide/html/ble-stack/l2cap.html#l2cap-connection-oriented-channel-coc-example>
|
|
- <https://software-dl.ti.com/lprf/simplelink_cc2640r2_sdk/1.35.00.33/exports/docs/ble5stack/ble_user_guide/html/ble-stack/l2cap.html#l2cap-connection-oriented-channel-coc-example>
|
|
|
- <https://code.briarproject.org/briar/public-mesh-testbed/-/tree/blessed-gatt>
|
|
- <https://code.briarproject.org/briar/public-mesh-testbed/-/tree/blessed-gatt>
|
|
|
- Bluetooth "classic", specifically RFCOMM
|
|
- Bluetooth "classic", specifically RFCOMM
|
|
|
- <https://developer.android.com/guide/topics/connectivity/bluetooth>
|
|
- <https://developer.android.com/guide/topics/connectivity/bluetooth>
|
|
|
- <https://code.briarproject.org/briar/public-mesh-testbed/-/tree/bt-classic>
|
|
- <https://code.briarproject.org/briar/public-mesh-testbed/-/tree/bt-classic>
|
|
|
|
|
|
|
|
### Bluetooth "classic" (BR/EDR)
|
|
### Bluetooth "classic" (BR/EDR)
|
|
|
|
|
|
| ... | @@ -190,24 +190,24 @@ Because we want to use the BLESSED library, we apply a similar patch to the unde |
... | @@ -190,24 +190,24 @@ Because we want to use the BLESSED library, we apply a similar patch to the unde |
|
|
On a mobile device, a public mesh Bluetooth service needs to be able to run uninterrupted in the background, and also need to be able to make Bluetooth advertisements and connections in the background. To do this, all of the Bluetooth Low Energy based branches of the testbed application request the following permissions:
|
|
On a mobile device, a public mesh Bluetooth service needs to be able to run uninterrupted in the background, and also need to be able to make Bluetooth advertisements and connections in the background. To do this, all of the Bluetooth Low Energy based branches of the testbed application request the following permissions:
|
|
|
|
|
|
|
|
<uses-permission
|
|
<uses-permission
|
|
|
android:name="android.permission.ACCESS_COARSE_LOCATION"
|
|
android:name="android.permission.ACCESS_COARSE_LOCATION"
|
|
|
android:maxSdkVersion="30" />
|
|
android:maxSdkVersion="30" />
|
|
|
<uses-permission
|
|
<uses-permission
|
|
|
android:name="android.permission.ACCESS_FINE_LOCATION"
|
|
android:name="android.permission.ACCESS_FINE_LOCATION"
|
|
|
android:maxSdkVersion="30" />
|
|
android:maxSdkVersion="30" />
|
|
|
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 and Nubia devices running API 32 -->
|
|
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 and Nubia devices running API 32 -->
|
|
|
<uses-permission
|
|
<uses-permission
|
|
|
android:name="android.permission.BLUETOOTH"
|
|
android:name="android.permission.BLUETOOTH"
|
|
|
android:maxSdkVersion="32" />
|
|
android:maxSdkVersion="32" />
|
|
|
<uses-permission
|
|
<uses-permission
|
|
|
android:name="android.permission.BLUETOOTH_ADMIN"
|
|
android:name="android.permission.BLUETOOTH_ADMIN"
|
|
|
android:maxSdkVersion="30" />
|
|
android:maxSdkVersion="30" />
|
|
|
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
|
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
|
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
|
<uses-permission
|
|
<uses-permission
|
|
|
android:name="android.permission.BLUETOOTH_SCAN"
|
|
android:name="android.permission.BLUETOOTH_SCAN"
|
|
|
android:usesPermissionFlags="neverForLocation"
|
|
android:usesPermissionFlags="neverForLocation"
|
|
|
tools:targetApi="31" />
|
|
tools:targetApi="31" />
|
|
|
|
|
|
|
|
Depending on the API level, various permissions must be granted by the user. On API level 31, the following permissions require user confirmation:
|
|
Depending on the API level, various permissions must be granted by the user. On API level 31, the following permissions require user confirmation:
|
|
|
|
|
|
| ... | @@ -255,45 +255,52 @@ Scanning for nearby peers is a key component of the Bluetooth Low Energy protoco |
... | @@ -255,45 +255,52 @@ Scanning for nearby peers is a key component of the Bluetooth Low Energy protoco |
|
|
#### Peer Connectivity
|
|
#### Peer Connectivity
|
|
|
|
|
|
|
|
As previously mentioned, Bluetooth Low Energy offers two different ways of actually connecting and sharing data between devices: GATT and L2CAP CoC. L2CAP CoC is much closer to traditional socket programming than the GATT protocol. This makes programming larger data transfers with L2CAP much easier, however API support for L2CAP on Android devices is worse compared to GATT, so our general thinking is to attempt to create links between devices using L2CAP, but fall back to using GATT in case the devices do not support L2CAP.
|
|
As previously mentioned, Bluetooth Low Energy offers two different ways of actually connecting and sharing data between devices: GATT and L2CAP CoC. L2CAP CoC is much closer to traditional socket programming than the GATT protocol. This makes programming larger data transfers with L2CAP much easier, however API support for L2CAP on Android devices is worse compared to GATT, so our general thinking is to attempt to create links between devices using L2CAP, but fall back to using GATT in case the devices do not support L2CAP.
|
|
|
|
|
|
|
|
##### GATT
|
|
##### GATT
|
|
|
|
|
|
|
|
Using BLESSED's `PeripheralManager` class, you can easily create and add characteristics:
|
|
Using BLESSED's `PeripheralManager` class, you can easily create services and characteristics:
|
|
|
|
|
|
|
|
BluetoothGattCharacteristic allocatorChar = new BluetoothGattCharacteristic(ALLOCATOR_UUID, PROPERTY_READ, PERMISSION_READ);
|
|
```Java
|
|
|
gattService.addCharacteristic(allocatorChar);
|
|
BluetoothGattService gattService = new BluetoothGattService(SERVICE_UUID, SERVICE_TYPE_PRIMARY);
|
|
|
peripheralManager.add(gattService);
|
|
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, PROPERTY_READ, PERMISSION_READ);
|
|
|
|
|
gattService.addCharacteristic(characteristic);
|
|
|
And start advertising the GATT service:
|
|
peripheralManager.add(gattService);
|
|
|
|
|
```
|
|
|
peripheralManager.startAdvertising(adSettings, adData, scanResponse);
|
|
|
|
|
|
|
And start advertising the GATT service by its UUID:
|
|
|
See this file for more information on how the `blessed-gatt` branch creates and advertises its GATT service:
|
|
|
|
|
|
|
```Java
|
|
|
<https://code.briarproject.org/briar/public-mesh-testbed/-/blob/blessed-gatt/app/src/main/java/org/briarproject/publicmesh/bt/BtServiceImpl.java#L261>
|
|
AdvertiseSettings adSettings = new AdvertiseSettings.Builder()
|
|
|
|
|
.setConnectable(true)
|
|
|
When a central device discovers a peripheral that's advertising the app's service UUID, it connects to the `BluetoothPeripheral` object by using the `centralManager.connectPeripheral()` method. See the following file for the full implementation of peer connections on the `blessed-gatt` branch:
|
|
.setTimeout(0)
|
|
|
|
|
.build();
|
|
|
<https://code.briarproject.org/briar/public-mesh-testbed/-/blob/blessed-gatt/app/src/main/java/org/briarproject/publicmesh/bt/BtServiceImpl.java#L320>
|
|
AdvertiseData adData = new AdvertiseData.Builder().addServiceUuid(SERVICE_UUID).build();
|
|
|
|
|
peripheralManager.startAdvertising(adSettings, adData, adData);
|
|
|
|
```
|
|
|
|
|
|
|
|
When a central device discovers a peripheral that's advertising the app's service UUID, it connects to the `BluetoothPeripheral` object by using the `centralManager.connectPeripheral()` method.
|
|
|
|
|
|
|
|
See the following file for the full implementation of advertising, discovery and peer connections on the `blessed-gatt` branch:
|
|
|
|
|
|
|
|
<https://code.briarproject.org/briar/public-mesh-testbed/-/blob/blessed-gatt/app/src/main/java/org/briarproject/publicmesh/bt/BtServiceImpl.java>
|
|
|
|
|
|
|
##### L2CAP CoC
|
|
##### L2CAP CoC
|
|
|
|
|
|
|
|
With L2CAP CoC, there is less of a conceptual divide between "central" and "peripheral" devices than there is with GATT. Instead of advertising a set of services consisting of characteristics, a peripheral using L2CAP CoC can just advertise a "PSM" value, which is similar to a port number, and open a Bluetooth server socket running on that PSM value. On our `blessed-gatt` branch, we advertise the PSM if the device supports L2CAP CoC:
|
|
With L2CAP CoC, there is less of a conceptual divide between "central" and "peripheral" devices than there is with GATT. Instead of advertising a set of services consisting of characteristics, a peripheral using L2CAP CoC can just advertise a "PSM" value, which is similar to a port number, and open a Bluetooth server socket running on that PSM value. On our `blessed-gatt` branch, we advertise the PSM if the device supports L2CAP CoC:
|
|
|
|
|
|
|
|
```Java
|
|
```Java
|
|
|
if (USE_L2CAP && SDK_INT >= 29 && serverSocket == null) openServerSocket();
|
|
|
|
|
AdvertiseSettings adSettings = new AdvertiseSettings.Builder()
|
|
|
|
|
.setConnectable(true)
|
|
|
|
|
.setTimeout(0)
|
|
|
|
|
.build();
|
|
|
|
|
AdvertiseData adData = new AdvertiseData.Builder().addServiceUuid(PARCEL_UUID).build();
|
|
AdvertiseData adData = new AdvertiseData.Builder().addServiceUuid(PARCEL_UUID).build();
|
|
|
AdvertiseData scanResponse;
|
|
AdvertiseData scanResponse;
|
|
|
if (USE_L2CAP && SDK_INT >= 29) {
|
|
if (USE_L2CAP && SDK_INT >= 29) {
|
|
|
byte[] serviceData = new byte[4];
|
|
byte[] serviceData = new byte[4];
|
|
|
writeUint32(psm, serviceData, 0);
|
|
writeUint32(psm, serviceData, 0);
|
|
|
scanResponse = new AdvertiseData.Builder()
|
|
scanResponse = new AdvertiseData.Builder()
|
|
|
.addServiceData(PARCEL_UUID, serviceData).build();
|
|
.addServiceData(PARCEL_UUID, serviceData)
|
|
|
|
.build();
|
|
|
|
} else {
|
|
|
|
scanResponse = adData;
|
|
|
}
|
|
}
|
|
|
|
peripheralManager.startAdvertising(adSettings, adData, scanResponse);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
Then, whenever we discover an L2CAP-compatible device, we can connect to it using a method like the `connectViaSocket()` method on the `blessed-gatt` branch:
|
|
Then, whenever we discover an L2CAP-compatible device, we can connect to it using a method like the `connectViaSocket()` method on the `blessed-gatt` branch:
|
| ... | @@ -302,14 +309,14 @@ Then, whenever we discover an L2CAP-compatible device, we can connect to it usin |
... | @@ -302,14 +309,14 @@ Then, whenever we discover an L2CAP-compatible device, we can connect to it usin |
|
|
|
|
|
|
|
#### Notes
|
|
#### Notes
|
|
|
|
|
|
|
|
- BLESSED doesn't provide a wrapper for the new advertising set API (added in API level 26), which supports Bluetooth 5 advertising features such as periodic advertising, extended advertising and coded PHY, so if we want to use those features we'll need to use the Android API directly, rather than going through BLESSED
|
|
- BLESSED doesn't provide a wrapper for the new advertising set API (added in API level 26), which supports Bluetooth 5 advertising features such as periodic advertising, extended advertising and coded PHY. If we want to use those features we'll need to use the Android API directly, rather than going through BLESSED.
|
|
|
- If we use any Bluetooth 5 advertising features then we also need to use the Android API directly for scanning (or submit a pull request upstream for BLESSED to allow legacy mode to be turned off for scanning)
|
|
- If we use any Bluetooth 5 advertising features then we also need to use the Android API directly for scanning (or submit a pull request upstream for BLESSED to allow legacy mode to be turned off for scanning).
|
|
|
- We can, however, use BLESSED to request coded PHY for GATT connections
|
|
- We can, however, use BLESSED to request coded PHY for GATT connections.
|
|
|
- The Moto G 4G never receives the result of starting advertising (no callback to `onAdvertisingStarted()` or `onAdvertiseFailure()`)
|
|
- The Moto G 4G never receives the result of starting advertising (no callback to `onAdvertisingStarted()` or `onAdvertiseFailure()`).
|
|
|
- The Moto G 4G and Huawei P8 Lite 2015 can discover the Samsung Galaxy J5 2016, but it can't discover them and they can't discover each other
|
|
- The Moto G 4G and Huawei P8 Lite 2015 can discover the Samsung Galaxy J5 2016, but it can't discover them and they can't discover each other.
|
|
|
- The P8 Lite can connect to the J5 via GATT and exchange pings and pongs
|
|
- The P8 Lite can connect to the J5 via GATT and exchange pings and pongs.
|
|
|
- The Moto G can't connect to the J5 via GATT: it receives a callback to `onConnectingPeripheral()`, never receives `onConnectedPeripheral()`, and eventually receives `onDisconnectedPeripheral()` with status `LMP_OR_LL_RESPONSE_TIMEOUT`. The J5 receives onCentralConnected() and onCentralDisconnected() as expected. The J5 can subsequently connect back to the Moto G, using the address it learned from the unsuccessful connection, and exchange pings and pongs
|
|
- The Moto G can't connect to the J5 via GATT: it receives a callback to `onConnectingPeripheral()`, never receives `onConnectedPeripheral()`, and eventually receives `onDisconnectedPeripheral()` with status `LMP_OR_LL_RESPONSE_TIMEOUT`. The J5 receives `onCentralConnected()` and `onCentralDisconnected()` as expected. The J5 can subsequently connect back to the Moto G, using the address it learned from the unsuccessful connection, and exchange pings and pongs.
|
|
|
- When the J5 receives a connection from the Moto G or P8 Lite, the J5 sees the same address that the Moto G/P8 Lite gets from its own BluetoothAdapter, ie the BT classic address
|
|
- When the J5 receives a connection from the Moto G or P8 Lite, the J5 sees the same address that the Moto G/P8 Lite gets from its own `BluetoothAdapter`, ie the BT classic address.
|
|
|
|
|
|
|
|
### Socket-Like Communication via GATT
|
|
### Socket-Like Communication via GATT
|
|
|
|
|
|
| ... | @@ -361,32 +368,23 @@ The full handshake as implemented in the `blessed-gatt-allocator-vuln` and `bles |
... | @@ -361,32 +368,23 @@ The full handshake as implemented in the `blessed-gatt-allocator-vuln` and `bles |
|
|
|
|
|
|
|
#### Notes
|
|
#### Notes
|
|
|
|
|
|
|
|
The allocator characteristic works as an active list of nearby peers, so higher level protocols could possibly utilize this as a way to further increase peer discovery and data propagation.
|
|
* The allocator characteristic works as an active list of nearby peers, so higher level protocols could possibly utilize this as a way to further increase peer discovery and data propagation.
|
|
|
|
|
* Because each peripheral has a limited number of read characteristics, protocols built on top of this strategy should prioritize quicker, more frequent connections rather than long lasting data transfers.
|
|
|
Because each peripheral has a limited number of read characteristics, protocols built on top of this strategy should prioritize quicker, more frequent connections rather than long lasting data transfers.
|
|
* The allocator system allows a socket-like abstraction to be made on top of regular GATT reads and writes.
|
|
|
|
|
|
|
|
The allocator system allows a socket-like abstraction to be made on top of regular GATT reads and writes.
|
|
|
|
|
This is useful because GATT has much greater support than L2CAP CoC among Android devices, especially older devices.
|
|
This is useful because GATT has much greater support than L2CAP CoC among Android devices, especially older devices.
|
|
|
The allocator characteristic system can be used in parallel with L2CAP CoC, by advertising the PSM of the peripheral's L2CAP server socket along with the UUID of the mesh service.
|
|
The allocator characteristic system can be used in parallel with L2CAP CoC, by advertising the PSM of the peripheral's L2CAP server socket along with the UUID of the mesh service.
|
|
|
This allows L2CAP CoC to be used between centrals and peripherals that support it, with the allocator characteristic system providing a fallback for older devices.
|
|
This allows L2CAP CoC to be used between centrals and peripherals that support it, with the allocator characteristic system providing a fallback for older devices.
|
|
|
|
|
* The GATT protocol allows a central to read from any read characteristic, not only the one that has been allocated to it.
|
|
|
The GATT protocol allows a central to read from any read characteristic, not only the one that has been allocated to it.
|
|
|
|
|
If the communication between a peripheral and a central needs to be confidential then higher-layer protocols must ensure that this remains the case even when the data sent from the peripheral to the central can easily be observed by other devices nearby.
|
|
If the communication between a peripheral and a central needs to be confidential then higher-layer protocols must ensure that this remains the case even when the data sent from the peripheral to the central can easily be observed by other devices nearby.
|
|
|
In practice this is unlikely to make a big difference to the design of higher-layer protocols, which must already be designed around the assumption that any data sent over a wireless medium can easily be received by unintended recipients.
|
|
In practice this is unlikely to make a big difference to the design of higher-layer protocols, which must already be designed around the assumption that any data sent over a wireless medium can easily be received by unintended recipients.
|
|
|
|
|
|
|
|
### BluetoothCommunicator
|
|
### BluetoothCommunicator
|
|
|
|
|
|
|
|
BluetoothCommunicator is a BLE library built upon the core Android `BluetoothGATT` objects similar to BLESSED. However, unlike BLESSED, BluetoothCommunicator is geared more towards async messaging, and not a general-use library. Because of the added flexibility working with BLESSED gives us, future development of BLE mesh networking tools will likely focus on our allocator characteristic framework. However it is useful to research the BluetoothCommunicator library because it gives us insight into how a higher-level messaging framework might be built upon the allocator characteristic system.
|
|
BluetoothCommunicator is a BLE library built upon the core Android `BluetoothGATT` objects similar to BLESSED. However, unlike BLESSED, BluetoothCommunicator is geared more towards async messaging, and not a general-use library.
|
|
|
|
|
|
|
|
#### Peer Advertisement
|
|
<https://github.com/niedev/BluetoothCommunicator>
|
|
|
|
|
|
|
|
TODO find code snippets from blechat impl
|
|
|
|
|
|
|
|
|
|
#### Peer Discovery
|
|
Because of the added flexibility working with BLESSED gives us, future development of BLE mesh networking tools will likely focus on our allocator characteristic framework. However it is useful to research the BluetoothCommunicator library because it gives us insight into how a higher-level messaging framework might be built upon the allocator characteristic system.
|
|
|
|
|
|
|
|
#### Peer Connectivity
|
|
|
|
|
|
|
|
|
|
#### Notes
|
|
|
|
|
|
|
|
|
|
While the library has methods built to enable auto-peering, our attempt to enable auto-peering with this framework proved unsuccessful.
|
|
While the library has methods built to enable auto-peering, our attempt to enable auto-peering with this framework proved unsuccessful.
|
|
|
|
|
|
| ... | @@ -467,7 +465,7 @@ When discovering services via NSD, one needs to resolve a discovered service to |
... | @@ -467,7 +465,7 @@ When discovering services via NSD, one needs to resolve a discovered service to |
|
|
It seems, however, that sometimes resolving neither succeeds nor fails, but instead we receive a service lost event. We don't get any updates on the resolving request afterwards, but we also cannot submit a new resolve request afterwards: they will still fail with a `FAILURE_ALREADY_ACTIVE` error. Even restarting service discovery entirely doesn't seem to help.
|
|
It seems, however, that sometimes resolving neither succeeds nor fails, but instead we receive a service lost event. We don't get any updates on the resolving request afterwards, but we also cannot submit a new resolve request afterwards: they will still fail with a `FAILURE_ALREADY_ACTIVE` error. Even restarting service discovery entirely doesn't seem to help.
|
|
|
|
|
|
|
|
The `lan-service-discovery-nsd-no-resolution` branch encodes the IP address in the NSD service name, allowing us to skip the buggy resolution step.
|
|
The `lan-service-discovery-nsd-no-resolution` branch encodes the IP address in the NSD service name, allowing us to skip the buggy resolution step.
|
|
|
|
|
|
|
|
This means we can't advertise attributes, unless we encode them in the service name along with the address, or fetch them separately via unicast. This (abandoned) library implements the latter approach to work around the empty attributes map issue mentioned above:
|
|
This means we can't advertise attributes, unless we encode them in the service name along with the address, or fetch them separately via unicast. This (abandoned) library implements the latter approach to work around the empty attributes map issue mentioned above:
|
|
|
<https://github.com/youviewtv/tinydnssd>
|
|
<https://github.com/youviewtv/tinydnssd>
|
|
|
|
|
|
| ... | @@ -479,7 +477,7 @@ Local Service Discovery (LSD) is the protocol used by BitTorrent clients to disc |
... | @@ -479,7 +477,7 @@ Local Service Discovery (LSD) is the protocol used by BitTorrent clients to disc |
|
|
It is a simple multicast-based protocol in which each peer periodically announces the infohashes of the torrents it is sharing.
|
|
It is a simple multicast-based protocol in which each peer periodically announces the infohashes of the torrents it is sharing.
|
|
|
|
|
|
|
|
<https://www.bittorrent.org/beps/bep_0014.html>
|
|
<https://www.bittorrent.org/beps/bep_0014.html>
|
|
|
|
|
|
|
|
#### Peer Advertisement
|
|
#### Peer Advertisement
|
|
|
|
|
|
|
|
A peer advertises the torrents it is sharing by periodically sending an advertisement packet to two predefined multicast addresses.
|
|
A peer advertises the torrents it is sharing by periodically sending an advertisement packet to two predefined multicast addresses.
|
| ... | |
... | |
| ... | | ... | |