1. Context

I’ve been trying to understand how Bluetooth works, and those are my notes along the way. I know better how the usual Internet stack works, so I tend to draw comparison from it.

This probably contains many errors, so beware of where you step.

2. Overview

Bluetooth Low Energy (LE) is achieved by using larger, but fewer channels (aka, by reducing the frequency accuracy).

Maximum throughput seems to be 8Mbits/s (HDR8) on a wide 4Mhz channel (mostly limited by the relatively slow clock used. This slow clock is also the reason for the relative high latency in bluetooth).

3. Networks

A single device can communicate with 7 other devices in a piconet. Piconets can be linked together to form scatternets.

4. Roles

Devices follow a leader/follower approach, but they can exchange roles. A device can be the follower of multiple leaders, and a leader can talk to up to 7 followers (switching between each in a round-robin fashion).

5. Protocol

The bluetooth protocol is designed differently from the OSI model used for Internet, and doesn’t preserve a very clear distinctions between all the layers:

Bluetooth stack diagram

The organization of the protocol seems to be linked to the teams having worked on the protocol and Conway’s law (reference: Computer Networks, by Andrew Tanenbaum).

The link manager is in charge of establishing the connection with other link managers (devices), and to also handle authentication.

5.2. Host Controller Interface (HCI)

Mainly finds other bluetooth devices on the network.

The L2CAP is a protocol used to transmit data.

It has 2 variants:

  • Enhanced Retransmission Mode (ERTM): basically equivalent to TCP on the Internet stack;

  • Streaming Mode (SM): basically equivalent to UDP on the Internet stack.

5.4. Service Discovery Protocol (SDP)

The SDP allows discovering services/profiles a device offers:

  • each service has a UUID;

  • each service defines a specific profile.

For example, a profile might be there to handle a headset’s play/pause communication, while another profile might be there to handle the actual audio data transmission.

Some profiles are only visible after a devices has been authenticated, for security purposes.

On other stacks, this would be mDNS and its service discovery on a LAN, or like UPnP’s SSDP in the world of DLNA’s audio/video devices.

5.5. Audio/Video Control Transport Protocol (AVCTP)

AVCTP defines ways to send/receive commands controlling audio and video streams, such as play, pause, next, etc.

Used by the Audio/Video Remote Control Profile (AVRCP) profile.

5.6. Audio/Video Distribution Transport Protocol (AVDTP)

AVDTP defines ways to send/receive audio and video streams by the advanced audio distribution (A2DP) profile.

5.7. Other protocols

Other protocols can be used such as OBEX, IP/TCP/UDP, PPP, WAP, etc.

Those might be used for sending files through Bluetooth (some phones do that).

Each protocol seems to be tightly linked to a given profile. This is a strong indication of the organizations behind having worked in silos. This is also unlike TCP which basically carry many different applicative protocol (profiles in the Bluetooth parlance).

6. Connections

6.1. Discovery

Each device can be in discovery mode, and transmit some information if requested, such as:

  • name;

  • class;

  • list of services.

The name does not have to be unique, and this can potentially lead to name squatting, or having people try to connect to devices they think they control because the name is identical.

6.2. Pairing (and bonding)

For security reasons, not all devices should automatically connect to each other, and require pairing.

The idea is to share and store a secret between 2 devices. Once this is done, the devices are bonded.

This is achieved through the Secure Simple Pairing (SSP) process (unless old Bluetooth < 2.1 used). Multiple ways exist for the SSP to succeed, depending on the capabilities of the devices:

  • Just Works: aka, automatic secret sharing with optional confirmation by the user. Simple, but not very secure (I never saw it in reality);

  • Numeric Comparison: if both devices have a display, a 6-digit code is shown on both devices, and the user must confirm it is the same on one of the devices (I never saw it in reality);

  • Passkey Entry: if only one of the devices has a display, and the other one has a way to enter digits (such as a keyboard), the user must enter the 6-digit code on the other devices for confirmation (it can be seen when setting up a new iPad with an existing iPhone for example, or some Android TVs);

  • Out of band: the confirmation is sent on a different channel/medium and/or at a different time (eg: by email, on an NFC token, etc.). (might be used when bringing a phone close to a device to pair them, one of them containing an NFC token)

