BLE: Where does the "handle" come from? - bluetooth-lowenergy

I'm trying to learn how to use BLE on a Pi4.
I have installed hcitool and gatttool and have figured out how to use them. I have also set up a virtual device using LightBlue on a Mac.
pi#raspsky:~ $ sudo hcitool -i hci0 lescan
LE Scan ...
98:9E:63:39:8B:ED Blank
98:9E:63:39:8B:ED (unknown)
That "Blank" is the virtual device.
pi#raspsky:~ $ gatttool -b 98:9E:63:39:8B:ED -I
[98:9E:63:39:8B:ED][LE]> connect
Attempting to connect to 98:9E:63:39:8B:ED
Connection successful
[98:9E:63:39:8B:ED][LE]> primary
attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001800-0000-1000-8000-00805f9b34fb
<snip>
attr handle: 0x0028, end grp handle: 0x002b uuid: 00001111-0000-1000-8000-00805f9b34fb
[98:9E:63:39:8B:ED][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
<snip>
handle: 0x002b, uuid: 00002901-0000-1000-8000-00805f9b34fb
Now, I'd like to be able to read from the virtual device, but I have no idea which "handle" to use. I figured out by trial and error that I need to use 002b:
[98:9E:63:39:8B:ED][LE]> char-read-hnd 002b
Characteristic value/descriptor: 53 6f 6d 65 74 68 69 6e 67
That hex turns out to be the ascii string "Something" which is what I put in the virtual device.
But, where does that handle come from? It seems like I ought to be able to figure it out without having to use trial and error:
UPDATE:
In this example Using bash and gatttool to get readings from Xiaomi Mijia LYWSD03MMC Temperature Humidity sensor, the author shows how to use hcitool to get the mac address of a BLE Device. The article then goes on with an example:
bt=$(timeout 15 gatttool -b A4:C1:38:8C:77:CA --char-write-req --handle='0x0038' --value="0100" --listen)
But the author never explains where the handle (handle='0x0038') came from. I see how you can get a list of handles using gatttool, but the only way I can figure out what data goes with each handle is to try each one until I find the one I want. There must be an easier way.

Since you updated your question, I have another answer for you. But since your topic is not facing any programming issue, you better ask it again at another StackExchange.
the only way I can figure out what data goes with each handle is to try each one until I find the one I want. There must be an easier way.
I guess I have to disappoint you here.
While there are some predefined GATT profiles by Bluetooth SIG, most of the proprietary implementations do not expose any meaningful information about their characteristics but the mandatory UUIDs.
If you are lucky, you might be able to find a Characteristic User Description (Bluetooth Core Spec Vol. 3 Part G 3.3.3.2) or deduce some information from a Characteristic Presentation Format (Bluetooth Core Spec Vol. 3 Part G 3.3.3.5) characteristic descriptor; but since these are optional, I doubt that a proprietary implementation will provide these.
So for a proprietary implementation, you have to reverse engineer that information or try to find it online (often other people already reversed engineered common devices).

hcitool, and gatttool were deprecated by the BlueZ project in 2017. If you are following a tutorial that uses them, there is a chance that it might be out of date. The current BlueZ tool for generic scanning and exploration is bluetoothctl.
With BLE the UUID is the key to identifying the service/characteristic/descriptor that you are interested in.
The 16-bit UUID Numbers Document lists the adopted UUIDs. SIG-adopted attribute types (UUIDs) share all but 16 bits of a special 128-bit base UUID:0000xxxx-0000-1000-8000-00805F9B34FB. The document lists the 16-bit value that goes into that base.
As you have with the virtual device using LightBlue, custom UUIDs can be created. These need to be outside of the 128-bit base reserved for SIG-adopted values.
As SO is about software development, I'll point you at the BlueZ API documentation should you want to do any of this with code. There are also examples in the BlueZ source tree.

The thing you are looking for is generally speaking GATT/ATT itself.
Basically you query a device implementing a GATT server
The best (res)source and reference for anything related to Bluetooth® is IMHO the Bluetooth Core Specification in the version your devices support and you are developing for.
Attribute Protocol (ATT)
Bluetooth Core Specification 5.2 Vol. 3 Part F describes the ATTRIBUTE PROTOCOL (ATT) as follows:
This Part defines the Attribute protocol; a protocol for discovering, reading, and writing attributes on a peer device
The ATT is some sort of "low level" since it describe the actual protocol itself and its messages / Protocol Data Units (PDUs), but it's definitely worth a (periphere) read, especial chapters 3.1 Introduction and 3.2 Basic Concepts.
Generic Attribute Profile (GATT)
Bluetooth Core Specification 5.2 Vol. 3 Part G describes the GENERIC ATTRIBUTE PROFILE (GATT) as follows:
This Part defines the Generic Attribute Profile that describes a service framework using the Attribute protocol for discovering services, and for reading and writing characteristic values on a peer device.
You can think of GATT like a high-level API for issuing ATT queries and commands.
You should definitely give the complete chapter 2.6 GATT Profile Hierarchy a read and then head over to 4 GATT Feature Requirements, especially chapters 4.4 Primary Service Discovery, 4.6 Charateristic discovery and *4.7 Characteristic Descriptor Discovery - regarding your question
But, where does that handle come from?

Related

BLE 128b Service UUID

I have the following 128 bit service UUID:
0000FFE0-0000-1000-8000-00805F9B34FB
AFAIK, this is basically the base UUID of 00000000-0000-1000-8000-00805F9B34FB, thus, this can be simplified into the 16 bit UUID of "FFE0".
I can't find this 16 bit UUID in any of the predefined lists (https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf), though, which leads me to believe that the manufactures of this particular BLE module are being a bit naughty and incorrectly defining a 128-bit UUID?
Have I missed something ?
It does appear to be a custom service in the Bluetooth SIG reserved range.
If a custom service is created it should use a UUID outside of that range.

DPDK Crypto Device Scheduler "Capability Update Failed"

I am working on a DPDK project and experience issues that need you help.
The project needs to implement encryption/decryption through DPDK (multi-buffer library). To support all cipher and hash algorithms, I need create 4 type of virtual devices: crypto_null, crypto_aesni_mb, crypto_snow3g and crypto_zuc. I tried to create a crypto-scheduler to manage all 4 devices. When the devices attach to the scheduler, it failed. I can reproduce the exact same failure with the DPDK example program: l2fwd_crypto.
Here is the command I use to run l2fwd_crypto.
./l2fwd-crypto -l 0-1 -n 4 --vdev "crypto_aesni_mb0" --vdev "crypto_null" --vdev "crypto_zuc" --vdev "crypto_snow3g0" --vdev "crypto_scheduler,slave=crypto_null,slave=crypto_aesni_mb0,slave=crypto_snow3g0,slave=crypto_zuc" -- -p 0x3 --chain CIPHER_HASH --cipher_op ENCRYPT --cipher_algo aes-cbc --cipher_key 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f --auth_op GENERATE --auth_algo aes-xcbc-mac --auth_key 10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f
The error message is:
rte_cryptodev_scheduler_slave_attach() line 214: capabilities update failed
I am using DPDK 20.05 on CentOS 7.4
My question is:
Is this the correct way to handle all different crypto algorithm? I mean create 4 virtual devices.
Why the crypto scheduler failed?
Any suggestion/comments are really appreciated.
[EDIT-1: Based on comment conversation]
DPDK POLL mode Crypto Scheduler is intended to be running with either HW or SW of the same type. This is covered in dpdk document. Hence if one needs to Crypto scheduler to work, it has to initialized with all same type (either HW/SW).
Hence re-running the test with either all NULL, ZUC, SNoW, AES_MB will work
note: with respect to internally logic working, my personal opinion is the current logic in crypto-scheduler logic is correct. Because, in actual logic one will lookup dest-ip or src+dest IP in either ACL, LPM, or Exact Match to identify the SA or Crypto keys. this can offloaded to SW or HW depending upon work load or flow (mice or elephant) flow.

How do I tell if my BLE communication use asymmetric encryption, if encrypted at all? (BLE 5.x)

I want to know if my BLE 5 (low energy, not "typical"/core bluetooth) embedded system uses (preferably asymmetric) encryption, if encrypted at all.
I'm using this ble module that is communicating with an SOC. My SOC is capable of encryption but the FAE of the BLE module product couldn't come up with any useful information.
My program doesn't appear to have a bonding/pairing process, but I could be wrong since I did not take a closer look at the HAL layer program.
My question is, does BLE 5 require encryption?
If not, how do I find out if my connection is encrypted or not, using methods other than sniffers? For example are there any steps which must be gone through to facilitate encryption, in which case I should check if these steps were skipped or not? (If skipped then surely my communication is in plain texts).
ETA: The target BLE module is based on nrf52832, don't know what BLE stack/softdevice they are using. My soc is STM32WB55 series, using a rather comprehensive BLE stack that supports most functions of which name I couldn't recall for the moment.
BLE does not require encryption for a connection to be made.
At first, every BLE connection starts in Security Mode 1, Level 1 which does not use any encryption at all. Every message will be sent in cleartext. To increase the security two devices have to "pair". Security keys are exchange during the pairing process. There are multiple different pairing methods with different requirements. Have a look at this article for a starting point.
The pairing process is usually not started manually but automatically as soon as a device tries to access a secured characteristic. If you are using a phone to access such a characteristic you will be prompted with a pairing request popup. Based on your description I would assume that your connection is currently not encrypted.
To enable encryption on your SoC please have a look at the function aci_gatt_add_char. This document (direct download link) refers to this function on page 55 and shows that it takes Security_Permissions as an argument. The next page states the possible options as:
0x00: ATTR_PERMISSION_NONE
0x01: Need authentication to read
0x02: Need authorization to read
0x04: Link should be encrypted to read
0x08: Need authentication to write
0x10: Need authorization to write
0x20: Link should be encrypted for write

How to customize BlueZ?

I will be asking a very subjective question, but it is important as I am looking to recover from failure to effectively use BlueZ programatically.
Basically I envision an IoT edge device that runs on a miniature computer (Ex: Raspberry pi or Intel Compute Stick). The device would then run AlpineLinux OS and interact with Cloud.
Since it is IoT environment, it is needless to mention the importance of Bluetooth BLE over ISM band. Hence the central importance of being able to customize and work with BlueZ.
I am looking to do several things with BlueZ BLE including but not limited to
Advertising
Pairing
Characteristic
Broadcast
Secure transport of data etc...
Since I will be needing full control over data, for data-processing and interacting with cloud (Edge AI or Data-science on Cloud) I am looking at three ways of using BlueZ:
Make DBus API calls to BlueZ Methods.
Modify BlueZ codebase and make install a custom bin.
(So that callback handlers can be registered and wealth of other bluez
methods can be invoked)
Invoke BlueZ using command line utils like hcitool/bluetoothctl inside a program using system() calls.
No 1 is where I have failed. It is exorbitant amount of effort to construct and export DBus objects and then to invoke BlueZ methods. Plus there is no guarantee that you will be able to take care of all BLE issues.
No 2 looks very promising and I want to fully explore how feasible it is to modify the BlueZ code to my needs.
No 3 is the least desirable option, but I want to have it as a fallback option nevertheless.
Given my problem statement, what is the most viable strategy forward? I am asking this aloud so that I do not make more missteps and cost myself time and efforts.
Your best strategy is to start with the second way (which you already found promising) as this is a viable solution and many developers go about this method in order to create their BlueZ programs. Here is what I would do:-
Write all the functionality of the system in some sort of flowchart or state machine. This helps you visualise your whole system and what needs to be done to reach your end goal.
Try to perform all the above functionality manually using bluetoothctl and btmgmt. This includes advertising, pairing, etc. I recommend steering away from legacy commands such as hcitool and hciconfig as these have been deprecated and have a very different code structure.
When stumbling upon something that is not the default in bluetoothctl/btmgmt or you want to tweak the functionality, update the source to do so.
Finally, once you manually get the system to perform the functionality that you need (it doesn't have to be all, it can just be a subset of the functions), you can move to automating the whole process. This involves modifying the source for bluetoothctl/btmgmt commands so that instead of manual intervention, everything would be event-driven.
This is a bonus, but if you can create automated tests using python or some other scripting language, then this would ensure that your system is robust and that previous functionality doesn't break when adding new ones.
By the end of this process, you'll have a much better understanding of the internals of bluetoothctl/btmgmt and D-BUS APIs that you might be able to completely detach your code from the original bluetoothctl/btmgmt or create the program from scratch.
You probably already know this, but when modifying the tools, this is the starting point for the source code:-
bluetoothctl - client/main.c
btmgmt - tools/btmgmt.c
For more references on using bluetoothctl commands and btmgmt, please see the links below:-
BlueZ D-Bus C or C++ Sample
Bluetoothctl set passkey
https://stackoverflow.com/a/51876272/2215147
Bluez Programming
Linux command line howto accept pairing for bluetooth device without pin
https://stackoverflow.com/a/52982329/2215147
Bluetooth Low Energy in C - using Bluez to create a GATT server
I hope this helps.

How to programmatically determine which is the boot disk on Solaris/illumos?

On a test server there are two Samsung 960 Pro SSDs, exactly same maker, model and size. On both I've installed a fresh install of exactly the same OS, OmniOS r15026.
By pressing F8 at POST time, I can access the motherboard BOOT manager, and choose one of the two boot drives. Thus, I know which one the system booted from.
But how can one know programmatically, after boot, which is the boot disk?
It seems that is:
Not possible on Linux,
Not possible on FreeBsd
Possible on macOS.
Does Solaris/illumos offer some introspective hooks to determine which is the boot disk?
Is it possible to programmatically determine which is the boot disk on Solaris/illumos?
A command line tool would be fine too.
Edit 1: Thanks to #andrew-henle, I have come to know command eeprom.
As expected it is available on illumos, but on test server with OmniOS unfortunately it doesn't return much:
root#omnios:~# eeprom
keyboard-layout=US-English
ata-dma-enabled=1
atapi-cd-dma-enabled=1
ttyd-rts-dtr-off=false
ttyd-ignore-cd=true
ttyc-rts-dtr-off=false
ttyc-ignore-cd=true
ttyb-rts-dtr-off=false
ttyb-ignore-cd=true
ttya-rts-dtr-off=false
ttya-ignore-cd=true
ttyd-mode=9600,8,n,1,-
ttyc-mode=9600,8,n,1,-
ttyb-mode=9600,8,n,1,-
ttya-mode=9600,8,n,1,-
lba-access-ok=1
root#omnios:~# eeprom boot-device
boot-device: data not available.
Solution on OmniOS r15026
Thanks to #abarczyk I was able to determine the correct boot disk.
I had to use a slightly different syntax:
root#omnios:~# /usr/sbin/prtconf -v | ggrep -1 bootpath
value='unix'
name='bootpath' type=string items=1
value='/pci#38,0/pci1022,1453#1,1/pci144d,a801#0/blkdev#w0025385971B16535,0:b
With /usr/sbin/format, I was able to see entry corresponds to
16. c1t0025385971B16535d0 <Samsung-SSD 960 PRO 512GB-2B6QCXP7-476.94GB>
/pci#38,0/pci1022,1453#1,1/pci144d,a801#0/blkdev#w0025385971B16535,0
which is correct, as that is the disk I manually selected in BIOS.
Thank you very much to #abarczyk and #andrew-henle to consider this and offer instructive help.
The best way to find the device from which the systems is booted is to check prtconf -vp output:
# /usr/sbin/prtconf -vp | grep bootpath
bootpath: '/pci#0,600000/pci#0/scsi#1/disk#0,0:a'
On my Solaris 11.4 Beta system, there is a very useful command called devprop which helps answer your question:
$ devprop -s bootpath
/pci#0,0/pci1849,8c02#1f,2/disk#1,0:b
then you just have to look through the output of format to see what that translates to. On my system, that is
9. c2t1d0 <ATA-ST1000DM003-1CH1-CC47-931.51GB>
/pci#0,0/pci1849,8c02#1f,2/disk#1,0
Use the eeprom command.
Per the eeprom man page:
Description
eeprom displays or changes the values of parameters in the EEPROM.
It processes parameters in the order given. When processing a
parameter accompanied by a value, eeprom makes the indicated
alteration to the EEPROM; otherwise, it displays the parameter's
value. When given no parameter specifiers, eeprom displays the values
of all EEPROM parameters. A '−' (hyphen) flag specifies that
parameters and values are to be read from the standard input (one
parameter or parameter=value per line).
Only the super-user may alter the EEPROM contents.
eeprom verifies the EEPROM checksums and complains if they are
incorrect.
platform-name is the name of the platform implementation and can be
found using the –i option of uname(1).
SPARC
SPARC based systems implement firmware password protection with
eeprom, using the security-mode, security-password and
security-#badlogins properties.
x86
EEPROM storage is simulated using a file residing in the
platform-specific boot area. The /boot/solaris/bootenv.rc file
simulates EEPROM storage.
Because x86 based systems typically implement password protection in
the system BIOS, there is no support for password protection in the
eeprom program. While it is possible to set the security-mode,
security-password and security-#badlogins properties on x86 based
systems, these properties have no special meaning or behavior on x86
based systems.

Resources