2. Linux 内核蓝牙子系统架构:BlueZ 协议栈全景

BlueZ 是 Linux 官方蓝牙协议栈,自 Linux 2.4.6 起被纳入主线内核。它采用内核空间 + 用户空间双层架构,将实时性要求高的底层协议(HCI、L2CAP)放在内核态,将灵活性强的高层协议(RFCOMM、GATT)及配置文件放在用户态。这种分工既保证了蓝牙通信的实时响应,又降低了内核模块的复杂度。

架构核心原则:内核只做“数据搬运与链路管理”,用户空间负责“协议解析与业务逻辑”。
BlueZ 协议栈架构图 BlueZ 协议栈架构图 用户空间 (User Space) 应用程序 GATT 配置文件 RFCOMM 服务 BlueZ 工具集 • 高层协议实现:GATT、RFCOMM、SDP • 通过 Socket 或 D-Bus 与内核通信 • 配置文件(Profile)注册与事件回调 内核空间 (Kernel Space) L2CAP 层 HCI 层 蓝牙驱动 硬件 • 底层协议:HCI 命令/事件、L2CAP 分段重组 • 通过 netlink/socket 向用户空间暴露接口 • 蓝牙控制器(UART/USB/SDIO)驱动适配

2.1 内核空间与用户空间的分工

BlueZ 将协议栈切分为两个域,通过 Socket 接口(AF_BLUETOOTH)和 D-Bus 进行跨域通信。下表列出了各层归属与职责边界:

域 包含层/模块 主要职责 通信方式
用户空间 应用程序、GATT 配置文件、RFCOMM 服务、SDP、BlueZ 工具(bluetoothd、bluetoothctl) 高层协议解析、配置文件注册、用户交互、策略控制 D-Bus(bluetoothd 提供 org.bluez 接口)
内核空间 HCI 层、L2CAP 层、蓝牙设备驱动(hci_uart、btusb 等) HCI 命令/事件处理、L2CAP 信道管理、数据帧收发、硬件控制 Socket(AF_BLUETOOTH)、Netlink
设计考量:将 L2CAP 放在内核态是因为它需要处理实时性高的分段重组(SAR)和重传;而 RFCOMM 和 GATT 放在用户态,便于灵活升级协议版本和配置文件,无需重新编译内核。

2.2 HCI 层(Host Controller Interface)

HCI 层是蓝牙协议栈的基石,位于主机(Host)与蓝牙控制器(Controller)之间。它定义了标准的命令、事件和数据包格式,屏蔽了底层传输介质(UART、USB、SDIO)的差异。

HCI 层结构图 HCI 层结构图 主机 (Host) HCI 核心层 (hci_core) HCI 传输层 (hci_uart/hci_usb) 控制器 (Controller) 固件 HCI 接口 蓝牙射频硬件 HCI 命令/事件/数据

HCI 层在内核中由 net/bluetooth/hci_core.c 实现,核心数据结构包括:

  • hci_dev:代表一个蓝牙控制器,包含设备状态、缓冲队列、命令发送等待队列。
  • hci_conn:代表一条 ACL 或 SCO 连接,管理连接状态与链路参数。
  • hci_cb:回调函数表,供上层 L2CAP 注册接收数据回调。
关键接口:HCI 层向上层提供 hci_send_cmd()、hci_recv_frame()、hci_conn_enter_active_mode() 等核心 API。

2.3 L2CAP 层(Logical Link Control and Adaptation Protocol)

L2CAP 位于 HCI 之上,提供逻辑信道复用、分段重组(SAR)、服务质量(QoS)控制等功能。它是所有高层协议(RFCOMM、GATT、SDP)的传输基础。

