Change key without drop
8 defined (bits 0–7)
Encryption only
Data Ext, Privacy
Continuing Section 8.12.3 — Encryption
The previous file introduced Encryption Start — enabling AES-128 on a previously unencrypted connection. This file covers what happens when you need to change the encryption key while the connection stays alive (Encryption Pause), and why you would want to do that. It then covers the Feature Exchange procedure and the Feature Set bitmap that lists every optional BLE capability a device may or may not implement.
8.12.3.2 — Encryption Pause and Encryption Restart
After a connection is encrypted, there may be a reason to switch to a different encryption key. The naive approach — disconnect, re-pair with a new key, reconnect — is disruptive and slow. The Encryption Pause procedure avoids this by suspending encryption temporarily, swapping the key, and then restarting encryption with the new key, all without closing the connection.
The steps are:
- Run the Encryption Pause procedure — pauses the encrypted mode
- Both sides exchange the new LTK through their respective hosts
- Run the Encryption Start procedure (as covered previously) — restarts encryption with the new key
The Encryption Pause + Restart combination is particularly valuable when a connection needs to change its security level dynamically. Here is a concrete scenario:
A medical device connects to a patient monitoring app with a standard 128-bit LTK. General status updates (battery level, device ID) flow over this link. The connection is encrypted but uses a key of normal strength.
The app is about to transmit medication dosage instructions or patient records. This data requires a higher level of security — a stronger key derived through additional authentication steps.
The Encryption Pause procedure is used to briefly pause the current encryption. The new, stronger LTK is loaded. Encryption restarts with the new key. The medical data now flows at the higher security level — all without any visible interruption or disconnection from the user’s perspective.
/* Reading BLE encryption status from BlueZ HCI */
/* Checks if a specific connection is currently encrypted */
#include <bluetooth/hci.h>
/* After Encryption Change event (event code 0x08): */
/* evt_encrypt_change.encrypt values: */
/* 0x00 = encryption disabled (paused) */
/* 0x01 = AES-128 CCM encryption enabled */
typedef struct {
uint8_t status;
uint16_t handle;
uint8_t encrypt; /* 0=off, 1=on */
} __attribute__((packed)) evt_encrypt_change;
/* Monitor encryption events with btmon: */
/* sudo btmon | grep -A 5 "Encryption Change" */
8.12.4 — Feature Exchange Procedure
The BLE specification defines many optional features. A device is not required to implement all of them. Two devices that connect may have different sets of capabilities, and they need a way to discover what the other side supports so they do not try to use a feature the peer cannot handle.
The Feature Exchange procedure solves this. It exchanges a FeatureSet bitmap — a 64-bit value where each bit represents one optional feature. The meaning of each bit is different depending on the direction of exchange:
Bit = 0 means the feature is not supported by this controller. The host uses this to know which features are available on its own hardware before trying to use them.
Bit = 1 means the controller allows the feature to be used. The peer reads this to know what capabilities are available for the connection.
Who can start it: In BLE 4.0, only the Master can initiate the feature exchange after connection is established. BLE 4.1 extended this — the Slave can also initiate using the new LL_SLAVE_FEATURE_REQ PDU.
BLE 4.0 defined only one feature bit (encryption). BLE 4.1 and 4.2 progressively added new feature bits for new capabilities. Understanding this evolution explains why you may encounter devices that do not respond to certain procedures — they simply report that bit as 0.
Whether this device supports AES-128 encryption on LE links. Valid in both directions (Controller→Host and Controller→Peer). In 4.0 this was the only feature bit; bits 1–63 were reserved.
The Slave can now request connection parameter changes using LL_CONNECTION_PARAM_REQ instead of waiting for the Master to update. Valid both directions.
Support for LL_REJECT_IND_EXT, which includes an error code explaining why a request was rejected (instead of just rejecting silently). Valid both directions.
The Slave can send LL_SLAVE_FEATURE_REQ to ask the Master’s feature set (previously only the Master could initiate feature exchange). Valid both directions.
Support for LL_PING_REQ/RSP — a way to verify the remote link layer is still alive. Valid Controller→Host only (not peer-to-peer), because the purpose is local controller health checks.
Support for the LL_LENGTH_REQ/RSP procedure allowing PDU payloads up to 251 bytes (from the original 27 bytes). Valid both directions. Essential for OTA updates and bulk data transfers.
Support for link layer privacy — the controller can automatically resolve Resolvable Private Addresses (RPAs) using stored IRKs, without involving the host. Valid Controller→Host only (not peer-to-peer).
Support for enhanced scanning filter options, including filtering based on RPAs. Valid Controller→Host only.
Devices must set RFU bits to 0 when sending. Receivers must ignore RFU bits. This forward compatibility means future BLE versions can add features without breaking existing devices.
/* Reading local BLE features via BlueZ HCI */
/* LE Read Local Supported Features: OGF=0x08, OCF=0x0003 */
/* Command line: */
/* hcitool cmd 0x08 0x0003 */
/* Returns 8 bytes of feature flags */
/* Feature bit masks from BlueZ hci.h: */
#define LMP_LE_ENCRYPTION 0x000000000001ULL /* bit 0: 4.0 */
#define LMP_CONN_PARAM_REQ 0x000000000002ULL /* bit 1: 4.1 */
#define LMP_EXT_REJECT 0x000000000004ULL /* bit 2: 4.1 */
#define LMP_SLAVE_FEAT_REQ 0x000000000008ULL /* bit 3: 4.1 */
#define LMP_LE_PING 0x000000000010ULL /* bit 4: 4.1 */
#define LMP_LE_DATA_LEN_EXT 0x000000000020ULL /* bit 5: 4.2 */
#define LMP_LL_PRIVACY 0x000000000040ULL /* bit 6: 4.2 */
#define LMP_EXT_SCAN_FILTER 0x000000000080ULL /* bit 7: 4.2 */
/* Check if local controller supports data length extension: */
uint64_t features;
hci_le_read_local_supported_features(sock, &features, 1000);
if (features & LMP_LE_DATA_LEN_EXT)
printf("Data length extension supported\n");
else
printf("Data length extension NOT supported (BLE 4.0 device)\n");
Next — Feature Set Bit Table, Version Exchange & Termination
The next file covers the complete feature set bit mapping table (Table 8.6), Version Exchange, Termination, and the Connection Parameters Request procedure added in BLE 4.1.
Next: Feature Table, Version Exchange, Termination (PDF 1920) → ← PDF 1315
