White List HCI, Resolving List HCI – ble tutorial

 

Host Flow, White List, Resolving List & Controller Info
Chapter 9 Sections 9.2.3–9.2.5 — Host Flow Control Commands, White List HCI, Resolving List HCI, Figure 9.6, Controller Information & Remote Information
Host Flow
Rarely used
White List
4 HCI commands
Resolving List
7 HCI commands
Max PDU (4.2)
251 bytes

Keywords:

BLE HCI host flow control BLE white list HCI commands BLE HCI resolving list 4.2 HCI_LE_Read_Peer_Resolvable_Address HCI_LE_Set_Address_Resolution_Enable BLE controller information HCI HCI_LE_Read_Maximum_Data_Length BLE remote information LE_Read_Remote_Used_Features

Continuing Section 9.2.3 — Host Flow Control

The previous file covered Controller Flow Control (data going host → controller) and the counter-based buffer management system. This file covers the remaining Host Flow Control commands (data going controller → host), the White List HCI commands used for device filtering, the Resolving List commands introduced in BLE 4.2 for controller-side privacy address resolution, Controller Information queries, and Remote Information commands.

9.2.3 — Host Flow Control Commands

Controlling Data Flow From Controller Back to the Host

Host flow control is the reverse of what was covered in section 9.2.2. While controller flow control prevents the host from overwhelming the controller’s buffers, host flow control prevents the controller from overwhelming the host’s buffers when sending received data upward.

In most implementations this is not needed — modern processors handle incoming BLE data easily. But a device with a very slow CPU or very limited RAM may genuinely need to pace the controller. The following commands make up this group:

Host_Buffer_Size_Command

The host uses this command to tell the controller how much buffer space the host itself has for incoming data. The host provides two values: the maximum size of ACL data packets it can receive, and how many ACL data packet slots it has. The controller uses this information to know how much data it can push up before the host’s buffers fill.

Set_Controller_To_Host_Flow_Control_Command

A simple on/off switch for the host flow control mechanism. By default, host flow control is disabled after HCI_Reset — the controller sends data upward as fast as it arrives. This command can enable ACL flow control, synchronous flow control, or both. Setting it to enabled instructs the controller to respect the host buffer limits reported by Host_Buffer_Size.

Host_Number_Of_Completed_Packets_Command

This is the host’s equivalent of the controller’s Number_Of_Completed_Packets_Event. When host flow control is enabled, the host sends this command to tell the controller how many packets it has finished processing. The controller uses this count to know it can send that many more packets to the host. This creates a two-way credit system — each side tells the other how many buffers have been freed.

Data_Buffer_Overflow_Event

Sent by the controller when the host has sent more data packets than the controller had free buffer slots — meaning the controller had to drop packets. This is an error condition. In a correctly written host, this event should never fire because the host is supposed to respect the buffer count from HCI_Read_Buffer_Size. Seeing this event in logs means there is a bug in the host’s flow control logic.

Set_Event_Mask

Not a flow control command in the traditional sense, but it is grouped here because it controls which events the controller will ever send to the host. It is a 64-bit bitmask — each bit corresponds to one event type. Setting a bit to 1 enables that event; setting it to 0 silences it forever. After HCI_Reset, a specific default mask is active. The host can narrow this further to avoid waking up for events it does not care about, saving CPU cycles.

Host Flow Control (When Enabled) — Two-Way Credit System
HOST CONTROLLER
Setup
Host_Buffer_Size (host has N slots)
Enable
Set_Controller_To_Host_Flow_Control (enable)
Radio receives incoming BLE data…
Receive data
HCI ACL Data Packets (up to N slots worth)
Host processes the data, frees buffer slots…
Signal freed
Host_Number_Of_Completed_Packets (M freed)
Controller now knows M more slots are available → sends M more packets
/* Host flow control setup with BlueZ (rarely needed)         */