7. Profiles

7.1. Advanced Audio Distribution Profile (A2DP)

This allows uni-directional transfer of up to 2 audio channels.

This is done by using some audio codecs, all but SBC are optional, but can be extended by manufacturers:

  • SBC (mandatory codec, easy to implement but low quality with default parameters);

  • MPG 2/3/4 (optional);

  • ATRAC (optional);

  • aptX (optional);

  • LDAC (optional);

  • etc.

No lossless codec is used yet (probably due to the lack of bandwidth to use something like Flac).

Some of those codecs also support DRMs.

Manufacturers tend to market and differentiate themselves on the list of supported codecs (especially for headphones).

Yet, high-end manufacturers of AV devices may only support the bare minimum codec (SBC), such as the Denon AVR-X2700H stating a support of [A2DP 1.2 SBC](https://manuals.denon.com/AVRX2700H/EU/FR/GFNFSYbsjxinov.php).

7.2. Audio/Video Remote Control Profile (AVRCP)

Each version of AVRCP adds functionalities to control an audio device (such as a HiFi system, a TV or a car audio system):

  • play, pause, volume, etc;

  • status (playing, paused, etc);

  • track metadata (artist, track name, etc);

  • searching and browsing;

  • sending albums covers.

7.3. Human Interface Device Profile (HID)

Mouses, keyboards and game controllers use the Human Interface Device (HID) protocol.

HID is also used through USB.

8. Bluetooth on Linux

However, the kernel does not usually see any of the packet/protocol used unlike on the Internet stack.

For example, a Bluetooth headset will be connected through HCI, but then appears as a sound card with some specific parameters, such as the SBC codec.

8.1. Bluetooth headset as an audio card

Once you have paired your headset on Linux, you can use pulseaudio to list it.

It is seen as an audio card supporting the SBC codec in this case (aka the bare minimum):

$ pactl list
Card #1
        Name: bluez_card.C8_7B_23_2C_EA_A8
        Driver: module-bluez5-device.c
        Owner Module: 22
        Properties:
                device.description = "LE-Bose Sport Earbuds"
                device.string = "C8:7B:23:2C:EA:A8"
                device.api = "bluez"
                device.class = "sound"
                device.bus = "bluetooth"
                bluez.path = "/org/bluez/hci0/dev_C8_7B_23_2C_EA_A8"
                bluez.class = "0x000000"
                bluez.alias = "LE-Bose Sport Earbuds"
                device.icon_name = "audio-card-bluetooth"
                bluetooth.codec = "sbc"
        Profiles:
                headset_head_unit: Headset Head Unit (HSP) (sinks: 1, sources: 1, priority: 30, available: no)
                a2dp_sink: High Fidelity Playback (A2DP Sink) (sinks: 1, sources: 0, priority: 40, available: yes)
                handsfree_head_unit: Handsfree Head Unit (HFP) (sinks: 1, sources: 1, priority: 30, available: yes)
                off: Off (sinks: 0, sources: 0, priority: 0, available: yes)
        Active Profile: a2dp_sink
        Ports:
                unknown-output: Bluetooth Output (type: Bluetooth, priority: 0, latency offset: 0 usec, availability unknown)
                        Part of profile(s): headset_head_unit, a2dp_sink, handsfree_head_unit
                unknown-input: Bluetooth Input (type: Bluetooth, priority: 0, latency offset: 0 usec, availability unknown)
                        Part of profile(s): headset_head_unit, handsfree_head_unit

Using pulseaudio and bluez, we can request which audio codecs are supported by this headset:

$ pactl send-message /card/bluez_card.C8_7B_23_2C_EA_A8/bluez list-codecs | jq
[
  {
    "name": "sbc",
    "description": "SBC"
  },
  {
    "name": "sbc_xq_453",
    "description": "SBC XQ 453kbps"
  },
  {
    "name": "sbc_xq_512",
    "description": "SBC XQ 512kbps"
  },
  {
    "name": "sbc_xq_552",
    "description": "SBC XQ 552kbps"
  }
]

8.2. Bluetooth traffic capture

tcpdump can be used to capture bluetooth packets:

$ tcpdump -D
1.wlo1 [Up, Running, Wireless, Associated]
2.flannel.1 [Up, Running, Connected]
...
35.bluetooth0 (Bluetooth adapter number 0) [Wireless, Association status unknown]
36.bluetooth-monitor (Bluetooth Linux Monitor) [Wireless]
...

Let’s start recording packets, and push the "play/pause" button on the headset:

$ tcpdump -i bluetooth0 -w bluetooth0_capture.pcap
tcpdump: listening on bluetooth0, link-type BLUETOOTH_HCI_H4_WITH_PHDR (Bluetooth HCI UART transport layer plus pseudo-header), snapshot length 262144 bytes
^C49 packets captured
27059 packets received by filter
0 packets dropped by kernel

However, this only shows HCI_EVT packets, and does not show anything else.

Alternatively, we can install hcidump to parse dump HCI packets (many more tools exist):

$ hcidump
HCI sniffer - Bluetooth packet analyzer ver 5.66
device: hci0 snap_len: 1500 filter: 0xffffffffffffffff
> HCI Event: Command Status (0x0f) plen 4
    Create Connection (0x01|0x0005) status 0x00 ncmd 1
> HCI Event: Connect Complete (0x03) plen 11
    status 0x00 handle 21 bdaddr C8:7B:23:2C:EA:A8 type ACL encrypt 0x00
> HCI Event: Command Status (0x0f) plen 4
    Read Remote Supported Features (0x01|0x001b) status 0x00 ncmd 1
> HCI Event: Command Complete (0x0e) plen 4
    Write Scan Enable (0x03|0x001a) ncmd 1
    status 0x00
> HCI Event: Read Remote Supported Features (0x0b) plen 11
    status 0x00 handle 21
    Features: 0xff 0xfe 0x8f 0xfe 0xdb 0xff 0x5b 0x87
> HCI Event: Command Status (0x0f) plen 4
    Read Remote Extended Features (0x01|0x001c) status 0x00 ncmd 1
> HCI Event: Read Remote Extended Features (0x23) plen 13
    status 0x00 handle 21 page 1 max 2
    Features: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> HCI Event: Command Status (0x0f) plen 4
    Remote Name Request (0x01|0x0019) status 0x00 ncmd 1
> HCI Event: Remote Name Req Complete (0x07) plen 255
    status 0x00 bdaddr C8:7B:23:2C:EA:A8 name 'Bose Sport Earbuds'
> HCI Event: Command Status (0x0f) plen 4
    Authentication Requested (0x01|0x0011) status 0x00 ncmd 1
> HCI Event: Command Complete (0x0e) plen 10
    Link Key Request Reply (0x01|0x000b) ncmd 1
    status 0x00 bdaddr C8:7B:23:2C:EA:A8
> HCI Event: Auth Complete (0x06) plen 3
    status 0x00 handle 21
> HCI Event: Command Status (0x0f) plen 4
    Set Connection Encryption (0x01|0x0013) status 0x00 ncmd 1
> HCI Event: Encrypt Change (0x08) plen 4
    status 0x00 handle 21 encrypt 0x01

Looking at the dump, it’s handling the connection setup, and that’s it. Nothing else is shown.

8.3. Why can’t Linux record bluetooth packets?

A2DP or HID packets cannot be seen by Linux, because manufacturers actually abstracted that part about with hardware Bluetooth controllers.

Block diagram of the Bluetooth controller CC256x Dual-Mode Bluetooth from Texas Instrument

The controller expose the connection part, but then abstract things away as a sound card.

This solution comes with a some pros and some cons:

Pros:

  • No specific Bluetooth driver required in the kernel to handle all the bluetooth protocols and profiles, relying on generic devices instead (sound card, keyboard, etc.);

  • No specific driver installation for each device when first using it;

  • No way for users to send rogue bluetooth packets easily.

Cons:

  • Specific Bluetooth protocols, profiles and codecs is not upgradable, because set in hardware;

  • Difficult for users to tinker with it, and gain knowledge on how all the protocol works;

The only way to capture the Bluetooth packets between Bluetooth controllers is with specialized devices called bluetooth sniffers, or with a Software Defined Radio (SDR).