Archive for the ‘Uncategorized’ Category.

LE Audio support in PipeWire

Since version 0.3.59, PipeWire supports LE Audio’s Basic Audio Profile (BAP) for Connected Isochronous Streams (CIS) with the Low Complexity Communication Codec (LC3), see https://www.linkedin.com/posts/collabora_add-bluetooth-le-audio-support-1360-activity-6978014601649037312-7W6d/.

Thanks to the modular architecture of PipeWire, it is ready for future codecs.
It supports bi-directional audio and can act as a Central or Peripheral device. In the former case, it allows the end-user to select a new audio profile, while in the latter, it automatically connects Bluetooth audio streams to the local audio input and output. This paves the way for Auracast support in BlueZ and PipeWire.

If you are interested in trying this, the LC3 codec from https://github.com/google/liblc3.git must be installed. The PipeWire meson build must be configured with the option `-Dbluez5-codec-lc3=enabled`.

LE Audio Support

From release 5.66, the initial support for BAP (Basic Audio Profile) which is an essential part of LE Audio responsible for stream control is added.

The plugin is considered experimental and depends on ISO socket in order to work so the following setting needs to be changed in order to enable it:

# Enables D-Bus experimental interfaces
# Possible values: true or false
Experimental = true

# Enables kernel experimental features, alternatively a list of UUIDs
# can be given.
# a6695ace-ee7f-4fb9-881a-5fac66c629af (BlueZ Experimental Offload Codecs)
# 6fbaf188-05e0-496a-9885-d6ddfdb4e03e (BlueZ Experimental ISO socket)
# Defaults to false.
KernelExperimental = 6fbaf188-05e0-496a-9885-d6ddfdb4e03e

While proper support to the likes of PulseAudio and Pipewire are still in progress it is possible to test using bluetoothctl with the following commands:

[Server/Peripheral]
[bluetooth]# power on
[bluetooth]# advertise on
[bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep0] Auto Accept (yes/no): y
[/local/endpoint/ep0] CIG (auto/value): a
[/local/endpoint/ep0] CIS (auto/value): a
Capabilities:
03 01 ff 00 02 02 03 02 03 03 05 04 1e 00 f0 00 ................
Endpoint /local/endpoint/ep0 registered
[bluetooth]# endpoint.register 00002bcb-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep1] Auto Accept (yes/no): y
[/local/endpoint/ep1] CIG (auto/value): a
[/local/endpoint/ep1] CIS (auto/value): a
Capabilities:
03 01 ff 00 02 02 03 02 03 03 05 04 1e 00 f0 00 ................
Endpoint /local/endpoint/ep1 registered

[Client/Central]
[bluetooth]# power on
[bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep0] Auto Accept (yes/no): y
[/local/endpoint/ep0] CIG (auto/value): a
[/local/endpoint/ep0] CIS (auto/value): a
Capabilities:
03 01 ff 00 02 02 03 02 03 03 05 04 1e 00 f0 00 ................
Endpoint /local/endpoint/ep0 registered
[bluetooth]# endpoint.register 00002bcb-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep1] Auto Accept (yes/no): y
[/local/endpoint/ep1] CIG (auto/value): a
[/local/endpoint/ep1] CIS (auto/value): a
Capabilities:
03 01 ff 00 02 02 03 02 03 03 05 04 1e 00 f0 00 ................
Endpoint /local/endpoint/ep1 registered
[bluetooth]# scan on
[bluetooth]# scan off
[bluetooth]# connect
[NEW] Transport /org/bluez/hci0/dev_00_AA_01_01_00_02/pac_source0/fd0
Endpoint: SetConfiguration
Transport /org/bluez/hci0/dev_00_AA_01_01_00_02/pac_source0/fd0
Device: /org/bluez/hci0/dev_00_AA_01_01_00_02
Auto Accepting...
[NEW] Transport /org/bluez/hci0/dev_00_AA_01_01_00_02/pac_sink0/fd1
Endpoint: SetConfiguration
Transport /org/bluez/hci0/dev_00_AA_01_01_00_02/pac_sink0/fd1
Device: /org/bluez/hci0/dev_00_AA_01_01_00_02
Auto Accepting...
[bluetooth]# transport.acquire /org/bluez/hci0/dev_00_AA_01_01_00_02/pac_sink0/fd1

BlueZ security bugs

BlueZ security bugs page is added to share how BlueZ handles the security bugs, process details, contact information, and more.

New IRC Channel for BlueZ

BlueZ IRC channel is moved to OFTC.

  • #bluez

Slack workspace

To improve the communication with our community we have create a Slack workspace, please join us using the following link.

Bluetooth 4.2 features going to the 3.19 kernel release

The Bluetooth Core Specification 4.2 was released December 2nd and it brings with itself several new features for Bluetooth Low Energy. Perhaps the most interesting one (and also the biggest) of these has been merged to the Bluetooth subsystem and submitted for inclusion in the 3.19 kernel release. The feature is called Low Energy Secure Connections (LE SC).

Security Implications