/* Step 1: Tell controller about host buffers                 */
/* OGF=0x03, OCF=0x0033 = Host Buffer Size                   */
typedef struct {
    uint16_t acl_mtu;    /* max ACL packet size host can accept */
    uint8_t  sco_mtu;    /* max SCO packet size (0 for LE only) */
    uint16_t acl_max_pkt;/* max ACL packets host can buffer     */
    uint16_t sco_max_pkt;/* max SCO packets (0 for LE only)     */
} __attribute__((packed)) host_buffer_size_cp;

/* Step 2: Enable host flow control for ACL                   */
/* OGF=0x03, OCF=0x0031                                      */
/* Parameter: 0x01 = enable ACL flow control                  */

/* Step 3: After processing N received packets, notify controller */
/* OGF=0x03, OCF=0x0035 = Host Number Of Completed Packets    */
/* Parameter: list of (handle, count) pairs                   */

White List HCI Commands

Four Commands to Manage the Controller’s White List

The White List is a table inside the controller that stores device addresses. When a filter policy is active, the controller only processes advertising packets or connection requests from devices on this list. All four management commands are grouped under Host Flow Control in Table 9.1 because they relate to how the controller is configured to handle incoming traffic.

?
HCI_LE_Read_White_List_Size

Reads how many entries the controller’s white list can hold. This is controller-hardware-dependent — some chips support 8 entries, others support 32 or more. The host should always read this first to know how many devices it can add. Returns a single byte: the maximum number of entries.

CLR
HCI_LE_Clear_White_List

Removes all entries from the white list in one operation. The controller initialises the white list to empty automatically after HCI_Reset, so this command is used when the host needs to rebuild the list from scratch at any point during operation. Cannot be used when the white list is in use by a currently active advertising, scanning, or connection procedure.

ADD
HCI_LE_Add_Device_To_White_List

Adds a single device’s address to the white list. Parameters: address type (0=public, 1=random) and 6-byte Bluetooth address. The combination of both parameters uniquely identifies the entry. Adding the same address twice has no effect. Returns error if the list is full.

REM
HCI_LE_Remove_Device_From_White_List

Removes a specific device from the white list. Uses the same address type + address parameters as the Add command. The remaining entries in the list are unaffected. Returns an error if the specified device was not in the list.

/* White list management via BlueZ HCI                       */

/* Read capacity: OGF=0x08, OCF=0x000F                       */
hcitool cmd 0x08 0x000f
/* Returns: 1 byte = max entries (e.g. 0x08 = 8 entries)    */

/* Clear the white list: OGF=0x08, OCF=0x0010                */
hcitool cmd 0x08 0x0010

/* Add a device (public addr): OGF=0x08, OCF=0x0011          */
/* Parameters: addr_type (1 byte) + addr (6 bytes, reversed) */
/* Example: add AA:BB:CC:DD:EE:FF (public)                   */
hcitool cmd 0x08 0x0011 00 FF EE DD CC BB AA

/* Remove a device: OGF=0x08, OCF=0x0012                     */
hcitool cmd 0x08 0x0012 00 FF EE DD CC BB AA

/* Using bluetoothctl for white list (paired devices auto-added): */
/* [bluetooth]# trust AA:BB:CC:DD:EE:FF                       */

Resolving List HCI Commands (BLE 4.2)

Seven Commands — How the Host Configures Controller-Side Privacy

As explained in Chapter 8, BLE 4.2 moved private address resolution from the Host down into the Controller. For the Controller to resolve incoming Resolvable Private Addresses (RPAs) on its own, the Host must first provide the necessary keying material. The Host does this by populating the Controller’s Resolving List — a table of device identities, each containing an Identity Address and the Identity Resolution Key (IRK) pair for that device.

Seven HCI commands manage this resolving list:

HCI_LE_Add_Device_To_Resolving_List

The main setup command. The host calls this once for each bonded device. Parameters include: the peer’s identity address type and address, the peer’s IRK (16 bytes), and the local IRK (16 bytes) to use when generating this device’s own RPA for communications with this peer. Without this step, the controller cannot resolve addresses from that peer device.

