Skip to main content

14.7 The Linux Bluetooth Subsystem

In the previous section, we were stressing over network latency, discussing how to squeeze every last drop of performance out of the system using "hardcore" techniques like Busy Poll. This is an extreme strategy that trades CPU idle time for speed.

Now, let's relax a bit and shift our gaze away from gigabit Ethernet cables toward a completely different kind of network world—Wireless Personal Area Networks (PANs). There are no blazing speeds of direct fiber connections here, nor the microsecond-level anxieties of HFT (High-Frequency Trading), but there is an ever-present need for connectivity: your wireless mouse, your fitness tracker, your wireless earbuds.

In this section, we'll talk about Bluetooth, and how Linux supports this massive and complex ecosystem through the BlueZ protocol stack.


Background and Motivation

If you told an engineer in 1994 that "one day we're going to cut the wires off our earbuds," they might have thought you were crazy. But that same year, Ericsson indeed launched a project called "Bluetooth." Initially, its goal was incredibly humble: replace RS-232 data cables. No one expected it to evolve into a wireless standard connecting billions of devices.

Today's Bluetooth is no longer a simple "wireless serial port." It operates in the free 2.4GHz ISM band (crowded alongside Wi-Fi and microwaves) and is maintained by the Bluetooth SIG (Special Interest Group). Although we often joke that Bluetooth is the "king of disconnections," in close-range, low-power scenarios, it remains the undisputed champion.

Linux kernel support for Bluetooth began in 2001 with kernel 2.4.6, in a project called BlueZ. This is still the default Bluetooth protocol stack for almost all Linux distributions today. Understanding the BlueZ architecture is crucial for debugging all sorts of bizarre connection issues or developing Bluetooth-based applications.


Protocol Stack Panorama: Layers and Responsibilities

The Bluetooth protocol stack looks a bit like TCP/IP, but it's more complex because it has to handle entirely different things like audio streams, device discovery, and file transfers. We can roughly map it to the OSI model:

  1. Lower Layers (Radio / Link Controller / LMP): These are typically implemented in hardware or firmware. As kernel driver developers, we usually only interact with the layer above and don't touch this directly.
  2. HCI (Host Controller Interface): This is the bridge for the kernel to talk to the hardware. It's also the main focus of this chapter.
  3. L2CAP (Logical Link Control and Adaptation Protocol): Equivalent to the transport layer. It handles packet encapsulation, segmentation, reassembly, and provides multiplexing.
  4. Application Layer Protocols: Built on top of L2CAP, such as RFCOMM (serial port emulation), SDP (Service Discovery), BNEP (Network Encapsulation), and so on.

💡 Analogy Time: Three-Stage Callback

You can think of the Bluetooth protocol stack as an office building.

  1. Establishing the Mapping:

    • The lower-level hardware is the building's foundation and plumbing (electricity, water, ventilation).
    • HCI is the front desk on the first floor. All letters and instructions must go through the front desk to be passed inside the building or sent out. The front desk doesn't care about the content of the letters; it only handles delivery.
    • L2CAP is the mailroom on each floor. It's responsible for breaking large packages into smaller ones (segmentation) or assembling small ones into large ones (reassembly), and distributing them to different rooms (Sockets) based on door numbers (Channel IDs).
    • Upper-layer protocols (like RFCOMM) are the specific rooms. Some rooms are dedicated to making phone calls (audio), others to sending emails (data transfer).
  2. Revealing the Distance: But there's a flaw in this analogy: the front desk (HCI) usually isn't just one. Your computer might have a built-in Bluetooth adapter (USB) and also have a USB Bluetooth dongle plugged in. The HCI layer in the kernel has to manage both "front desks" simultaneously, and they are completely independent of each other. Additionally, L2CAP's "mailroom" is smarter than its real-world counterpart—it can negotiate packet sizes (MTU) and guarantee ordering—something a UDP postal system doesn't offer.

  3. Callback Verification: When you see the hci_dev structure later, you'll realize it's essentially the employee files for the front desk staff; and l2cap_chan is the mailroom's logbook. If the front desk goes on strike (driver fails to load), no matter how luxurious the rooms upstairs are, the building is paralyzed.


BlueZ Architecture in the Linux Kernel

BlueZ is not a single module; it's a suite of components.

The core code resides in the net/bluetooth/ directory. If you don't want to tear your hair out, it's best to first understand these key players:

  • HCI Core (hci_core.c, mgmt.c): The brain of the Bluetooth controller, responsible for managing devices, connections, and scheduling.
  • Socket Layer (af_bluetooth.c): Provides the BSD Socket API, allowing user-space programs to interact with Bluetooth just like TCP/IP.
  • L2CAP (l2cap*.c): Handles logical link control; this is the mandatory path for all data streams.
  • Driver Layer (drivers/bluetooth/): This is where the kernel shakes hands with the hardware. For example, btusb.c is the generic USB Bluetooth driver, and hci_uart.c is the serial port-based driver (used by many embedded boards).