Bluetooth LE pairing has had known security vulnerabilities ever since its introduction to the Bluetooth specification. LE SC upgrades the Security Manager Protocol (SMP, used for LE pairing) to take advantage of the same Elliptic curve Diffie–Hellman (ECDH) key agreement protocol that classic BR/EDR Bluetooth uses. This essentially brings LE pairing to the same level of security as BR/EDR pairing.

User-visible improvements

Another improvement that LE SC brings is what’s called cross-transport key derivation. What this means is that when two dual-mode (supporting LE + BR/EDR) devices pair with each other, they only need to pair over either LE or BR/EDR to get the encryption keys for both transports in one go. When pairing over LE, as a last step of the SMP pairing procedure the BR/EDR Link Key (LK) gets derived from the LE Long Term Key (LTK) by both devices. For BR/EDR on the other hand, a subset of SMP can now be run over a fixed L2CAP channel resulting in deriving an LTK from the LK at the end of the BR/EDR pairing procedure.

Hardware & Software Requirements

BlueZ 5.26 is the first user space version that supports LE SC and will automatically take advantage of it for kernels also indicating support for it (i.e. >= 3.19 in practice). Most LE SC features are available for any Bluetooth adapter capable of LE (i.e. supporting Bluetooth 4.0 or later), however cross-transport key derivation in the BR/EDR -> LE direction requires that the BR/EDR link is encrypted with AES (compared to E0 for Bluetooth 4.0 and before), i.e. supports BR/EDR Secure Connections. Since BR/EDR SC was introduced with Bluetooth 4.1 this means that full LE SC is only available when the local and remote Bluetooth HW support at least Bluetooth 4.1.

Android related work happening in BlueZ

To avoid unnecessary questions and confusion I thought it’d be good to give a quick overview of Android related code that will be going into bluez.git in the near future.

Since Android 4.2 there exists a well standardized HAL interface that the Bluetooth stack is expected to provide and which enables the easy replacement of the stack of choice on Android. What’s now happening in BlueZ is that we’re working on making BlueZ a drop-in replacement to Android by ensuring that the required HAL interfaces are available straight out of the BlueZ source tree.

Most of the work has little or  no impact on existing BlueZ functionality and architecture and the code will be going under a separate “android” subdirectory. However, since we’re trying to reuse as much code with the rest of BlueZ as possible this also means that some refactoring will be happening elsewhere in the tree to create reusable library-like modules from parts of the code.

One of the intentions of this work is to avoid multiple companies doing their own Android adaptation for BlueZ by having the work done in a central place upstream.

BlueZ 5 API introduction and porting guide

The BlueZ 5 D-Bus API contains significant changes compared to BlueZ 4. The bulk of the changes are due to the following features in BlueZ 5:

  • Transformation to use standard D-Bus Properties and ObjectManager interfaces (available in the D-Bus specification document)
  • Introduction of interface versions (e.g. org.bluez.Adapter1). When new versions are introduced we’ll try to keep supporting at least the two latest versions simultaneously.
  • The simplification or removal of per-profile interfaces and the addition of a general org.bluez.Device1.Connect method to connect profiles.
  • The removal of the org.bluez.Service interface (used for registering SDP records and authorization) and the introduction of a new org.bluez.Profile1 interface
  • Dynamic device object creation during device discovery
  • Introduction of an AgentManager1 interface
  • Base path moved to “/org/bluez”. This shouldn’t make much difference though as the main entry point to any interaction through D-Bus is the ObjectManager.GetManagedObjects call.

D-Bus Properties

The D-Bus Properties interface generalizes access to object/interface properties. BlueZ 4 implemented properties with custom GetProperties and SetProperty methods and PropertyChanged signals on each interface that needed them. Since the release of BlueZ 4 a standard Properties interface has been completed and instead of having these methods and signal on specific interfaces there exists a generic org.freedesktop.DBus.Properties interface on each object with methods such as Set, Get and GetAll as well as a PropertiesChanged signal. These methods and signals contain the specific interface the property belongs to as part of the message parameters. One feature which the standard properties interface exposes that didn’t exist in BlueZ 4 is the invalidation of a property. This is particularly convenient to relay the information that a property doesn’t exist any more.

D-Bus ObjectManager

The D-Bus ObjectManager interface is a generic way of accessing the the entire object hierarchy of a D-Bus service. It includes signals for interface addition and removal and a single GetManagedObjects method which returns all available objects in a service, including interfaces of the objects as well as all properties on all interfaces. The actual ObjectManager interface can be found on the root (“/”) path of the BlueZ service.

Because most tasks of managing and discovering objects can be done through ObjectManager many methods, signals and properties in BlueZ 4 became redundant and were decided to be removed. One of the most notable of these removals is the old org.bluez.Manager interface. In BlueZ 5 there does not exist anything that would correspond to this. Instead, an application would discover the available adapters by performing a ObjectManager.GetManagedObjects call and look for any returned objects with an “org.bluez.Adapter1″ interface. The concept of a default adapter was always a bit fuzzy and the value could’t be changed, so if applications need something like it they could e.g. just pick the first adapter they encounter in the GetManagedObjects reply.

There’s a test/get-managed-objects test script in the source tree that can be used to see the bluetoothd objects exported by ObjectManager.