HCI_LE_Remove_Device_From_Resolving_List

Removes the identity information for one specific peer device from the resolving list. Used when a device is un-bonded or its keys are invalidated. Parameters: peer address type and identity address.

HCI_LE_Clear_Resolving_List

Removes all entries from the resolving list at once. Equivalent to calling Remove for every entry. Used when rebuilding the list from scratch — for example after a factory reset of all bonded device data.

HCI_LE_Read_Resolving_List_Size

Returns the maximum number of device identity entries the controller can store. Like the white list, this is hardware-dependent. If the controller can hold fewer entries than the host has bonded devices, the host must prioritise which entries to load based on which devices are most likely to be encountered.

HCI_LE_Read_Peer_Resolvable_Address

Reads the current Resolvable Private Address that the controller is using for a specific peer device. Because the peer’s RPA rotates every 15 minutes, the host may need to ask the controller “what RPA is the peer currently using?” to populate the address field when creating a directed advertising packet aimed at that peer. Input: peer identity address. Output: the currently active RPA for that peer.

HCI_LE_Read_Local_Resolvable_Address

Reads the Resolvable Private Address that this device is currently using when communicating with a specific peer. Each peer relationship has its own local RPA (generated from the local IRK for that peer). This command takes the peer’s identity address as input and returns the local RPA currently active for that peer.

HCI_LE_Set_Address_Resolution_Enable

The master on/off switch for controller-side address resolution. After populating the resolving list with HCI_LE_Add_Device_To_Resolving_List, the host must call this command with parameter 0x01 to actually enable the resolution feature. The default after HCI_Reset is disabled (0x00). Only when enabled does the controller attempt to resolve incoming RPAs against its resolving list.

Figure 9.6 — Typical Usage of Resolving Lists

The typical sequence for setting up controller-side address resolution follows a clear order. Every step must be completed before the next one makes sense:

Figure 9.6 — Resolving List Setup Sequence
HOST CONTROLLER

HCI_LE_Read_Resolving_List_Size → finds capacity N

HCI_LE_Clear_Resolving_List → start clean

③×N
HCI_LE_Add_Device_To_Resolving_List (for each bonded device):
• peer identity addr type + addr
• peer IRK (16 bytes from bonding database)
• local IRK (16 bytes)

HCI_LE_Set_Address_Resolution_Enable (0x01 = enable)
Controller now resolves incoming RPAs independently — Host only wakes for known bonded devices
/* Complete resolving list setup in BlueZ C code             */

struct bonded_device {
    uint8_t addr_type;
    uint8_t addr[6];
    uint8_t peer_irk[16];
    uint8_t local_irk[16];
};

int setup_resolving_list(int hci_sock,
                          struct bonded_device *devices,
                          int count)
{
    /* Step 1: Disable resolution before modifying list      */
    uint8_t disable = 0x00;
    hci_send_cmd(hci_sock, OGF_LE_CTL,
                 OCF_LE_SET_ADDRESS_RESOLUTION_ENABLE,
                 1, &disable);

    /* Step 2: Clear existing list                           */
    hci_send_cmd(hci_sock, OGF_LE_CTL,
                 OCF_LE_CLEAR_RESOLVING_LIST, 0, NULL);

    /* Step 3: Add each bonded device                        */
    for (int i = 0; i < count; i++) {
        le_add_device_to_resolving_list_cp cp;
        cp.peer_identity_address_type = devices[i].addr_type;
        memcpy(cp.peer_identity_address, devices[i].addr, 6);
        memcpy(cp.peer_irk,  devices[i].peer_irk,  16);
        memcpy(cp.local_irk, devices[i].local_irk, 16);
        hci_send_cmd(hci_sock, OGF_LE_CTL,
                     OCF_LE_ADD_DEVICE_TO_RESOLVING_LIST,
                     sizeof(cp), &cp);
    }

    /* Step 4: Enable resolution                             */
    uint8_t enable = 0x01;
    return hci_send_cmd(hci_sock, OGF_LE_CTL,
                        OCF_LE_SET_ADDRESS_RESOLUTION_ENABLE,
                        1, &enable);
}