Core Mechanism Breakdown: The HCI Layer

HCI is the interface between the Host and the Controller. In the Linux kernel, every physical Bluetooth adapter is represented by an struct hci_dev structure.

This structure is massive (over 100 members) and serves as the "ID card" of the kernel's Bluetooth world. Let's look at a few of the most important fields:

struct hci_dev {
char name[8];
unsigned long flags;
__u8 bus;
bdaddr_t bdaddr;
__u8 dev_type;

struct work_struct rx_work;
struct work_struct cmd_work;

struct sk_buff_head rx_q;
struct sk_buff_head raw_q;
struct sk_buff_head cmd_q;

int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
int (*send)(struct sk_buff *skb);
...
};

Let's do a "manual" breakdown of these fields:

  • bdaddr: This is the Bluetooth device's MAC address, 48 bits, globally unique. You can see it in /sys/class/bluetooth/hci0/address.
  • bus: Where is this controller attached? Is it USB (HCI_USB)? PCIe (HCI_PCI)? Or UART (HCI_UART)? The driver fills this in during initialization.
  • flags: Describes the state. For example, HCI_UP means the device is up, and HCI_INIT means it's initializing.
  • Workqueues (rx_work, cmd_work): Bluetooth handles a massive amount of asynchronous events. The kernel can't do too much work inside a hardware interrupt, so it puts received packets (rx_q) and pending commands (cmd_q) into queues, handing them over to work_struct for slow processing.
  • Callback Functions (open, close, send): This is the stage for driver developers. When you write a Bluetooth driver, your main job is to implement these functions to tell the kernel how to push data to your hardware.

The Four Journeys of a Packet

The HCI layer defines four types of packets, and these four types make up the entire conversation between the kernel and the hardware:

  1. HCI_COMMAND_PKT: Commands sent from the host to the hardware. For example, "start scanning for nearby devices" or "connect to XX:XX:XX:XX:XX:XX".
  2. HCI_ACLDATA_PKT: Asynchronous data. This is the main body of file transfers, corresponding to ACL links.
  3. HCI_SCODATA_PKT: Synchronous data. Primarily audio (SCO links).
  4. HCI_EVENT_PKT: Events sent from the hardware to the host. For example, "found a device" or "connection completed".

The interaction flow looks like this: When you run hcitool scan, the kernel sends a HCI_COMMAND_PKT to the hardware via hci_send_cmd(). The hardware doesn't reply immediately; instead, after scanning and finding a device, it throws an HCI_EVENT_PKT back via an interrupt. This packet is received and processed by hci_event_packet(). There is no synchronous waiting here; it's all asynchronous callbacks.


Upward Integration: The L2CAP Layer

After the HCI layer pulls data from the hardware, it tosses it up to the L2CAP layer. L2CAP is the central nervous system of the Bluetooth protocol stack.

Its job isn't just transportation; it also includes:

  • Segmentation and Reassembly (SAR): The lower-level HCI can only transmit packets of limited size. L2CAP is responsible for chopping your 1MB file into small chunks, sending them, and reassembling them on the other end.
  • Multiplexing: You're listening to music over Bluetooth (A2DP) while moving your mouse (HID). L2CAP separates these two data streams using Channel IDs (CIDs).

The kernel uses struct l2cap_chan to represent a channel.

When HCI receives ACL data, it calls hci_acldata_packet() -> l2cap_recv_acldata(). This function checks the packet header:

struct l2cap_hdr {
__le16 len; // 长度
__le16 cid; // 通道 ID
} __attribute__ ((packed));
  • If cid == 0x0001, it means this is the signaling channel, which handles control commands. For example, if another device wants to connect to you, the connection request (L2CAP_CONN_REQ) it sends will go through this channel. The kernel calls l2cap_sig_channel() to handle it, creates a new l2cap_chan, sets its state to BT_OPEN, and begins configuration.
  • If cid is any other value, the data is simply thrown to the corresponding Socket.

Hands-on: BNEP and Bluetooth IP

Bluetooth isn't just for transferring files or audio; it can also run IP. This is what BNEP (Bluetooth Network Encapsulation Protocol) does. It stuffs Ethernet frames into Bluetooth L2CAP channels, allowing you to connect two computers into a local area network over Bluetooth.

This is much more efficient than using PPP dial-up.

Returning to the "office building" analogy: BNEP is like laying a dedicated freight line between buildings. Whether you're sending a parcel (IP packet) or a letter, as long as you pack it into a shipping container (Ethernet frame) and toss it onto the freight line, it gets transported to the other building. The other building's mailroom (L2CAP) receives it, uncrates it, and distributes it to the specific rooms.

How to Play with BNEP?