Device discovery

Bluetooth Low Energy essentially extended Bluetooth addresses with one extra bit, requiring one to always know whether an address is “random” or “public”. This caused issues with the BlueZ 4 API where the address was given to BlueZ in the CreateDevice and CreatePairedDevice calls. Since the parameter didn’t contain any of this extra random/public information bluetoothd had to maintain an internal cache to look up the necessary info. Another complication to the matter is that the BlueZ D-Bus API doesn’t differentiate between traditional BR/EDR devices and LE devices so there are essentially three possible address types: BR/EDR, LE public and LE random.

To solve this issue we decided to simply get rid of explicit CreateDevice/CreatePairedDevice methods and instead dynamically create device objects as they are discovered during device discovery. Since ObjectManager is available this also means that a separate DeviceFound signal is no longer needed. Instead an application doing discovery can simply track newly created device objects through the usual ObjectManager signals. To pair a device (identical to the old CreatePairedDevice) a new Device1.Pair method was added, and to skip pairing and just connect a Device1.Connect method was added (similar, but not quite the same as the old CreateDevice). Once the discovery stops, devices neither connected to or paired will be automatically removed by bluetoothd within three minutes.

There’s a test/test-discovery test script in the source tree that can both be used for testing discovery as well as an example of how to implement device discovery support to an application (which methods and signals are involved, etc)

General device connection procedure

BlueZ 4 had a general Device.Disconnect method but no general Connect. The closest you would get was the Connect method on the Audio interface which grouped together all audio profiles into a single coordinated connection procedure.

Through internal re-factoring and creation of a cleaner internal profile interface BlueZ 5 has been able to generalize this for all profiles and introduce a Device1.Connect method. Any implemented profile can elect to participate in this general connection procedure and will get connected when the user calls the method. Internally this method contains some special knowledge about the recommended connection order for profiles and will sort the profiles based on that. One example is the audio profiles where it’s desirable to have HFP connected first, then A2DP and finally AVRCP.

What this interface means to applications is that instead of trying to discover supported profiles of a device and then deciding exactly which interface’s Connect method needs to be called (org.bluez.Input, org.bluez.Audio, etc. in BlueZ 4) the application can straight proceed to call Device1.Connect and not worry about the details.

To test the Device1.Connect() functionality you can e.g. use the test/test-device script: test-device connect <remote addr>

The new Profile1 interface (and removal of org.bluez.Service)

BlueZ 5 introduces a new generic D-Bus interface for implementing external profiles. The profile (residing in a separate process) implements a org.bluez.Profile1 interface and registers an object implementing it through a new ProfileManager1 interface on the BlueZ side. In the RegisterProfile method (on the ProfileManager1 interface) the profile needs to at least provide the UUID for the profile to be registered. BlueZ has internally a table of defaults for common profiles so no other information is necessarily needed. However, if the profile desires to it can provide information such as the full SDP record (XML encoded), desired security level, enable/disable authorization, version, features, role, name, etc.

Once the profile is registered bluetoothd will take over all tasks needing to be done until the point of a fully created connection for the profile. This includes registering an SDP record (for server-side profiles), starting server sockets or connecting client sockets, and performing authorization (for server-side profiles). Once bluetoothd has completed these tasks it will pass the new connection to the external profile object through a Profile1.NewConnection method call. The method call contains the file descriptor (socket) for the connection as well as a dictionary of properties for the connection. These properties can include things like Version and Features (fetches from the remote SDP record) or even profile-specific entries which bluetoothd internally provides a mechanism to register hooks for.

Since this interface fulfills the same tasks (and more) than the org.bluez.Service interface in BlueZ 4 the old interface has been removed. At the time of BlueZ 5 release, existing projects that have been converted to use the new Profile interface include obexd (all OBEX profiles) as well as oFono (for HFP).

There are a few test scripts in the source tree like test/test-profile and test/test-hfp that can be used as examples for interacting with the ProfileManager1 interface.

The new AgentManager1 interface

BlueZ requires the registration of Agent objects to handle pairing and incoming connection authorization. BlueZ 5 does away with the old Adapter.RegisterAgent method and the agent parameter of the CreatePairedDevice method (Device1.Pair in BlueZ 5) in favor of a more generic AgentManager1 inteface. All agents need to be registered through this interface and BlueZ will automatically pick the agent of same application that called Device1.Pair (assuming that application also owns an agent). An AgentManager1.RequestDefault method exists for an agent to request to become the default one, in which case it will be assigned to handle all incoming (remotely initiated) requests. An agent that previously registered itself with Adapter.RegisterAgent should register itself as the default agent in BlueZ 5.

There are also a few changes for the Agent1 interface (in addition to the rename from Agent to Agent1). Firstly, the ConfirmModeChange method has been removed as this was tied in to the Adapter.RequestSession functionality which was also removed (due to not adding much value). Secondly, there is a new RequestAuthorization method used for requesting authorization for pairing requests which would otherwise not trigger any action for the user. The main situation where this would occur is an incoming SSP pairing request that would trigger the just-works model.

There’s a test/simple-agent test script for testing the AgentManager1 interface as well as giving an example of how agent registration is done.