The upcoming Management Interface

I thought I’d write some things about the upcoming Management Interface, since what it is and the reasons for its existence might be unclear to people. In short, it’s a new interface for user space Bluetooth components (like bluetoothd) to talk to the kernel and it aims to replace the existing raw HCI sockets.

Issues with the current solution

Probably a good starting point is to look at problems with the existing interface to the kernel.

Command queues and synchronization

So far both the kernel and user space have been involved in receiving HCI events and sending HCI commands. However, neither one knows exactly what the other one is doing. The kernel has a proper HCI command queue which makes sure it doesn’t send commands to the controller when the controller is unable to receive them. User space doesn’t have such a mechanism, nor is it aware of the kernels queue. HCI commands sent from user space will bypass the kernel queue as they use the “raw data” queue instead of the command queue.

What this missing synchronization means is that it’s possible for user space to send commands when the controller can’t receive them and we’ve seen several controllers behaving badly in such circumstances. One common case when this can happen is when establishing connections: it’s cheap to update information (e.g. the friendly name) about the remote device when there’s already a link to it so both user space and the kernel try to do it when they see a new link becoming available.

Blocking operations

Powering a Bluetooth adapter on or off from user space has so far been accomplished using the HCIDEVDOWN & HCIDEVUP ioctl’s. Nothing wrong with it as such, except that the ioctl interface is blocking. This isn’t so nice for a single threaded process with an asynchronous mainloop like bluetoothd. The issue has been worked around so far by forking off a child process that does the ioctl, but it’s not a very nice or clean solution.

Extra (unnecessary) processing of HCI events

When there’s one or more raw HCI sockets in user space a special promisc flag is set for the corresponding adapter on the kernel side. When this flag is set the kernel needs to do extra processing to figure out whether an HCI event packet needs to be forwarded to user space or not.

Distributed security policy and logic

With pre-2.1 adapters the Bluetooth security model was rather simple and well understood. The worksplit between the kernel and userspace was also rather simple: user space would take care of storing link keys and responding to PIN and link key requests while the kernel would enforce authentication for sockets that had it as a requirement. With Bluetooth 2.1 and Secure Simple Pairing (SSP) this changed.

With SSP there are several different possible authentication methods and the link key type becomes much more relevant for the security policy. For example, if a socket requires Man In The Middle (MITM) attack protection (aka high security level in BlueZ speak) an unauthenticated link key is not enough but a link key with the type “authenticated” is needed. This is not a problem per-se, but the kernel-user space worksplit has an issue: the kernel knows all sockets and their security requirements while userspace knows the stored link keys and their types. However, the link key response (which the kernel could potentially try to catch) does not contain the key type information. This means that the kernel has no idea of the level of security that a link key provides when user space responds to a link key request.

Lack of early-tracing capability

There’s a nice tool for doing HCI level tracing called hcidump. However, if one desires to catch the early traffic going to and from an adapter right after the adapter has been plugged in there’s a problem: hcidump can only be started once the adapter is available. It’d be nice to have some sort of a higher-level socket that could be used to catch traffic from all existing adapters as well as newly plugged ones.

Cue the Management interface

The idea of the management interface is to remove the need to have raw HCI sockets in user space. It solves most of the issues raised above:

Command queues and synchronization

Since the kernel is now responsible for all HCI traffic there’s no risk of conflicts between kernel and userspace.

Blocking operations

With the management interface there are simple asynchronous messages that are used to power on and off adapters: blocking problem solved.

Unnecessary HCI event processing

No raw HCI sockets means no promisc flag on the kernel side. So extra processing of these packets isn’t needed anymore.

Distributed security policy and logic

With the management interface only user interaction (PIN code/pass key requests, etc) and link key storage is handled on the user space side. User space will feed the kernel with all stored link keys, including the key types, upon adapter initialization. After that the kernel is responsible for handling link key requests.

An additional benefit with having an abstracted interface for security is that it can be used for the Security Manager Protocol (SMP) that’s part of the Bluetooth Low Energy (LE) specification. SMP has a similar user interaction model as SSP so the same messages between user space and the kernel can be reused.

As long as SMP is implemented on the kernel side there’d be a big problem with dealing with it from user space using the existing kernel interface since unlike SSP, SMP uses L2CAP and not HCI for messaging.

Lack of early-tracing capability

The management interface will offer a special type of tracing socket which can be used to get the HCI traffic of all connected adapters. This will allow a userspace process to catch all traffic to and from an adapter from the first moment that it is plugged in.

Current status

During the last few months bluetoothd has gone through considerable refactoring to move the user space – kernel interface to a single place and create an abstraction which doesn’t depend on the techincal details of this interface. This interface is called “adapter operations” and there’s a adapter_ops struct in src/adapter.c that describes it. For the legacy raw HCI socket based solution there’s a plugin called hciops (plugins/hciops.c) which implements the adapter_ops interface. For the management interface there is plugins/mgmtops.c. bluetoothd will automatically select mgmtops if it is running on top of a kernel with that capability and if not it will wall back to hciops.

The exact definition of the management interface is still evolving, but the latest one can always be found in doc/mgmt-api.txt.

On the kernel side some management patches have already gone into the bluetooth-next-2.6 tree [0] and the very latest ones can be found in my own kernel tree [1] (which is rebased periodically on top of bluetooth-next-2.6). Since the code cannot fully replace the existing raw HCI socket based solution it is disabled by default and needs to be explicitly enabled using a enable_mgmt=1 option to the bluetooth module (or “echo 1 > /sys/module/bluetooth/parameters/enable_mgmt”).


What works

  • Adapter enumeration
  • Powering on/off adapters (no blocking ioctls anymore!)
  • Setting adapters as discoverable
  • Basic Class of Device value control
  • Legacy pairing (PIN request)
  • Link key handling
  • just-works SSP pairing

What doesn’t work (but will in a few weeks)

  • Device discovery
  • Full pairing support (legacy, SSP & SMP)
  • LE support (both SMP and device discovery)
  • Some minor features of adapter_ops.

The future of hciops

Originally our plans were to drop the raw HCI socket based approach completely with BlueZ 5.x and require a kernel that has the management interface. This plan was based on the assumption that the user space code base wouldn’t be maintainable with both kernel interfaces. However, as the mgmtops/hciops abstraction seems to have proceeded rather successfully there really isn’t a need to drop support for old kernels anymore (it remains to be seen if this will still be done though). Some things however, like LE SMP support, will not be available with hciops.