5 total
Advertiser, Scanner…
48-bit
Random Address
8.1 — What the Link Layer Does
The Link Layer sits directly above the Physical Layer in the BLE stack. While the Physical Layer just moves raw bits over the air, the Link Layer gives those bits structure and meaning. It is responsible for:
- Controlling and establishing links — deciding when to connect, how to connect, and managing the lifecycle of a connection
- Selecting frequencies — implementing frequency hopping across the 37 data channels during a connection
- Supporting topologies — managing the Master/Slave relationship in a piconet
- Supporting data exchange modes — advertising, scanning, and connected data transfer
The Link Layer is one of the layers that was completely redesigned for BLE rather than adapted from classic Bluetooth. Its 5-state design is intentionally minimal — just enough to support all required BLE use cases while keeping the implementation as simple and power-efficient as possible.
The Link Layer provides services upward to L2CAP and receives radio services downward from the Physical Layer. HCI is the interface that separates the host stack (everything from L2CAP upward, typically running on the main application processor) from the controller (Link Layer + Physical Layer, typically on a dedicated Bluetooth chip).
8.2 — The Five Link Layer States
The entire operation of the BLE Link Layer can be described by a state machine with exactly five states. At any point in time, the Link Layer is in exactly one of these states. The state determines what radio activity is happening and what the device is currently doing on the air.
advertising packets
No TX, no RX
ch 37, 38, 39
connection
connection
to an Advertiser
Advertiser → Slave
on 37 data channels
In practice, most BLE devices only ever need two or three of these states. A simple sensor that just advertises its data might only use Standby and Advertising. A smartphone scanning for peripherals uses Standby, Scanning, Initiating, and Connection. The full five-state machine is the union of all possible device behaviours.
Standby is the default state. The device is powered on but the radio is completely inactive — no packets are transmitted or received. Every BLE device starts here after power-on reset. A device can transition to Standby from any other state, making it the universal reset point of the state machine.
In terms of power consumption, Standby is the cheapest active state — the device is ready to do something but is not consuming radio power yet. A BLE sensor in deep sleep would power up into Standby, move to Advertising to send its data, then return to Standby and power down the radio until the next sensor reading.
In the Advertising state, the Link Layer transmits advertising packets on the three advertising channels (37, 38, 39) in a repeating cycle. A device in this state is called an Advertiser. It may also listen briefly for responses from devices that react to its advertisement.
Advertising serves multiple purposes depending on what the Advertiser puts in its advertising packets:
- Announcing existence: “I am here, I am a heart rate monitor”
- Broadcasting data: Sending a small payload (like a temperature reading or beacon data) to any listener within range, with no connection needed
- Inviting connections: Signalling that the device is ready to accept a connection request from an Initiator
(Advertiser role)
• “I am a thermometer”
• Current temp: 37.2°C
• Connectable: YES
• TX Power: -4 dBm
ch 38
ch 39
(typical interval)
Picks up ADV packet
→ may connect
Receives temp data
no connection needed
In the Scanning state, the Link Layer listens on the advertising channels for packets from Advertisers. A device in this state is called a Scanner. The Scanner may also send a Scan Request to an Advertiser to ask for additional information not included in the initial advertising packet (for example, the full device name if it was too long to fit). The Advertiser responds with a Scan Response.
Scanning uses more power than advertising because the receiver must stay active and sensitive to detect incoming signals. This is by design — in the BLE power model, the central device (typically a phone or hub with a large battery) does the scanning while the peripheral (the small sensor) does the advertising.
/* Starting BLE scan from BlueZ — two ways */
/* Method 1: Command line */
/* sudo hcitool lescan */
/* sudo hcitool lescan --duplicates (show repeated advertisers) */
/* sudo hcitool lescan --passive (don't send scan requests) */
/* Method 2: C code using BlueZ HCI library */
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int start_le_scan(int dev_id)
{
int sock = hci_open_dev(dev_id);
/* scan_type: 0x01 = active (sends scan requests)
0x00 = passive (only listens) */
int err = hci_le_set_scan_parameters(
sock,
0x01, /* active scan */
htobs(0x0010), /* interval: 10ms */
htobs(0x0010), /* window: 10ms */
0x00, /* own addr type: public */
0x00, /* filter policy: accept all */
1000);
if (err < 0) { perror("Set scan params"); return err; }
err = hci_le_set_scan_enable(sock, 0x01, 0x00, 1000);
if (err < 0) { perror("Enable scan"); return err; }
return sock; /* caller must read HCI events from this socket */
}
The Initiating state is entered when the Scanner has found an Advertiser it wants to connect to and decides to establish a connection. A device in this state is called an Initiator. The Initiator sends a CONNECT_REQ packet to the specific Advertiser. This packet contains all the parameters needed for the connection — timing, channel map, hop increment, and so on.
When the Advertiser receives the CONNECT_REQ:
- The Initiator transitions to the Connection state and takes the Master role
- The Advertiser also transitions to the Connection state and takes the Slave role
This is the critical moment where the roles become fixed for the duration of the connection. The device that initiated (sent CONNECT_REQ) is always the Master. The device that advertised and accepted is always the Slave.
In the Connection state, two devices are communicating directly over the 37 data channels using adaptive frequency hopping. This state has two distinct roles:
The Master controls the connection timing. It decides when connection events happen, sets the connection interval, and manages the channel hopping sequence. The Master is always the device that was the Initiator — the one that sent the CONNECT_REQ to start the connection. Typically a smartphone, hub, or computer.
The Slave follows the timing set by the Master. It wakes up at the scheduled connection events, exchanges data, and then sleeps until the next event. The Slave is always the device that was the Advertiser. Typically a sensor, peripheral device, or IoT node.
Scatternet support — Bluetooth 4.0 vs 4.1: In version 4.0 of the specification, a Slave could only be connected to one Master at a time. There was no scatternet support. Specification 4.1 extended this: a device can now be the Master of one piconet and the Slave of another simultaneously, or a Slave in multiple different piconets. This flexibility enables more complex IoT topologies but adds implementation complexity — which is why it remained optional.
/* Connecting to a BLE peripheral using bluetoothctl */
/* bluetoothctl is the standard BlueZ management tool */
/* Step 1: Start scanning to find the device */
/* $ bluetoothctl */
/* [bluetooth]# scan on */
/* Discovery started */
/* [NEW] Device AA:BB:CC:DD:EE:FF Polar H7 */
/* Step 2: Connect — our device becomes Master, Polar H7 = Slave */
/* [bluetooth]# connect AA:BB:CC:DD:EE:FF */
/* Attempting to connect to AA:BB:CC:DD:EE:FF */
/* [CHG] Device AA:BB:CC:DD:EE:FF Connected: yes */
/* Step 3: Verify connection state via hcitool */
/* $ hcitool con */
/* Connections: */
/* LE AA:BB:CC:DD:EE:FF handle 64 state 1 lm MASTER */
/* The "MASTER" label confirms our device is in Master role */
8.3 — Device Address
In classic Bluetooth, every device has exactly one permanent 48-bit Bluetooth Device Address (BD_ADDR) burned into the hardware at the factory. You cannot change it. BLE is more flexible — a BLE device may have a Public Address, a Random Address, or both. At least one must be present so the device can be identified on the air.
• Same as BD_ADDR (dual mode)
• Administered by IEEE
• Cannot change
The Public Address is BLE’s equivalent of the classic Bluetooth BD_ADDR. It is a 48-bit globally unique identifier that is permanently assigned to the device by the manufacturer. It never changes. For dual-mode devices (those supporting both BR/EDR and BLE), the public device address is the same value as the BR/EDR BD_ADDR — the single address identifies the device regardless of which radio it is using.
The 48-bit address is structured in two halves:
to each company.
All devices from the
same company share this prefix.
B8:27:EB = Raspberry Pi Foundation
manufacturer to each
individual controller unit.
Unique within that company.
No two devices share this
The OUI is administered by IEEE — the same organisation that manages Ethernet MAC addresses. This is not a coincidence: the 48-bit format and the OUI concept are borrowed directly from the IEEE 802 address space. The Bluetooth SIG is registered with IEEE to allocate OUIs for Bluetooth device manufacturers.
/* Reading the local Bluetooth device address with BlueZ */
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
void print_device_address(int dev_id)
{
struct hci_dev_info di;
if (hci_devinfo(dev_id, &di) < 0) {
perror("hci_devinfo");
return;
}
char addr_str[18];
ba2str(&di.bdaddr, addr_str);
/* ba2str converts binary bdaddr_t to "XX:XX:XX:XX:XX:XX" string */
printf("Device: %s\n", di.name);
printf("BD_ADDR: %s\n", addr_str);
/* Output example:
Device: hci0
BD_ADDR: 00:1A:7D:DA:71:13 */
/* Command line equivalent: */
/* hciconfig hci0 | grep "BD Address" */
}
A fixed address is a tracking problem. If a BLE device always broadcasts from the same address, any device within radio range can build a log of when and where that address appeared. Over time, this creates a detailed movement and behaviour profile of the device owner — without their knowledge or consent.
The shoe example from the spec: Imagine someone wearing BLE-enabled running shoes that constantly broadcast step count data. A stationary listener (a phone, a laptop, anything with a BLE radio) can passively record every packet from those shoes. Since the address is fixed, the listener can track the person’s entire route through a building, a mall, or a city — just by following the known address.
AA:BB:CC:11:22:33
loc: lobby
AA:BB:CC:11:22:33
loc: corridor
AA:BB:CC:11:22:33
loc: office
AA:BB:CC:11:22:33
FF:01:C3:A7:B2:44
20:DE:9F:55:C1:08
BLE solves this with three types of random address, each with different privacy levels and use cases. The intended receiver of the data (a paired device) is given a way to resolve the random address back to the real device using a shared key — so only the authorised recipient can link the transmissions together.
The device may generate a new static address each time it powers up, but the address cannot change while the device is running. This provides some privacy (the address changes between usage sessions) while maintaining consistency within a single session. The downside: any peer device that stored the old address cannot reconnect after a reboot.
A purely random address that changes periodically (typically every 15 minutes). Nobody — not even a bonded device — can determine the real identity of the device from this address. Maximum anonymity. Used when the device genuinely needs to be untrackable by anyone.
The address changes periodically, but bonded devices possess an Identity Resolving Key (IRK) that lets them cryptographically verify that the random address belongs to the same device they bonded with. Strangers cannot resolve the address. Only trusted bonded peers can. This is the most practical approach for devices like fitness trackers — the owner’s phone can always recognise the device, but nobody else can track it.
/* BlueZ handles random/resolvable addresses automatically */
/* You can see the address type when scanning: */
/* btmon output for an advertising device using RPA: */
/* > HCI Event: LE Meta Event (0x3e) */
/* LE Advertising Report (0x02) */
/* Address type: Random (0x01) <--- random! */
/* Address: 7D:A3:F1:22:C8:B0 */
/* (This is a resolvable private address — */
/* top 2 bits are 11 = RPA format) */
/* After bonding, BlueZ resolves RPAs automatically */
/* using stored IRKs. You see the real name/address */
/* in bluetoothctl even though the RPA changes. */
/* Check stored bonding keys: */
/* ls /var/lib/bluetooth/<your-adapter>/ */
/* Each subdirectory = one bonded device */
Chapter 8 Part 1 Complete
You understand the five Link Layer states, the roles in each state, and all three types of device addressing. Part 2 covers physical channels, the channel map, and adaptive frequency hopping.
