0x08
Code 0x3E
HCI_LE_*
LE HCI only
9.1 — What Is the HCI and Why Does It Exist?
In most Bluetooth implementations the software and the radio hardware live on two separate chips. The host is the main application processor — a CPU running an operating system, the Bluetooth host stack, and the application. The controller is a dedicated Bluetooth chip that handles the radio, the link layer, and the physical layer.
These two chips need to talk to each other. The Host Controller Interface (HCI) is the standardised protocol that defines exactly how they communicate — what commands the host can send to the controller, what events the controller sends back to the host, and how data packets flow between them. Without a standard interface, every Bluetooth chip would need its own custom driver.
HCI sits between the upper and lower layers of the BLE protocol stack. Everything from L2CAP upward runs in software on the host. Everything from the Link Layer downward runs in firmware on the controller. HCI is the bridge between them.
Rather than designing a completely new HCI for BLE, the specification reused the existing HCI from classic BR/EDR Bluetooth and extended it with LE-specific commands and events. This decision had three major benefits for developers and manufacturers:
All the code already written to handle the HCI layer in BR/EDR implementations can be used directly with LE. The routines that transmit commands, receive events, transmit data packets, and receive data packets are completely identical. Only the new LE-specific command and event opcodes need to be added on top. A developer who has already built a BR/EDR Bluetooth host stack gets BLE HCI support with a fraction of the work.
A controller that supports dual mode (both BR/EDR and BLE) is fully backward compatible with the BR/EDR controller it replaces. Any product that was working with a BR/EDR-only chip can have that chip swapped for a dual mode chip without breaking any existing BR/EDR functionality. The host software does not need to be modified for the BR/EDR side at all.
When a product upgrades from a BR/EDR-only controller to a dual mode controller, absolutely no software changes are needed for the existing BR/EDR functionality. The existing driver, command handling, and event processing code all continue to work exactly as before. Only new code to handle the LE-specific commands and events needs to be added.
9.1.1 — HCI Packet Types
Three types of packets travel across the HCI interface. Two are used exactly as in BR/EDR. One is slightly modified for LE. One BR/EDR packet type is absent entirely from LE.
HCI Command Packet
Host → Controller. Format is identical to BR/EDR. Only the OGF value and specific OCF opcodes differ for LE commands.
HCI Event Packet
Controller → Host. Slightly enhanced for LE — all LE events use a single new event code (LE Meta Event = 0x3E) with a sub-event code inside.
HCI ACL Data Packet
Bidirectional. Format is identical to BR/EDR. All L2CAP data for LE connections travels in these packets.
SCO/eSCO Packets
Not supported in LE. SCO was designed for synchronous voice audio in BR/EDR. LE has no equivalent and does not need it.
9.1.2 — HCI Command Packet Format
Every HCI command has a 16-bit OpCode that identifies which command it is. The OpCode is split into two sub-fields: the upper 6 bits form the OGF (Opcode Group Field) and the lower 10 bits form the OCF (Opcode Command Field).
The OGF groups commands by category. For all BLE-specific commands, the OGF is always 0x08. This is how the controller knows whether an incoming command is a BR/EDR command or an LE command — it checks the OGF first.
[9:0]
[15:10]
(0 to 255 bytes)
/* Sending a raw HCI command with BlueZ hcitool */
/* Format: hcitool cmd OGF OCF [parameters...] */
/* Example: LE Set Advertise Enable */
/* OGF=0x08, OCF=0x000A, param: 0x01=enable */
hcitool cmd 0x08 0x000a 01
/* Example: LE Set Scan Enable */
/* OGF=0x08, OCF=0x000C, params: enable, filter */
hcitool cmd 0x08 0x000c 01 00
/* Programmatic: building an HCI command in C */
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
/* Every LE command uses OGF_LE_CTL = 0x08 */
/* OCF values are defined in hci.h as */
/* OCF_LE_SET_ADVERTISE_ENABLE = 0x000A */
/* OCF_LE_SET_SCAN_ENABLE = 0x000C */
/* OCF_LE_CREATE_CONN = 0x000D */
/* OCF_LE_SET_ADVERTISING_DATA = 0x0008 */
9.1.3 — HCI Event Packet — The LE Meta Event
In BR/EDR, each different event type has its own unique event code. If you wanted to catch a “Connection Complete” event you would look for event code 0x03. If you wanted “Inquiry Complete” it would be event code 0x01. Every event had its own code in a flat namespace.
For BLE, rather than consuming many new event codes in that same namespace, the specification reserved a single event code 0x3E — the LE Meta Event — and put all LE events inside it. Inside the LE Meta Event, a Subevent Code identifies exactly which LE event occurred. The remaining bytes after the subevent code are the event-specific parameters.
/* Catching LE Meta Events in BlueZ C code */
/* All LE events share event code HCI_LE_META_EVENT = 0x3E */
#define HCI_LE_META_EVENT 0x3e
/* Subevent codes (defined in hci.h): */
#define EVT_LE_CONN_COMPLETE 0x01 /* Connection done */
#define EVT_LE_ADVERTISING_REPORT 0x02 /* ADV packet seen */
#define EVT_LE_CONN_UPDATE_COMPLETE 0x03 /* Params updated */
#define EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
#define EVT_LE_LTK_REQUEST 0x05 /* Key needed */
/* Parsing an HCI event in a filter loop: */
hci_filter_set_event(HCI_LE_META_EVENT, &filter);
read(hci_sock, &buf, sizeof(buf));
evt_le_meta_event *meta = (void *)(buf + HCI_EVENT_HDR_SIZE + 1);
switch (meta->subevent) {
case EVT_LE_CONN_COMPLETE:
printf("LE connection established\n");
break;
case EVT_LE_ADVERTISING_REPORT:
printf("LE advertising report received\n");
break;
}
9.1.4 — HCI ACL Data Packet
ACL (Asynchronous Connection-Less) data packets carry the actual application data between host and controller. The format for LE is identical to BR/EDR — the same field structure, the same connection handle field, and the same Packet Boundary (PB) and Broadcast (BC) flag bits.
All the data that flows between the L2CAP layer on the host and the link layer on the controller travels in these ACL packets. GATT notifications, ATT reads and writes, Security Manager pairing messages — all of it goes through HCI ACL packets.
9.2 — Table 9.1 — All LE-Related HCI Commands and Events
Before looking at the table, here is the naming logic:
HCI_LE_*
Commands that are only for LE. These do not exist in BR/EDR and are always rejected by a BR/EDR-only controller.
HCI_*
Commands shared by both BR/EDR and LE. These work the same way on both types of controller, though their meaning may expand slightly with LE.
LE_*
Events specific to LE only. Events without the LE prefix apply to both BR/EDR and LE controllers.
Commands and events introduced in specs 4.1 and 4.2 are shown in italics in the original textbook’s Table 9.1. In the table below they are highlighted in colour.
| Group | Commands | Events |
|---|---|---|
| Device Setup | HCI_Reset |
— |
| Controller Flow Control | HCI_Read_Buffer_SizeHCI_LE_Read_Buffer_Size |
Number_Of_Completed_Packets_Event |
| Host Flow Control | HCI_Host_Buffer_SizeHCI_Set_Event_MaskHCI_Set_Controller_To_Host_Flow_ControlHCI_Host_Number_Of_Completed_PacketsHCI_LE_Set_Event_MaskHCI_LE_Add_Device_To_White_ListHCI_LE_Clear_White_ListHCI_LE_Read_White_List_SizeHCI_LE_Remove_Device_From_White_ListHCI_LE_Add_Device_To_Resolving_ListHCI_LE_Remove_Device_From_Resolving_ListHCI_LE_Clear_Resolving_ListHCI_LE_Read_Resolving_List_SizeHCI_LE_Read_Peer_Resolvable_AddressHCI_LE_Read_Local_Resolvable_AddressHCI_LE_Set_Address_Resolution_Enable |
Data_Buffer_Overflow_Event |
| Controller Information | HCI_Read_Local_Version_InformationHCI_Read_Local_Supported_CommandsHCI_Read_Local_Supported_FeaturesHCI_LE_Read_Local_Supported_FeaturesHCI_LE_Read_Supported_StatesHCI_LE_Read_Maximum_Data_Length |
— |
| Remote Information | HCI_Read_Remote_Version_InformationHCI_LE_Read_Remote_Used_Features |
Read_Remote_Version_Information_CompleteLE_Read_Remote_Used_Features_Complete |
| Controller Configuration | HCI_LE_Set_Advertise_EnableHCI_LE_Set_Advertising_DataHCI_LE_Set_Advertising_ParametersHCI_LE_Set_Random_AddressHCI_LE_Set_Scan_Response_DataHCI_Read_LE_Host_SupportHCI_Write_LE_Host_SupportHCI_LE_Set_Resolvable_Private_Address_Timeout |
— |
| Device Discovery | HCI_LE_Set_Scan_EnableHCI_LE_Set_Scan_Parameters |
LE_Advertising_Report_EventLE_Direct_Advertising_Report_Event |
| Connection Setup | HCI_DisconnectHCI_LE_Create_Connection_CancelHCI_LE_Create_Connection |
Disconnect_Complete_EventLE_Connection_Complete_EventLE_Enhanced_Connection_Complete_Event |
/* Quick reference — most commonly used LE HCI commands */
/* Start advertising: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, ...);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, ...);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, 1_byte);
/* Start scanning: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, ...);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, 2_bytes);
/* Create a connection: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_CREATE_CONN, ...);
/* Wait for LE_Connection_Complete meta event (subevent 0x01) */
/* Disconnect: */
hci_send_cmd(sock, OGF_LINK_CTL, OCF_DISCONNECT, 3_bytes);
/* Wait for Disconnect_Complete event */
/* Check controller capabilities: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_READ_LOCAL_SUPPORTED_FEATURES, 0);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_READ_SUPPORTED_STATES, 0);
Chapter 9 Introduced — HCI Commands Reference Complete
You now understand the HCI layer fully — where it sits, why it was reused from BR/EDR, all three packet types, and the complete command table. The next chapters go deeper into specific command groups and how the host uses them to drive device discovery, connection setup, and data transfer.