9.2.4 — Controller Information Commands

How the Host Discovers What the Controller Supports

These are all read-only queries that the host sends to find out what capabilities the controller hardware has. They are typically called during stack initialisation, right after HCI_Reset, so the host knows what features it can rely on.

HCI_Read_Local_Version_Information

Returns the HCI version, HCI revision, LMP/PAL version, manufacturer name, and LMP sub-version of the controller. The LMP version is the most useful field — it tells you whether the chip supports BLE at all. LMP version 6 = BT 4.0 (first BLE version), 7 = BT 4.1, 8 = BT 4.2. If the controller returns a version below 6, it is a classic-only chip with no LE capability.

HCI_Read_Local_Supported_Command

Returns a 64-byte bitmask (512 bits) where each bit indicates whether one specific HCI command is implemented by the controller. The host should check this before sending any command to avoid sending unsupported commands that would return an error. This is the definitive way to test for command support.

HCI_Read_Support_Features_Command

Returns the LMP feature bits for the controller — a bitmask indicating which LMP-level features are supported. For a dual-mode controller this covers both BR/EDR and LE features. The LE Host Supported bit and LE Supported bit in this mask indicate dual-mode capability.

HCI_LE_Read_Support_Features_Command

The LE-specific feature mask query. Returns the 64-bit FeatureSet bitmap we covered in the LLCP Feature Exchange section — bits 0–7 indicating LE Encryption, Connection Parameters Request, Extended Reject, Slave Feature Exchange, LE Ping, Data Length Extension, LL Privacy, and Extended Scanner Filters. Bit = 0 means not supported.

HCI_LE_Read_Supported_States

Returns a 64-bit bitmask of all the link layer state combinations this controller supports. For example, some lower-cost controllers may not support advertising while connected (a combination that is optional). The host checks this before attempting any multi-state operation to avoid errors.

HCI_LE_Read_Maximum_Data_Length BLE 4.2

Reads the absolute maximum PDU payload sizes and transmission times the controller’s hardware can handle. Returns four values: supportedMaxTxOctets, supportedMaxTxTime, supportedMaxRxOctets, supportedMaxRxTime. These are the hardware ceiling values — the actual connection negotiation during Data Length Update can only go up to these limits, not beyond them.

Controller Information — Typical Initialisation Query Sequence
HCI_Read_Local_Version_Information → check LMP version ≥ 6 (BLE capable)
HCI_Read_Local_Supported_Commands → bitmask of supported HCI commands
HCI_LE_Read_Local_Supported_Features → which LE features are available
HCI_LE_Read_Supported_States → which state combos are valid
HCI_LE_Read_Maximum_Data_Length → max PDU size supported (BLE 4.2 only)
Host now knows exactly what this controller can do → proceed with stack setup
/* Reading controller capabilities with BlueZ hcitool         */

/* Read version (check LMP version field):                    */
hcitool info           /* shows version, manufacturer, etc.  */

/* Check LE feature support:                                  */
/* OGF=0x08, OCF=0x0003 = LE Read Local Supported Features   */
hcitool cmd 0x08 0x0003
/* Returns 8 bytes LE feature bitmask:                        */
/* Byte 0: bit0=LE Enc, bit1=Conn Param Req, bit2=Ext Reject  */
/*         bit3=Slave Feat Req, bit4=LE Ping, bit5=Data Ext   */
/*         bit6=LL Privacy, bit7=Ext Scan Filter               */

/* Check max data length (BLE 4.2):                          */
/* OGF=0x08, OCF=0x002F = LE Read Maximum Data Length        */
hcitool cmd 0x08 0x002f
/* Returns: MaxTxOctets(2) MaxTxTime(2) MaxRxOctets(2) MaxRxTime(2) */

9.2.5 — Remote Information Commands

Finding Out What the Connected Peer Supports

