40 seconds
30 seconds
Master wins
4 per direction
Where We Are — Section 8.12.7 Continued
The previous file introduced the Connection Parameters Request procedure — the BLE 4.1 addition that lets either the Master or the Slave request a parameter change. This file covers how the receiving device can respond with alternative parameters instead of simply accepting or rejecting, then moves to two more 4.1/4.2 procedures (LE Ping and Data Length Update), followed by the rules governing procedure management in Section 8.13, and opens Section 8.14 on Link Layer Privacy.
8.12.7 — Connection Parameters Request (Continued)
The LL_CONNECTION_PARAM_REQ PDU can request changes to these three connection timing parameters:
Time between connection events. Shorter = more responsive, higher power. Longer = lower power, higher latency.
How many connection events the Slave may skip. Higher value = more battery saving for Slave.
Maximum time without a received packet before declaring the connection lost.
When a device receives a LL_CONNECTION_PARAM_REQ, it has three options. This three-way choice is more flexible than the older Connection Update procedure where the Slave had no say at all.
(proposed connInterval, latency, timeout)
Master may now issue LL_CONNECTION_UPDATE_REQ to apply the agreed-upon parameters.
Why alternative parameters matter: The receiving device may not be able to accept the exact interval or latency requested. For example, the Master might be managing multiple Slave connections and the requested interval would conflict with existing scheduled connection events. Rather than simply rejecting the request, the Master can propose a nearby interval that fits its schedule. The original requester then receives a workable compromise instead of a flat refusal.
/* Checking connection parameters on a live BLE connection */
/* Using BlueZ hcitool to see current parameters: */
/* hcitool con (lists all current connections) */
/* Output shows handle, role, and current parameters */
/* Requesting a parameter update from Central side: */
/* hcitool lecup --handle 0x0040 */
/* --min 0x0064 --max 0x0064 */
/* --latency 2 --timeout 0x00C8 */
/* min/max 0x0064 = 100 × 1.25ms = 125ms interval */
/* latency 2 = Slave may skip 2 events between responds */
/* timeout 0xC8 = 200 × 10ms = 2000ms supervision */
/* Using bluetoothctl for interactive param negotiation: */
/* [bluetooth]# menu gatt */
/* [bluetooth]# list-attributes AA:BB:CC:DD:EE:FF */
8.12.8 — LE Ping Procedure (BLE 4.1)
Anyone who has used a Linux terminal is familiar with the ping command — you type ping 192.168.1.1 and if that device is reachable, it responds. You know the connection is alive. The BLE LE Ping procedure does the same thing at the Link Layer level.
BLE 4.1 introduced LL_PING_REQ and LL_PING_RSP for two related purposes:
Purpose 1 — Verify Presence
Check that the remote link layer is still alive and able to receive and respond to requests. If a peer device has crashed, run out of battery, or moved completely out of range, its link layer will not respond to the ping. This gives the local device early confirmation that the peer is gone rather than waiting for the full supervision timeout.
Purpose 2 — Verify Message Integrity (MIC)
On an encrypted connection, request the remote device to reply with a packet containing a valid MIC (Message Integrity Check). Receiving a packet with a valid MIC confirms that the encryption is working correctly on both sides — keys are matching and the encryption engine is functioning.
Who can initiate: Either the Master or the Slave. This makes LE Ping symmetric — both sides have equal ability to check on the health of the link. If the remote link layer does not recognise the PING command (e.g. a BLE 4.0 device that pre-dates the 4.1 specification), it responds with LL_UNKNOWN_RSP instead of LL_PING_RSP.
(device is alive)
(BLE 4.0 device)
(device is gone)
The LE Ping procedure works hand-in-hand with the Authenticated Payload Timeout introduced in Section 8.13.3. If no authenticated packet (one with a valid MIC) has been received within that timeout window, the link layer automatically triggers a LE Ping to force the peer to send an authenticated response. This prevents the encrypted connection from becoming stale without either side noticing.
/* LE Ping is handled automatically by the BLE controller */
/* in firmware when Authenticated Payload Timeout is active */
/* You can observe LE Ping events in btmon: */
/* sudo btmon | grep -i "ping" */
/* The HCI LE Ping command lets the host set the timeout: */
/* OGF=0x08, OCF=0x0023 = LE Write Authenticated Payload TO */
typedef struct {
uint16_t handle; /* connection handle */
uint16_t auth_payload_to; /* timeout in units of 10ms */
/* default = 3000 (30 seconds) */
} __attribute__((packed)) le_write_auth_payload_to_cp;
/* Reading the current authenticated payload timeout: */
/* OGF=0x08, OCF=0x0024 = LE Read Authenticated Payload TO */
8.12.9 — Data Length Update Procedure (BLE 4.2)
BLE 4.2 introduced the ability to use PDU payloads up to 251 bytes (up from the original 27 bytes). However, two devices must first agree that both sides support and can handle the larger packets. They do this using the Data Length Update procedure via LL_LENGTH_REQ and LL_LENGTH_RSP.
The procedure communicates four parameters in each direction — two for receiving and two for transmitting. Each side tells the other what it is capable of, and both sides then operate within the agreed limits.
connMaxRxOctets
Maximum number of bytes in the payload of a data channel PDU I can receive. Range: 27–251 bytes (BLE 4.2+).
connMaxRxTime
Maximum time in microseconds I need to receive a data channel PDU. Sender must not transmit for longer than this. Range: 328–2120 µs.
connMaxTxOctets
Maximum number of bytes in the payload of a data channel PDU I will transmit. The sender must not exceed the receiver’s connMaxRxOctets limit.
connMaxTxTime
Maximum time in microseconds my transmitted PDU will occupy the air. The other side uses this to know how long to keep its receiver on.
(MaxRxOctets, MaxRxTime, MaxTxOctets, MaxTxTime)
(remote’s MaxRxOctets, MaxRxTime, MaxTxOctets, MaxTxTime)
Dynamic adjustment example: Consider a device whose RX buffer starts filling up because data is arriving faster than it can be processed. It can send an updated LL_LENGTH_REQ informing the peer that its connMaxRxOctets has decreased — effectively telling the other side “please send smaller packets for now.” Once the buffer is cleared, it sends another update increasing the limit back up. This prevents buffer overflows without dropping the connection.
/* Data Length Update using BlueZ HCI commands */
/* LE Set Data Length: OGF=0x08, OCF=0x0022 */
typedef struct {
uint16_t handle; /* connection handle */
uint16_t tx_octets; /* preferred max TX octets (27–251) */
uint16_t tx_time; /* preferred max TX time in µs */
} __attribute__((packed)) le_set_data_len_cp;
/* Example: request 200-byte packets for faster data transfer */
le_set_data_len_cp cp = {
.handle = htobs(conn_handle),
.tx_octets = htobs(200), /* 200-byte PDU payload */
.tx_time = htobs(1712), /* time for 200 bytes @ 1M */
};
hci_send_cmd(sock, OGF_LE_CTL,
OCF_LE_SET_DATA_LEN,
sizeof(cp), &cp);
/* btmon shows the negotiation: */
/* > HCI Command: LE Set Data Length (0x08|0x0022) plen 6 */
/* > HCI Event: LE Meta Event — LE Data Length Change */
/* Max TX Octets: 200 */
/* Max TX Time: 1712 us */
/* Max RX Octets: 251 */
/* Max RX Time: 2120 us */
8.13 — Management of Link Layer Procedures
Running LLCP procedures over a wireless link introduces practical challenges. Devices can move out of range. Bugs can cause a device to stop responding. Both sides might try to change the same parameter at the same time. Section 8.13 defines the rules that handle all of these situations.
When a link layer sends a control PDU (any LLCP request) and waits for a response, there is no guarantee the response will ever arrive. The peer device may have:
- Moved out of radio range
- Run out of battery mid-procedure
- Crashed due to a software bug
- Entered a state where it cannot process the request
To handle this, BLE defines a procedure response timeout of 40 seconds. If no response arrives within 40 seconds of sending a control PDU, the local link layer concludes the connection is lost, closes the connection, and notifies the host.
Because Master and Slave operate independently, it is possible for both sides to initiate the same procedure (or two procedures that modify the same parameters) at almost the same time. For example, the Master might send a LL_CONNECTION_UPDATE_REQ to change the connection interval at the same moment the Slave sends a LL_CONNECTION_PARAM_REQ to request the same kind of change.
This creates a collision — both sides are now running a procedure that would update the same parameters. The rule is simple and deterministic: the Master’s procedure always has priority.
LL_CONNECTION_UPDATE_REQ
LL_CONNECTION_PARAM_REQ
The Master rejects the Slave’s colliding procedure using LL_REJECT_IND or LL_REJECT_IND_EXT. The Slave’s procedure is cancelled. The Slave can re-attempt its request after the Master’s procedure completes.
An authenticated packet is a packet that contains a valid MIC (Message Integrity Check) — meaning it was properly encrypted and the integrity check was computed correctly with the current session key. On an encrypted connection, all data packets carry a MIC. However, if encryption is paused or if there is some problem with the encryption session, authenticated packets could stop arriving.
BLE 4.1 introduced a maximum time interval within which an authenticated packet must be received from the peer. If this timer is about to expire and no authenticated packet has arrived, the link layer proactively sends a LL_PING_REQ to force the peer to send an authenticated response.
The default value of 30 seconds gives enough time for normal quiet periods on the connection without triggering unnecessary pings, while still catching any situation where the encryption session has silently broken down. The timeout can be adjusted via the HCI command if a shorter or longer window is appropriate for the application.
8.14 — Link Layer Privacy 1.2 (Introduction)
Many BLE devices are designed to be carried on or near the body — fitness trackers, smartwatches, heart rate monitors, smart shoes, glucose sensors. Because these devices constantly broadcast advertising packets, and because each device has a Bluetooth address, a passive observer with a BLE sniffer can build a very detailed picture of someone’s movements and habits by simply logging which addresses appear where and when.
This is not a hypothetical concern. The technology to do passive BLE tracking is cheap and widely available. A person’s Bluetooth address appearing at a gym, a medical clinic, a specific coffee shop, and a home address can reveal daily routines, health conditions, and personal relationships without the person doing anything wrong and without their knowledge or consent.
BLE 4.2 introduced Link Layer Privacy 1.2 — a set of mechanisms that prevent this tracking. The full details of how LL privacy works are covered in the next section, but the fundamental idea is that a device regularly changes the Bluetooth address it uses for advertising, making it impossible for a passive observer to link two different advertising packets from the same device together over time.
The paired device (the user’s phone) can still resolve these rotating addresses back to the same known device using a shared Identity Resolving Key (IRK) stored from the original bonding. But any third-party observer — even with a professional BLE sniffer — sees only unrelated random addresses and cannot build a movement profile. The full mechanism of how IRKs and Resolvable Private Addresses (RPAs) work is covered in Section 8.14 which continues in the next chapter.
/* Enabling LL Privacy on a BLE controller via BlueZ */
/* Requires BLE 4.2 controller (feature bit 6 set) */
/* Using bluetoothctl: */
/* [bluetooth]# advertise on */
/* The controller automatically uses RPA if */
/* supported and the device is bonded */
/* HCI LE Set Address Resolution Enable: */
/* OGF=0x08, OCF=0x002D */
typedef struct {
uint8_t enable; /* 0x00 = disable, 0x01 = enable */
} le_set_addr_res_enable_cp;
/* HCI LE Set Resolvable Private Address Timeout: */
/* OGF=0x08, OCF=0x002E */
/* Default RPA rotation: every 15 minutes (900s) */
typedef struct {
uint16_t rpa_timeout; /* in seconds, 1 – 65535 */
} le_set_rpa_timeout_cp;
- Either side can initiate
- Receiver can counter-propose
- 3 responses: accept, alternative, reject
- Master applies final change
- Either side can initiate
- Verify peer is alive
- Verify MIC on encrypted link
- BLE 4.0 replies LL_UNKNOWN_RSP
- Either side can initiate
- 4 params each: RxOct, RxTime, TxOct, TxTime
- Dynamic size changes mid-connection
- Prevents buffer overflow
- Response timeout: 40s
- Collision rule: Master wins
- Auth payload timeout: 30s
- Ping auto-fired on timeout
Chapter 8 Link Layer — Fully Complete!
All LLCP procedures are now covered end to end. Section 8.14 Link Layer Privacy continues with the full Resolvable Private Address mechanism in the next chapter.