You don't need to write code; Linux has a ready-made tool called pand (BlueZ PAN daemon).

Server (acting as a router/hotspot):

pand --listen --role=NAP
# NAP = Network Access Point

Client (connecting to the hotspot):

pand --connect 00:1A:7D:DA:71:13

Once connected, a virtual network interface called bnep0 will appear on your machine.

At this point, you can assign it an IP address just like a regular network interface:

ifconfig bnep0 192.168.1.1 netmask 255.255.255.0 up

The Underlying Mechanism

When pand --connect is executed, the user-space program creates an L2CAP Socket and initiates a connection. After receiving the request, the server sends an IOCTL command of BNEPCONNADD to the kernel.

The function handling this command in the kernel is bnep_add_connection() (net/bluetooth/bnep/core.c). It does the following:

  1. Creates a session: Generates a bnep_session object to record the connection state.
  2. Registers the network device: Calls register_netdev(), which is why you see bnep0 appear in the ip link list.
  3. Starts a kernel thread: Creates a daemon thread called kbnepd. This thread is an infinite loop dedicated to receiving packets (bnep_rx_frame) and sending packets (bnep_tx_frame).
    • Receive packet -> Strip BNEP header -> What remains is a pure Ethernet frame -> Throw it to netif_rx() to enter the TCP/IP stack.
    • Send packet -> Add BNEP header -> Throw it to L2CAP -> Throw it to HCI -> Transmit.

Full Data Flow Panorama

Let's trace how an IP packet is transmitted over Bluetooth:

  1. Application Layer: ping 192.168.1.2
  2. TCP/IP Stack: Constructs an ICMP packet, looks up the routing table, and determines it should go out through bnep0.
  3. BNEP: bnep_netdev_xmit() is called. It encapsulates the Ethernet frame into BNEP format.
  4. L2CAP: BNEP calls the L2CAP Socket send interface. L2CAP adds its own header (containing the CID) and may fragment the data.
  5. HCI: L2CAP calls the HCI send interface. HCI puts the packet on cmd_q or sends it directly to the hardware driver via hci_send_frame().
  6. Hardware Driver (e.g., btusb): Converts the SKB into a USB URB and sends it flying to the USB Bluetooth dongle.
  7. Over-the-Air Interface: The Bluetooth chip turns the data into 2.4GHz radio waves and beams them to the other device.

Reception is the reverse: Over-the-air -> Hardware -> HCI (hci_rx_work) -> L2CAP (l2cap_recv_acldata) -> BNEP (bnep_rx_frame) -> TCP/IP Stack -> Application.


Extended Features and Tools

As the standard evolved, L2CAP is no longer the "simple UDP" it once was. Kernel 2.6.36 introduced Extended Features (eL2CAP):

  • ERTM (Enhanced Retransmission Mode): Reliable transmission with retransmissions. This is similar to TCP, not just UDP's "best effort" approach.
  • Streaming Mode (SM): A streaming mode that sacrifices reliability for real-time performance.
  • FCS (Frame Check Sequence): Adds a checksum to each packet to prevent data corruption.

These features are mandatory for certain medical devices (HDP Profile) that have extremely high reliability requirements.

Finally, how do we troubleshoot issues? Don't expect dmesg to tell you everything; you need a Swiss Army knife:

  • hciconfig: View and configure HCI devices. hciconfig hci0 up brings up the device.
  • hcitool: A debugging powerhouse. hcitool scan for scanning, hcitool lescan for scanning Low Energy devices.
  • hcidump / btmon: Packet capture artifacts. Just like Wireshark, but they capture raw Bluetooth data over the air (or at the HCI layer). If you want to see why your mouse won't connect, just run btmon and it will be clear at a glance.

Chapter Echoes

We completed a full traversal from the lower-level hardware drivers up to the upper-level IP protocol.

On the surface, this section is about "how Bluetooth connects to the network," but in reality, we're looking at how a complete network subsystem collaborates across layers.

  • The HCI layer abstracts away hardware differences (USB, UART, SDIO).
  • The L2CAP layer provides multiplexing and basic transport services.
  • The BNEP layer disguises the heterogeneous Bluetooth link as a standard Ethernet device, allowing the existing TCP/IP stack to run without modification.

Remember the "office building" analogy from the beginning? Now you should understand that the Linux Bluetooth subsystem is complex because it not only has to manage the building's front desk (HCI) and mailroom (L2CAP), but also lay dedicated freight lines (BNEP) between buildings. Each layer has its own independent state machine and protocols, yet they tightly interlock.

In the next section, we'll jump from Personal Area Networks (PANs) to a broader, but more low-level wireless domain—IEEE 802.15.4 and 6LoWPAN. That is the world of the Internet of Things (IoT), where protocols are more streamlined and stingier with resources, but the design philosophy shares striking similarities with Bluetooth.