While the Controller Information commands query the local device’s capabilities, the Remote Information commands query the remote (peer) device’s capabilities across an active connection. These are the HCI-layer equivalents of the LLCP Feature Exchange and Version Exchange procedures.

HCI_LE_Read_Remote_Used_Features

When the host calls this command with a connection handle, the controller initiates the LLCP Feature Exchange procedure with the remote device. The remote device sends back its FeatureSet bitmap. The host has no direct access to the link layer — it goes through this HCI command and gets the result via an event.

At present the FeatureSet only has meaningful content in the bits we covered in Chapter 8 (bits 0–7). The textbook notes that bit 0 (LE Encryption) is the main bit of interest — it tells the local host whether the remote side supports AES-128 encryption. Without this bit being set in the remote’s features, the host must not attempt to start encryption.

LE_Read_Remote_Used_Features_Complete Event

This event is generated asynchronously after the LLCP procedure completes and the peer has responded. It contains: the status (success or error), the connection handle, and the 8-byte FeatureSet received from the peer. The host reads the feature bits to decide what capabilities to enable for this connection.

Remote Features Query — HCI Commands Trigger LLCP Automatically
HOST
HCI CMD
Read Remote Features
LOCAL
CTRL
LLCP Feature Exchange initiated
REMOTE
DEVICE
LL_FEATURE_RSP
REMOTE
DEVICE
HOST
LE Meta Event
Read Remote Features Complete
(FeatureSet 8 bytes)
LOCAL
CTRL
/* Requesting remote LE features via BlueZ                   */
/* OGF=0x08, OCF=0x0016 = LE Read Remote Used Features       */
/* Parameter: connection handle (2 bytes)                    */

uint8_t params[2];
params[0] = conn_handle & 0xFF;
params[1] = (conn_handle >> 8) & 0xFF;
hci_send_cmd(hci_sock, OGF_LE_CTL,
             OCF_LE_READ_REMOTE_USED_FEATURES,
             2, params);

/* The result comes back as a LE Meta Event subevent 0x04:   */
/* EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE = 0x04          */
/* Payload: status(1) + handle(2) + LE_features(8)           */

/* Checking if remote supports encryption:                   */
/* if (le_features[0] & 0x01) → remote supports LE Encrypt  */

/* Using btmon to observe the exchange:                      */
/* sudo btmon | grep -A 10 "LE Remote Features"              */

Chapter 9 — Sections 9.2.3–9.2.5 Summary
Host Flow Control

  • Rarely needed in practice
  • Host_Buffer_Size: tell controller host capacity
  • Set_Ctrl_To_Host_Flow_Ctrl: enable/disable
  • Host_Num_Completed: free slots signal
  • Data_Buffer_Overflow: error event
White & Resolving Lists

  • WL: Read Size, Clear, Add, Remove
  • RL: Add (identity addr + IRKs)
  • RL: Remove, Clear, Read Size
  • RL: Read Peer/Local RPA
  • Set_Address_Resolution_Enable
Controller Information

  • Read_Local_Version → LMP version
  • Read_Supported_Commands → 512-bit mask
  • LE_Read_Local_Supported_Features
  • LE_Read_Supported_States
  • LE_Read_Maximum_Data_Length (4.2)
Remote Information

  • LE_Read_Remote_Used_Features
  • Triggers LLCP Feature Exchange
  • Result via LE Meta Event 0x04
  • Key check: bit 0 = remote supports encryption

Chapter 9 HCI Series — Both Files
📋

PDF 13 (Chapter 9)

Table 9.1 Continued, HCI_Reset, Controller Flow Control, Data Flow Diagram

PDF 46 (Chapter 9) — Here

Host Flow, White List, Resolving List, Figure 9.6, Controller Info, Remote Info

Chapter 9 HCI Sections Complete

You now have the full Chapter 9 HCI coverage — every command group, every packet format, the data flow control diagram, White List and Resolving List management, and all controller information queries.

← PDF 13: Table 9.1, Reset & Controller Flow

Leave a Reply

Your email address will not be published. Required fields are marked *