功能 说明 内核实现文件
信道复用 通过 CID(Channel ID)区分不同上层协议的数据流 net/bluetooth/l2cap_core.c
分段重组 将大于 HCI 数据包 MTU 的 L2CAP SDU 拆分为多个 HCI ACL 数据包 net/bluetooth/l2cap_core.c
重传与流控 支持 ERTM(Enhanced Retransmission Mode)和 Streaming Mode net/bluetooth/l2cap_core.c
连接管理 处理连接请求、配置参数、断开连接等信令 net/bluetooth/l2cap_sock.c
L2CAP 层协议栈 L2CAP 层协议栈 上层协议:RFCOMM | GATT | SDP | BNEP L2CAP 层:信道管理 + 分段重组 + 流控 HCI 层:ACL 数据包收发
常见陷阱:L2CAP 的 MTU 协商必须在连接建立阶段完成。如果上层协议(如 GATT)未正确协商 MTU,可能导致数据包被丢弃或连接异常断开。内核日志中常见的 l2cap_sock_recvmsg: sock len 0 错误往往与此相关。

2.4 RFCOMM 层(Radio Frequency Communication)

RFCOMM 是一个串口仿真协议,它在 L2CAP 之上模拟 RS-232 串行接口,使得传统串口应用(如蓝牙串口调试、拨号网络)可以无缝迁移到蓝牙上。RFCOMM 在 BlueZ 中作为内核模块实现,但会话管理和 DLC(数据链路连接)控制由用户空间的 bluetoothd 协调。

RFCOMM 的核心概念:

  • DLCI(Data Link Connection Identifier):标识一条 RFCOMM 数据链路,范围 0~63。
  • MSC(Modem Status Command):模拟串口控制信号(RTS/CTS/DTR/DSR)。
  • PN(Parameter Negotiation):协商最大帧大小、波特率等参数。
典型应用:Android 的蓝牙串口(SPP)配置文件、Linux 的 rfcomm 工具、车载蓝牙免提(HFP)的音频/命令通道均基于 RFCOMM。

2.5 GATT 层(Generic Attribute Profile)

GATT 是 BLE(Bluetooth Low Energy)的核心配置文件,定义了属性(Attribute)的组织方式和交互流程。在 BlueZ 中,GATT 的实现分为两部分:

  • 内核部分:net/bluetooth/gatt.c 提供属性数据库的底层存储和基本读写操作。
  • 用户空间部分:bluetoothd 中的 GATT 插件实现服务发现、通知、指示等高层逻辑。
GATT 属性层次结构 GATT 属性层次结构 服务 (Service) — UUID: 0x180D (心率服务) 特征 (Characteristic) — UUID: 0x2A37 (心率测量) 属性 (Attribute) — Handle: 0x0012 | 权限: 读/通知 | 值: [心率数据] 描述符 (Descriptor) — UUID: 0x2902 (客户端特征配置)

GATT 操作的核心流程:

  1. 服务发现:客户端发送 Read By Group Type 请求,获取服务列表。
  2. 特征发现:客户端发送 Read By Type 请求,获取特征声明及其属性句柄。
  3. 属性读写:客户端通过 Read Request / Write Request 操作具体属性。
  4. 通知/指示:服务端主动推送数据,客户端通过 CCCD(客户端特征配置描述符)使能。
调试技巧:使用 btmon 或 hcidump 抓取 HCI 日志,可以清晰看到 GATT 的 ATT PDU 交互过程。例如 btmon -w gatt.log 导出日志后用 Wireshark 分析。

2.6 各层协作流程示例

以 BLE 设备连接并读取心率数据为例,展示各层协作:

步骤 涉及层 动作描述
1 HCI 主机发送 LE Create Connection 命令,控制器发起广播扫描与连接
2 L2CAP 连接建立后,L2CAP 创建 ATT 信道(CID=0x0004),协商 MTU
3 GATT 客户端通过 ATT 信道发送 Exchange MTU Request,协商最大传输单元
4 GATT 客户端发送 Read By Group Type 发现心率服务
5 GATT 客户端发送 Read By Type 发现心率测量特征
6 GATT 客户端写入 CCCD 描述符,使能通知
7 HCI 控制器收到心率数据,通过 HCI ACL 数据包上传至主机
8 L2CAP → GATT L2CAP 重组数据包,GATT 解析 ATT Handle Value Notification,回调应用层
性能关键点:整个链路中,HCI 层的 ACL 数据包大小(默认 27 字节)是 BLE 吞吐量的主要瓶颈。通过 L2CAP MTU 协商(最大可到 251 字节)和 DLE(Data Length Extension)可以显著提升传输效率。