基于内核源码版本:Linux 主线(master,含 nfsd-7.0-2 合并) 分析日期:2026-03-22
- 总体架构概览
- BlueZ 内核协议栈层次
- HCI 设备抽象:
struct hci_dev - HCI 连接抽象:
struct hci_conn - HCI 传输层驱动:USB、UART、SDIO
- HCI 核心工作流:命令/数据/事件
- HCI 事件处理:
hci_event.c - L2CAP 层:连接、信道与协议复用
- L2CAP 信道类型与传输模式
- 低功耗蓝牙(LE):扫描、广播与连接
AF_BLUETOOTHSocket 层- MGMT 接口:用户态与内核的管理桥梁
- SMP(Security Manager Protocol)
- 上层协议:RFCOMM / BNEP / HIDP / ISO
- 关键数据结构关系图
- 核心锁机制与并发模型
- 调试接口与工具
- HCI 同步命令框架:
hci_sync.c - RFCOMM 层深度分析
- BNEP 层深度分析
- HIDP 层深度分析
- ISO 层与 LE Audio
- BLE 扫描与广播深度分析
- 蓝牙 5.x 新特性
- SMP 配对深度分析
- MGMT Mesh 网络支持
- A2DP / AVDTP 音频配置文件
- HCI 初始化流程详解
- 蓝牙子系统电源管理
- 完整数据流追踪示例
Linux 内核蓝牙子系统(BlueZ)由两大部分组成:
net/bluetooth/:协议栈核心,包含 HCI 核心、L2CAP、SMP、RFCOMM、BNEP、HIDP、SCO、ISO 等。drivers/bluetooth/:具体硬件传输层驱动,包含 USB(btusb)、UART(hci_ldisc/hci_uart)、SDIO(btsdio/btmrvl_sdio)等。
+---------------------------------------------------------+
| 用户空间(User Space) |
| bluetoothd(BlueZ) bluetoothctl hcitool obexd |
+-----------+--------------------+-------------------+----+
| AF_BLUETOOTH socket |
| (socket(AF_BLUETOOTH, ...)) | MGMT socket
+-----------v----------------------------------------v----+
| AF_BLUETOOTH 协议族 |
| bt_sock_create() --> bt_proto[]->create() |
| |
| BTPROTO_L2CAP BTPROTO_HCI BTPROTO_RFCOMM |
| BTPROTO_SCO BTPROTO_BNEP BTPROTO_HIDP |
| BTPROTO_AVDTP BTPROTO_ISO |
+---+------------+----------+----------+---------+-------+
| | | | |
+---v---+ +---v--+ +----v--+ +----v--+ +---v---+
|RFCOMM | |BNEP | |HIDP | | SCO | | ISO |
+---+---+ +--+---+ +---+---+ +---+---+ +---+---+
| | | | |
+---v-----------v----------v----------v----------v-------+
| L2CAP 核心层 |
| l2cap_core.c l2cap_sock.c |
| struct l2cap_conn / struct l2cap_chan |
+-----------------------------+--------------------------+
|
+-----------------------------v--------------------------+
| HCI 核心层 |
| hci_core.c hci_conn.c hci_event.c |
| struct hci_dev / struct hci_conn |
| struct hci_chan |
+--------+---------------+---------------+--------------+
| | |
+--------v---+ +--------v---+ +--------v---+
| btusb | | hci_ldisc | | btsdio |
| (USB) | | (UART/TTY) | | (SDIO) |
+--------+---+ +--------+---+ +--------+---+
| | |
+--------v---------------v---------------v--------------+
| 物理硬件 |
| USB Controller UART/serdev SDIO/MMC Host |
+--------------------------------------------------------+
核心源码文件索引:
| 文件 | 说明 |
|---|---|
include/net/bluetooth/bluetooth.h |
基础类型、协议号、socket 选项定义 |
include/net/bluetooth/hci_core.h |
hci_dev、hci_conn、hci_chan 等核心结构 |
include/net/bluetooth/l2cap.h |
L2CAP 协议结构、l2cap_conn、l2cap_chan |
net/bluetooth/hci_core.c |
HCI 设备注册、发现缓存、TX/RX 工作队列 |
net/bluetooth/hci_conn.c |
连接建立、断开、SCO 参数配置 |
net/bluetooth/hci_event.c |
全部 HCI 事件和 LE meta 事件处理 |
net/bluetooth/hci_sync.c |
HCI 同步命令框架、初始化序列 |
net/bluetooth/l2cap_core.c |
L2CAP 信道管理、PSM 分配、ERTM 状态机 |
net/bluetooth/mgmt.c |
MGMT 接口命令与事件分发 |
net/bluetooth/smp.c |
SMP 配对协议、LE SC 加密算法 |
net/bluetooth/af_bluetooth.c |
AF_BLUETOOTH socket 族注册与创建 |
drivers/bluetooth/btusb.c |
通用 USB 蓝牙驱动 |
drivers/bluetooth/hci_ldisc.c |
UART HCI line discipline 驱动 |
include/net/bluetooth/bluetooth.h 第 52-61 行定义了所有 Bluetooth 协议号:
#define BTPROTO_L2CAP 0
#define BTPROTO_HCI 1
#define BTPROTO_SCO 2
#define BTPROTO_RFCOMM 3
#define BTPROTO_BNEP 4
#define BTPROTO_CMTP 5
#define BTPROTO_HIDP 6
#define BTPROTO_AVDTP 7
#define BTPROTO_ISO 8
#define BTPROTO_LAST BTPROTO_ISO协议族号为 AF_BLUETOOTH = 31(第 39 行)。
BT_MAX_PROTO = BTPROTO_LAST + 1 = 9,对应 9 个可注册的子协议。
// include/net/bluetooth/bluetooth.h,第 34-35 行
#define BT_SUBSYS_VERSION 2
#define BT_SUBSYS_REVISION 22当前 MGMT 接口版本(net/bluetooth/mgmt.c,第 43-44 行):
#define MGMT_VERSION 1
#define MGMT_REVISION 23struct hci_dev 是内核蓝牙子系统中最重要的数据结构,定义在 include/net/bluetooth/hci_core.h 第 355-664 行,代表一个完整的 HCI 控制器。
struct hci_dev {
/* === 标识与基础信息 === */
struct list_head list; // 全局 hci_dev_list 链表节点
struct mutex lock; // 设备大锁
struct srcu_struct srcu; // SRCU(sleepable RCU)
const char *name; // "hci0", "hci1" 等
unsigned long flags; // HCI_UP, HCI_INQUIRY 等
__u16 id; // 数字索引,由 ida_alloc_max() 分配
__u8 bus; // HCI_USB, HCI_UART, HCI_SDIO 等
/* === 地址信息 === */
bdaddr_t bdaddr; // 公共 BD 地址
bdaddr_t random_addr; // LE 随机地址
bdaddr_t static_addr; // LE 静态随机地址
bdaddr_t rpa; // 当前 Resolvable Private Address
/* === 特性与版本 === */
__u8 features[HCI_MAX_PAGES][8]; // BR/EDR LMP 特性位图
__u8 le_features[248]; // LE 特性位图
__u8 hci_ver; // HCI 版本
__u16 manufacturer; // 制造商 ID
/* === LE 参数 === */
__u8 le_scan_type; // LE_SCAN_PASSIVE / LE_SCAN_ACTIVE
__u16 le_scan_interval;
__u16 le_scan_window;
__u16 le_conn_min_interval;
__u16 le_conn_max_interval;
__u8 le_accept_list_size; // Accept list(白名单)大小
__u8 le_resolv_list_size; // 地址解析列表大小
__u8 le_num_of_adv_sets; // 扩展广播集数量
/* === 流控计数器 === */
unsigned int acl_cnt; // ACL 数据包可用配额
unsigned int sco_cnt; // SCO 配额
unsigned int le_cnt; // LE ACL 配额
unsigned int iso_cnt; // ISO 配额
atomic_t cmd_cnt; // HCI 命令配额
/* === MTU === */
unsigned int acl_mtu, sco_mtu, le_mtu, iso_mtu;
/* === 工作队列 === */
struct workqueue_struct *workqueue; // 一般异步任务
struct workqueue_struct *req_workqueue; // HCI 请求同步任务
struct work_struct rx_work; // 接收数据处理
struct work_struct cmd_work; // 命令发送
struct work_struct tx_work; // 数据发送
/* === SKB 队列 === */
struct sk_buff_head rx_q; // 从硬件收到的原始 SKB
struct sk_buff_head raw_q; // 原始 HCI 包(for HCI socket)
struct sk_buff_head cmd_q; // 待发送 HCI 命令队列
/* === 连接哈希表 === */
struct hci_conn_hash conn_hash;
/* === 密钥存储 === */
struct list_head link_keys; // BR/EDR link key 列表
struct list_head long_term_keys; // LE LTK 列表
struct list_head identity_resolving_keys; // LE IRK 列表
/* === 发现状态机 === */
struct discovery_state discovery;
/* === 驱动回调函数(类似 ops 接口)=== */
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
int (*setup)(struct hci_dev *hdev);
int (*shutdown)(struct hci_dev *hdev);
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
void (*notify)(struct hci_dev *hdev, unsigned int evt);
void (*hw_error)(struct hci_dev *hdev, u8 code);
int (*post_init)(struct hci_dev *hdev);
int (*set_diag)(struct hci_dev *hdev, bool enable);
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
void (*reset)(struct hci_dev *hdev);
bool (*wakeup)(struct hci_dev *hdev);
};
Linux Bluetooth 不使用单独的 hci_dev_ops 结构体,而是将回调函数直接嵌入 struct hci_dev(第 645-663 行)。这是一组必须由传输层驱动实现的操作:
| 回调 | 含义 |
|---|---|
open |
上电并初始化硬件 |
close |
关闭硬件 |
flush |
清空发送队列 |
setup |
初始化固件/补丁(btusb 中的 btusb_setup_*) |
shutdown |
优雅关机 |
send |
将 SKB 发往硬件 |
notify |
通知驱动状态变化(SCO 开关等) |
hw_error |
硬件错误回调 |
set_bdaddr |
设置本地蓝牙地址 |
wakeup |
判断是否允许唤醒系统 |
hci_register_dev()(net/bluetooth/hci_core.c 第 2585 行)是驱动完成初始化后调用的入口:
// hci_core.c:2585
int hci_register_dev(struct hci_dev *hdev)
{
// 1. 验证必须实现的回调
if (!hdev->open || !hdev->close || !hdev->send)
return -EINVAL;
// 2. 从 IDA 分配设备 ID(hci0, hci1 ...)
id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);
// 3. 创建有序工作队列(高优先级)
hdev->workqueue = alloc_ordered_workqueue("%s", WQ_HIGHPRI, hdev->name);
hdev->req_workqueue = alloc_ordered_workqueue("%s", WQ_HIGHPRI, ...);
// 4. 注册 sysfs device,创建 debugfs 目录
device_add(&hdev->dev);
hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
// 5. 注册 rfkill
hdev->rfkill = rfkill_alloc(...);
// 6. 加入全局 hci_dev_list
write_lock(&hci_dev_list_lock);
list_add(&hdev->list, &hci_dev_list);
write_unlock(&hci_dev_list_lock);
// 7. 调度 setup 工作,触发 HCI Reset 和特性读取
queue_work(hdev->req_workqueue, &hdev->power_on);
}HCI_MAX_ID = 10000(第 45 行),系统支持最多 10000 个 HCI 设备。
net/bluetooth/hci_core.c 第 67 行实现了按 ID 查找设备:
static struct hci_dev *__hci_dev_get(int index, int *srcu_index)
{
read_lock(&hci_dev_list_lock);
list_for_each_entry(d, &hci_dev_list, list) {
if (d->id == index) {
hdev = hci_dev_hold(d); // 引用计数 +1
if (srcu_index)
*srcu_index = srcu_read_lock(&d->srcu);
break;
}
}
read_unlock(&hci_dev_list_lock);
}struct hci_conn(include/net/bluetooth/hci_core.h 第 679-788 行)代表一条物理级蓝牙连接,无论是 BR/EDR ACL、SCO、LE 还是 ISO CIS/BIS。
// 连接类型由 hci_conn.type 字段区分
// include/net/bluetooth/hci.h 中定义:
#define SCO_LINK 0x00
#define ACL_LINK 0x01
#define ESCO_LINK 0x02
#define LE_LINK 0x80
#define ISO_LINK 0x81
#define INVALID_LINK 0xffhci_conn.state 字段遵循标准 BT socket 状态机,状态值定义于 include/net/bluetooth/bluetooth.h(BT_CONNECTED、BT_OPEN、BT_CONNECT、BT_CONNECT2、BT_CONFIG、BT_DISCONN、BT_CLOSED):
BT_OPEN ──[连接请求]──> BT_CONNECT
|
v
BT_CONNECT2 <── 等待对端响应
|
v
BT_CONFIG <── 执行 L2CAP 配置
|
v
BT_CONNECTED <── 数据传输中
|
[断连请求或超时]
|
v
BT_DISCONN <── 等待断连完成
|
v
BT_CLOSED
struct hci_conn {
struct list_head list; // 挂在 hci_dev.conn_hash.list
atomic_t refcnt; // 引用计数
bdaddr_t dst; // 对端蓝牙地址
__u8 dst_type; // BDADDR_BREDR / BDADDR_LE_PUBLIC / BDADDR_LE_RANDOM
bdaddr_t src; // 本地地址
__u16 handle; // HCI connection handle(0x0000-0x0EFF)
__u16 state; // BT_OPEN / BT_CONNECTED 等
__u8 type; // ACL_LINK / SCO_LINK / LE_LINK / ISO_LINK
__u8 role; // HCI_ROLE_MASTER / HCI_ROLE_SLAVE
bool out; // true = 本端发起的出向连接
/* 安全相关 */
__u8 sec_level; // BT_SECURITY_SDP/LOW/MEDIUM/HIGH/FIPS
__u8 auth_type;
__u8 enc_key_size; // 加密密钥长度(字节)
__u8 io_capability; // IO 能力(用于 SSP/SMP 配对)
/* LE 专用参数 */
__u16 le_conn_min_interval;
__u16 le_conn_max_interval;
__u16 le_conn_interval; // 协商后的实际 conn interval
__u16 le_conn_latency; // peripheral latency
__u16 le_supv_timeout; // supervision timeout
/* ISO QoS(CIS/BIS)*/
struct bt_iso_qos iso_qos;
__u8 num_bis;
__u8 bis[HCI_MAX_ISO_BIS];
/* 发送队列 */
struct sk_buff_head data_q;
struct list_head chan_list; // 挂载在此连接上的 l2cap_chan 列表
/* 关联的父设备 */
struct hci_dev *hdev;
void *l2cap_data; // l2cap_conn 指针
void *sco_data;
void *iso_data;
/* 延迟工作 */
struct delayed_work disc_work; // 断连定时器
struct delayed_work le_conn_timeout; // LE 连接超时
/* 驱动回调 */
void (*connect_cfm_cb)(struct hci_conn *conn, u8 status);
void (*security_cfm_cb)(struct hci_conn *conn, u8 status);
void (*disconn_cfm_cb)(struct hci_conn *conn, u8 reason);
void (*cleanup)(struct hci_conn *conn);
};struct hci_conn_hash(第 128-137 行)是 hci_dev 中管理所有连接的容器:
struct hci_conn_hash {
struct list_head list; // 所有连接的链表头
unsigned int acl_num; // 当前 ACL 连接数
unsigned int sco_num; // 当前 SCO 连接数
unsigned int cis_num; // ISO CIS 连接数
unsigned int bis_num; // ISO BIS 连接数
unsigned int pa_num; // Periodic Advertisement 连接数
unsigned int le_num; // LE 连接总数
unsigned int le_num_peripheral; // 作为 peripheral 的 LE 连接数
};文件:drivers/bluetooth/btusb.c
btusb 是最常用的蓝牙传输层驱动,支持所有符合 Bluetooth USB 规范的设备(Class e0/01/01)。
一个标准 USB 蓝牙设备有三类端点(btusb_probe() 第 4066-4080 行):
Interface 0:
├── Interrupt IN ──> HCI 事件接收(HCI_EVENT_PKT)
├── Bulk IN ──> ACL 数据接收(HCI_ACLDATA_PKT)
└── Bulk OUT ──> ACL 数据发送 + HCI 命令发送
Interface 1 (等时):
├── Isoc IN ──> SCO 语音数据接收
└── Isoc OUT ──> SCO 语音数据发送
hdev->open = btusb_open;
hdev->close = btusb_close;
hdev->flush = btusb_flush;
hdev->send = btusb_send_frame; // 根据厂商可能替换为 btusb_send_frame_intel / _mtk
hdev->notify = btusb_notify;#define BTUSB_IGNORE BIT(0) // 应忽略该接口
#define BTUSB_INTEL_COMBINED BIT(8) // Intel 组合固件设备
#define BTUSB_BCM_PATCHRAM BIT(10) // Broadcom patchram 设备
#define BTUSB_REALTEK BIT(16) // Realtek 设备
#define BTUSB_MEDIATEK BIT(20) // MediaTek 设备
#define BTUSB_QCA_WCN6855 BIT(23) // Qualcomm WCN6855
#define BTUSB_WIDEBAND_SPEECH BIT(21) // 支持宽带语音应用层 write()
|
v
l2cap_sock_sendmsg()
|
v
hci_send_acl() / hci_send_cmd()
|
v (enqueue to hdev->cmd_q 或 hci_conn->data_q)
hci_tx_work (work_struct)
|
v
hdev->send(hdev, skb) = btusb_send_frame()
|
v (根据 bt_cb(skb)->pkt_type 选择端点)
usb_fill_bulk_urb() 或 usb_fill_control_urb()
|
v
USB Host Controller
文件:drivers/bluetooth/hci_ldisc.c、hci_h4.c、hci_h5.c、hci_bcsp.c 等
UART 传输通过 TTY Line Discipline(N_HCI,ldisc id = 15)实现。
static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
int hci_uart_register_proto(const struct hci_uart_proto *p)
{
if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL;
hup[p->id] = p;
BT_INFO("HCI UART protocol %s registered", p->name);
return 0;
}支持的 UART 子协议:
| 子协议 | 文件 | 特点 |
|---|---|---|
| H4 (HCI_UART_H4) | hci_h4.c |
最简单,4 字节头标识包类型 |
| BCSP (HCI_UART_BCSP) | hci_bcsp.c |
带 CRC 和重传的可靠传输 |
| H5 (HCI_UART_3WIRE) | hci_h5.c |
三线串口,SLIP 编码 |
| LL (HCI_UART_LL) | hci_ll.c |
TI CC256x 专用 |
| ATH3K (HCI_UART_ATH3K) | hci_ath.c |
Qualcomm Atheros |
| QCA (HCI_UART_QCA) | hci_qca.c |
Qualcomm QCA 系列 |
| BCM (HCI_UART_BCM) | hci_bcm.c |
Broadcom UART |
| INTEL (HCI_UART_INTEL) | hci_intel.c |
Intel UART |
// 非抢占式 TX 调度
int hci_uart_tx_wakeup(struct hci_uart *hu)
{
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state))
goto no_schedule;
schedule_work(&hu->write_work);
...
}文件:drivers/bluetooth/btsdio.c、btmrvl_sdio.c
SDIO 蓝牙驱动通过 sdio_claim_irq() 注册中断,在中断上下文中触发接收工作。
Marvell SDIO(btmrvl_sdio.c)使用专用固件加载和命令通道,与通用 btsdio 略有区别,提供 btmrvl_sdio_card_reg 硬件寄存器映射。
net/bluetooth/hci_core.c 第 50-52 行声明了三个工作项处理函数:
static void hci_rx_work(struct work_struct *work); // 处理接收到的 HCI 包
static void hci_cmd_work(struct work_struct *work); // 发送 HCI 命令
static void hci_tx_work(struct work_struct *work); // 发送 ACL/SCO/ISO 数据hci_send_cmd(hdev, opcode, plen, param)
|
v 分配 SKB,设置 bt_cb(skb)->pkt_type = HCI_COMMAND_PKT
v 设置 hci_skb_opcode(skb) = opcode
|
v skb 放入 hdev->cmd_q
|
v queue_work(hdev->workqueue, &hdev->cmd_work)
|
v hci_cmd_work():
if (atomic_read(&hdev->cmd_cnt) > 0) {
skb = skb_dequeue(&hdev->cmd_q);
hdev->sent_cmd = skb; // 保存以便匹配响应
hdev->send(hdev, skb);
atomic_dec(&hdev->cmd_cnt);
}
btusb_bulk_in_complete() (URB 完成回调)
|
v skb_queue_tail(&hdev->rx_q, skb)
|
v queue_work(hdev->workqueue, &hdev->rx_work)
|
v hci_rx_work():
while ((skb = skb_dequeue(&hdev->rx_q))) {
switch (bt_cb(skb)->pkt_type) {
case HCI_EVENT_PKT:
hci_event_packet(hdev, skb);
break;
case HCI_ACLDATA_PKT:
hci_acldata_packet(hdev, skb);
break;
case HCI_SCODATA_PKT:
hci_scodata_packet(hdev, skb);
break;
}
}
net/bluetooth/hci_event.c 使用静态分发表处理所有 HCI 事件,每个事件对应一个处理函数。
对于 BR/EDR 标准事件(如连接完成、断连完成、链接键通知等),在文件末尾的 hci_ev_table[] 数组中注册。
对于 LE Meta 事件,通过 hci_le_meta_evt()(第 7432 行)分发到 hci_le_ev_table[]。
// hci_event.c:7432
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb, u16 *opcode, u8 *status,
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb)
{
struct hci_ev_le_meta *ev = data;
const struct hci_le_ev *subev;
// 从 hci_le_ev_table 中按 subevent 号查找处理函数
subev = &hci_le_ev_table[ev->subevent];
if (!subev->func)
return;
// 长度校验(min_len 和 max_len 均由表项指定)
if (skb->len < subev->min_len) { ... return; }
data = hci_le_ev_skb_pull(hdev, skb, ev->subevent, subev->min_len);
subev->func(hdev, data, skb); // 调用对应子事件处理函数
}| 子事件 | 函数 | 行号 |
|---|---|---|
HCI_EV_LE_CONN_COMPLETE |
hci_le_conn_complete_evt() |
5866 |
HCI_EV_LE_ADVERTISING_REPORT |
hci_le_adv_report_evt() |
6381 |
HCI_EV_LE_CONN_UPDATE_COMPLETE |
hci_le_conn_update_complete_evt() |
6052 |
HCI_EV_LE_META (总入口) |
hci_le_meta_evt() |
7432 |
le_conn_complete_evt()(第 5703 行)是 LE 连接建立的关键路径:
static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
bdaddr_t *bdaddr, u8 bdaddr_type,
bdaddr_t *local_rpa, u8 role, u16 handle,
u16 interval, u16 latency,
u16 supervision_timeout)
{
hci_dev_lock(hdev);
// 广播停止:控制器建立连接后隐式停止广播
hci_dev_clear_flag(hdev, HCI_LE_ADV);
// 查找或创建 hci_conn 对象
conn = hci_conn_hash_lookup_role(hdev, LE_LINK, role, bdaddr);
if (!conn || ...) {
conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, bdaddr_type, role);
} else {
cancel_delayed_work(&conn->le_conn_timeout);
}
// 防止重复处理:检查 handle 是否已设置
if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
goto unlock;
}
// 设置连接 handle 和 LE 参数,通知 L2CAP 层
...
}hci_le_adv_report_evt()(第 6381 行)处理 HCI_EV_LE_ADVERTISING_REPORT 事件,将扫描结果转发给 mgmt_device_found(),最终通过 MGMT 事件 MGMT_EV_DEVICE_FOUND 通知用户态。
hci_event.c 中大量 hci_cc_* 函数处理 HCI 命令完成事件,例如(第 83-399 行):
hci_cc_inquiry_cancel():处理 Inquiry Cancel 的完成hci_cc_reset():处理 HCI Reset 完成,清空广播数据、重置扫描类型hci_cc_write_local_name():处理写本地名称完成,通知 MGMT 层hci_cc_role_discovery():更新hci_conn.role字段
L2CAP(Logical Link Control and Adaptation Protocol)是蓝牙协议栈的多路复用层,位于 HCI 之上,为上层协议(RFCOMM、BNEP、SMP、ATT 等)提供统一的信道抽象。
核心数据结构有两个:struct l2cap_conn(连接级)和 struct l2cap_chan(信道级)。
定义于 include/net/bluetooth/l2cap.h 第 643-675 行:
struct l2cap_conn {
struct hci_conn *hcon; // 关联的 HCI 连接
struct hci_chan *hchan; // 关联的 HCI 逻辑信道
unsigned int mtu; // 当前连接 MTU
__u32 feat_mask; // 对端的 L2CAP 扩展特性位图
__u8 remote_fixed_chan; // 对端支持的固定信道位图
__u8 local_fixed_chan; // 本地支持的固定信道位图
__u8 info_state; // Info Request 握手状态
__u8 info_ident;
struct delayed_work info_timer; // Info Request 超时定时器
struct sk_buff *rx_skb; // 当前正在组装的 SDU
__u32 rx_len;
struct ida tx_ida; // 发送 PDU id 分配器
struct sk_buff_head pending_rx; // 暂存的接收 SKB
struct work_struct pending_rx_work;
struct delayed_work id_addr_timer; // LE 身份地址解析定时器
__u8 disc_reason;
struct l2cap_chan *smp; // SMP 专用信道
struct list_head chan_l; // 挂载在本连接上的所有 l2cap_chan
struct mutex lock;
struct kref ref;
struct list_head users; // l2cap_user 回调(RFCOMM、BNEP 等)
};定义于 include/net/bluetooth/l2cap.h 第 514 行,是单个 L2CAP 信道的完整描述:
struct l2cap_chan {
struct l2cap_conn *conn; // 所属 l2cap_conn
struct kref kref; // 引用计数
__u8 state; // BT_CONNECTED, BT_OPEN 等
/* 地址信息 */
bdaddr_t dst, src;
__u8 dst_type, src_type;
__le16 psm; // Protocol/Service Multiplexer(服务端口)
__le16 sport; // 服务端 PSM(监听时使用)
__u16 dcid, scid; // 目标/源信道标识符(CID)
/* MTU 与窗口 */
__u16 imtu; // 入方向 MTU
__u16 omtu; // 出方向 MTU
__u8 mode; // L2CAP_MODE_BASIC / ERTM / STREAMING / LE_FLOWCTL
__u8 chan_type; // L2CAP_CHAN_RAW / CONN_LESS / CONN_ORIENTED / FIXED
/* 安全级别 */
__u8 sec_level;
/* ERTM 滑动窗口 */
__u16 tx_win; // 发送窗口大小
__u16 tx_win_max;
__u16 ack_win;
__u8 max_tx; // 最大重传次数
__u16 retrans_timeout;
__u16 monitor_timeout;
__u16 mps; // Maximum PDU Payload Size
/* LE 流量控制 */
__u16 tx_credits; // 剩余发送信用
__u16 rx_credits; // 剩余接收信用
/* ERTM 序列号 */
__u16 next_tx_seq;
__u16 expected_ack_seq;
__u16 expected_tx_seq;
__u16 buffer_seq;
__u16 last_acked_seq;
/* 重传定时器 */
struct delayed_work retrans_timer;
struct delayed_work monitor_timer;
struct delayed_work ack_timeout;
};include/net/bluetooth/l2cap.h 定义了固定与动态 CID 范围(第 258-267 行):
/* 固定 CID(BR/EDR + LE) */
#define L2CAP_CID_SIGNALING 0x0001 // BR/EDR 信令
#define L2CAP_CID_CONN_LESS 0x0002 // 无连接数据
#define L2CAP_CID_ATT 0x0004 // ATT(GATT)
#define L2CAP_CID_LE_SIGNALING 0x0005 // LE 信令
#define L2CAP_CID_SMP 0x0006 // LE SMP
#define L2CAP_CID_SMP_BREDR 0x0007 // BR/EDR SMP
/* 动态 CID 范围 */
#define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_LE_DYN_END 0x007f // LE 动态 CID 上限
#define L2CAP_CID_DYN_END 0xffff // BR/EDR 动态 CID 上限l2cap_core.c 第 182-224 行实现了 l2cap_add_psm(),为信道分配 PSM 值:
- BR/EDR 动态 PSM:从
L2CAP_PSM_DYN_START (0x1001)开始,步长 2(只用奇数) - LE 动态 PSM:从
L2CAP_PSM_LE_DYN_START (0x0080)开始,步长 1
标准 PSM 值(第 246-250 行):
#define L2CAP_PSM_SDP 0x0001 // Service Discovery Protocol
#define L2CAP_PSM_RFCOMM 0x0003 // RFCOMM(串口模拟)
#define L2CAP_PSM_3DSP 0x0021 // 3D 同步
#define L2CAP_PSM_IPSP 0x0023 // 6LoWPAN// include/net/bluetooth/l2cap.h:687-690
#define L2CAP_CHAN_RAW 1 // 原始 HCI 数据(HCI socket)
#define L2CAP_CHAN_CONN_LESS 2 // 无连接(G-Frames)
#define L2CAP_CHAN_CONN_ORIENTED 3 // 面向连接(标准 L2CAP 连接)
#define L2CAP_CHAN_FIXED 4 // 固定 CID(ATT、SMP、LE 信令)// include/net/bluetooth/l2cap.h:348-359
#define L2CAP_MODE_BASIC 0x00 // 基础模式(默认)
#define L2CAP_MODE_RETRANS 0x01 // 重传模式(已废弃)
#define L2CAP_MODE_FLOWCTL 0x02 // 流控模式(已废弃)
#define L2CAP_MODE_ERTM 0x03 // 增强重传模式(ERTM)
#define L2CAP_MODE_STREAMING 0x04 // 流媒体模式
#define L2CAP_MODE_LE_FLOWCTL 0x80 // LE 基于信用的流控(内核内部使用)
#define L2CAP_MODE_EXT_FLOWCTL 0x81 // LE 扩展信用流控(ECRED)对应用户空间 socket 选项(include/net/bluetooth/bluetooth.h,第 160-164 行):
#define BT_MODE_BASIC 0x00
#define BT_MODE_ERTM 0x01
#define BT_MODE_STREAMING 0x02
#define BT_MODE_LE_FLOWCTL 0x03
#define BT_MODE_EXT_FLOWCTL 0x04ERTM 在 l2cap_core.c 中实现,使用三个定时器(第 280-294 行):
retrans_timer:重传超时(默认 2000ms,L2CAP_DEFAULT_RETRANS_TO)monitor_timer:监控超时(默认 12000ms,L2CAP_DEFAULT_MONITOR_TO)ack_timeout:延迟 ACK 定时器(默认 200ms,L2CAP_DEFAULT_ACK_TO)
ERTM S 帧监督函数(include/net/bluetooth/l2cap.h 第 180-183 行):
#define L2CAP_SUPER_RR 0x00 // Receiver Ready(请求对端继续发)
#define L2CAP_SUPER_REJ 0x01 // Reject(请求从某序号重传)
#define L2CAP_SUPER_RNR 0x02 // Receiver Not Ready(流控暂停)
#define L2CAP_SUPER_SREJ 0x03 // Selective Reject(选择性重传)LE 基于信用的流控使用 tx_credits 和 rx_credits 字段。接收方通过 L2CAP_LE_CREDITS(命令码 0x16)分配信用给发送方。
LE_FLOWCTL_MAX_CREDITS = 65535(l2cap_core.c 第 43 行)。
ECRED(Enhanced Credit Based Flow Control)支持在单次请求中同时建立最多 L2CAP_ECRED_CONN_SCID_MAX = 5 个信道(include/net/bluetooth/l2cap.h 第 50 行)。
enable_ecred 标志(l2cap_core.c 第 46 行)由 Kconfig CONFIG_BT_LE_L2CAP_ECRED 控制:
bool enable_ecred = IS_ENABLED(CONFIG_BT_LE_L2CAP_ECRED);l2cap_core.c 提供了多种信道查找方式:
// 按 DCID(目标 CID)查找
static struct l2cap_chan *__l2cap_get_chan_by_dcid(
struct l2cap_conn *conn, u16 cid) // 行 90
// 按 SCID(源 CID)查找
static struct l2cap_chan *__l2cap_get_chan_by_scid(
struct l2cap_conn *conn, u16 cid) // 行 102
// 带引用锁的安全版本
static struct l2cap_chan *l2cap_get_chan_by_scid(
struct l2cap_conn *conn, u16 cid) // 行 117
// 按 PSM 查找全局监听信道
static struct l2cap_chan *__l2cap_global_chan_by_addr(
__le16 psm, bdaddr_t *src, u8 src_type) // 行 164hci_dev 中维护多套 LE 扫描参数(第 407-417 行),针对不同场景动态切换:
__u16 le_scan_interval; // 通用扫描间隔
__u16 le_scan_window;
__u16 le_scan_int_suspend; // 挂起时的扫描参数
__u16 le_scan_window_suspend;
__u16 le_scan_int_discovery; // 发现模式的扫描参数
__u16 le_scan_window_discovery;
__u16 le_scan_int_adv_monitor; // 广播监控的扫描参数
__u16 le_scan_window_adv_monitor;
__u16 le_scan_int_connect; // 连接发起前的扫描参数
__u16 le_scan_window_connect;struct discovery_state(include/net/bluetooth/hci_core.h 第 72-99 行)管理 LE/BR 发现过程:
struct discovery_state {
int type;
enum {
DISCOVERY_STOPPED, // 已停止
DISCOVERY_STARTING, // 正在启动
DISCOVERY_FINDING, // 正在扫描/查询
DISCOVERY_RESOLVING, // 正在解析名称
DISCOVERY_STOPPING, // 正在停止
} state;
struct list_head all; // 发现的所有设备
struct list_head unknown; // 名称未知的设备
struct list_head resolve; // 需要解析名称的设备
bdaddr_t last_adv_addr;
u8 last_adv_addr_type;
s8 last_adv_rssi;
u32 last_adv_flags;
u8 last_adv_data[HCI_MAX_EXT_AD_LENGTH];
u8 last_adv_data_len;
bool result_filtering; // 结果过滤(按 RSSI/UUID)
bool limited; // 仅发现 Limited Discoverable
s8 rssi; // RSSI 过滤阈值
u16 uuid_count;
u8 (*uuids)[16]; // UUID 过滤列表
};状态转换由 hci_discovery_set_state()(hci_core.c 第 122 行)驱动,切换时向 MGMT 层发送 MGMT_EV_DISCOVERING 事件。
hci_dev 支持多广播实例(adv_instances 链表),最多 HCI_MAX_ADV_INSTANCES = 5 个实例(第 279 行)。
每个广播实例由 struct adv_info(第 243-271 行)描述:
struct adv_info {
bool enabled;
bool periodic; // 是否为 Periodic Advertising
bool periodic_enabled;
__u8 instance; // 实例 ID(0 = 默认)
__u8 handle; // 硬件 advertising set handle
__u32 flags;
__u16 timeout;
__u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_EXT_AD_LENGTH];
__u16 scan_rsp_len;
__u8 scan_rsp_data[HCI_MAX_EXT_AD_LENGTH];
__u16 per_adv_data_len;
__u8 per_adv_data[HCI_MAX_PER_AD_LENGTH];
__s8 tx_power;
__u32 min_interval;
__u32 max_interval;
bdaddr_t random_addr;
bool rpa_expired;
struct delayed_work rpa_expired_cb; // RPA 轮换定时器
};默认 RPA 超时:HCI_DEFAULT_RPA_TIMEOUT = 15 * 60(900 秒,第 345 行)。
hci_conn 中的 LE 连接参数(第 721-725 行)在 HCI_LE_Connection_Update_Complete 事件时更新:
__u16 le_conn_min_interval; // 请求的最小连接间隔
__u16 le_conn_max_interval; // 请求的最大连接间隔
__u16 le_conn_interval; // 当前实际间隔(单位 1.25ms)
__u16 le_conn_latency; // Peripheral Latency(允许跳过的 event 数)
__u16 le_supv_timeout; // 监督超时(单位 10ms)LE Accept List(原 Whitelist)和 Resolving List 由 hci_dev 中的链表管理:
struct list_head le_accept_list; // Accept List 条目
struct list_head le_resolv_list; // Resolving List(IRK 地址解析)Privacy 模式下,本地 IRK 存储在 hdev->irk[16](第 610 行),用于生成和解析 RPA。
hci_conn 中的 ISO 支持(第 740-742 行):
struct bt_iso_qos iso_qos; // CIG/CIS 或 BIG/BIS 的 QoS 参数
__u8 num_bis; // BIS 数量
__u8 bis[HCI_MAX_ISO_BIS]; // BIS 索引列表struct bt_iso_qos(include/net/bluetooth/bluetooth.h 第 217-222 行)联合体支持单播(ucast)和广播(bcast)两种模式。
net/bluetooth/af_bluetooth.c 实现了 AF_BLUETOOTH 协议族的注册和 socket 创建:
// af_bluetooth.c:44-46
#define BT_MAX_PROTO (BTPROTO_LAST + 1) // = 9
static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
static DEFINE_RWLOCK(bt_proto_lock);各子协议通过 bt_sock_register() 注册(第 85-103 行):
int bt_sock_register(int proto, const struct net_proto_family *ops)
{
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
write_lock(&bt_proto_lock);
if (bt_proto[proto])
err = -EEXIST;
else
bt_proto[proto] = ops;
write_unlock(&bt_proto_lock);
return err;
}
EXPORT_SYMBOL(bt_sock_register);bt_sock_create()(第 116 行)是 socket(AF_BLUETOOTH, type, proto) 系统调用的内核入口:
static int bt_sock_create(struct net *net, struct socket *sock,
int proto, int kern)
{
// 1. 网络命名空间检查:仅支持 init_net
if (net != &init_net)
return -EAFNOSUPPORT;
// 2. 未加载时触发自动加载模块
if (!bt_proto[proto])
request_module("bt-proto-%d", proto);
// 3. 调用子协议的 create() 回调
read_lock(&bt_proto_lock);
if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
err = bt_proto[proto]->create(net, sock, proto, kern);
if (!err)
bt_sock_reclassify_lock(sock->sk, proto); // 重新分类锁
module_put(bt_proto[proto]->owner);
}
read_unlock(&bt_proto_lock);
return err;
}第 146 行的 bt_sock_alloc() 是所有子协议创建 socket 的通用函数:
struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
struct proto *prot, int proto, gfp_t prio, int kern)
{
sk = sk_alloc(net, PF_BLUETOOTH, prio, prot, kern);
sock_init_data(sock, sk);
INIT_LIST_HEAD(&bt_sk(sk)->accept_q); // 初始化 accept 队列
sock_reset_flag(sk, SOCK_ZAPPED);
sk->sk_protocol = proto;
sk->sk_state = BT_OPEN;
// 记录创建进程的 PID 和凭证(用于审计)
if (!kern) {
sk->sk_peer_pid = get_pid(task_tgid(current));
sk->sk_peer_cred = get_current_cred();
}
return sk;
}每个协议有独立的锁类,用于 lockdep 检测(第 48-72 行):
static const char *const bt_key_strings[BT_MAX_PROTO] = {
"sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
"sk_lock-AF_BLUETOOTH-BTPROTO_HCI",
"sk_lock-AF_BLUETOOTH-BTPROTO_SCO",
"sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM",
"sk_lock-AF_BLUETOOTH-BTPROTO_BNEP",
"sk_lock-AF_BLUETOOTH-BTPROTO_CMTP",
"sk_lock-AF_BLUETOOTH-BTPROTO_HIDP",
"sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
"sk_lock-AF_BLUETOOTH-BTPROTO_ISO",
};include/net/bluetooth/bluetooth.h 定义了丰富的 socket 选项(第 68-260 行):
| 选项名 | 值 | 含义 |
|---|---|---|
BT_SECURITY |
4 | 获取/设置安全级别(struct bt_security) |
BT_DEFER_SETUP |
7 | 延迟建立连接(用于授权) |
BT_FLUSHABLE |
8 | 允许 L2CAP flush |
BT_POWER |
9 | 控制连接功耗(struct bt_power) |
BT_CHANNEL_POLICY |
10 | AMP/BR 信道策略 |
BT_VOICE |
11 | SCO 语音格式(struct bt_voice) |
BT_PHY |
14 | PHY 能力查询(BR/EDR/LE PHY 位图) |
BT_MODE |
15 | L2CAP 传输模式 |
BT_ISO_QOS |
17 | ISO QoS 参数(struct bt_iso_qos) |
BT_CODEC |
19 | 编解码器选择(struct bt_codec) |
安全级别(第 73-77 行):
#define BT_SECURITY_SDP 0 // 仅 SDP 查询,无需认证
#define BT_SECURITY_LOW 1 // 低安全性,无需认证但允许加密
#define BT_SECURITY_MEDIUM 2 // 需要认证
#define BT_SECURITY_HIGH 3 // 需要认证和加密
#define BT_SECURITY_FIPS 4 // FIPS 级别(128-bit 密钥)MGMT(Management Interface)是 bluetoothd 与内核之间的专用控制通道,通过 HCI_DEV_NONE(设备无关)的 HCI socket 通信,路径为:
bluetoothd
|
| socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)
| bind({ dev_id = HCI_DEV_NONE, channel = HCI_CHANNEL_CONTROL })
|
v
hci_sock_sendmsg() --> hci_mgmt_cmd() --> mgmt_commands[] 分发表
|
v
mgmt.c 中对应的处理函数
|
v
HCI 命令发送 / 状态变更 / 事件上报
|
v
mgmt_event() / mgmt_event_skb() --> hci_sock 广播回用户态
net/bluetooth/mgmt.c 第 46-136 行列出了所有支持的 MGMT 命令(当前 MGMT_REVISION=23),代表性命令包括:
基础配置:
MGMT_OP_READ_INDEX_LIST:枚举所有 HCI 设备MGMT_OP_READ_INFO:读取控制器详细信息MGMT_OP_SET_POWERED:上下电控制器MGMT_OP_SET_DISCOVERABLE:设置可发现性MGMT_OP_SET_CONNECTABLE:设置可连接性MGMT_OP_SET_LE:启用/禁用 LE 功能MGMT_OP_SET_BREDR:启用/禁用 BR/EDR 功能
密钥管理:
MGMT_OP_LOAD_LINK_KEYS:加载 BR/EDR link keyMGMT_OP_LOAD_LONG_TERM_KEYS:加载 LE LTKMGMT_OP_LOAD_IRKS:加载 LE IRK(用于隐私解析)
配对操作:
MGMT_OP_PAIR_DEVICE:发起配对MGMT_OP_CANCEL_PAIR_DEVICE:取消配对MGMT_OP_UNPAIR_DEVICE:解除配对MGMT_OP_PIN_CODE_REPLY:回复 PIN 码MGMT_OP_USER_CONFIRM_REPLY:确认数字比较MGMT_OP_USER_PASSKEY_REPLY:回复 Passkey
发现:
MGMT_OP_START_DISCOVERY:启动设备发现MGMT_OP_STOP_DISCOVERY:停止发现MGMT_OP_START_LIMITED_DISCOVERY:仅发现 Limited Discoverable 设备MGMT_OP_START_SERVICE_DISCOVERY:按 UUID 过滤发现
广播:
MGMT_OP_ADD_ADVERTISING:添加广播实例MGMT_OP_REMOVE_ADVERTISING:移除广播实例MGMT_OP_ADD_EXT_ADV_PARAMS:扩展广播参数
新增(高版本):
MGMT_OP_SET_MESH_RECEIVER:Mesh 广播接收MGMT_OP_HCI_CMD_SYNC:直接同步发送任意 HCI 命令(调试用)
第 138-183 行的 mgmt_events[] 是内核主动推送给 bluetoothd 的事件集合:
关键事件:
| 事件 | 触发时机 |
|---|---|
MGMT_EV_DEVICE_CONNECTED |
设备连接成功 |
MGMT_EV_DEVICE_DISCONNECTED |
设备断连 |
MGMT_EV_DEVICE_FOUND |
LE 扫描发现设备 |
MGMT_EV_NEW_LINK_KEY |
产生新 BR/EDR link key |
MGMT_EV_NEW_LONG_TERM_KEY |
产生新 LE LTK |
MGMT_EV_NEW_IRK |
产生新 LE IRK |
MGMT_EV_NEW_CSRK |
产生新 CSRK |
MGMT_EV_PIN_CODE_REQUEST |
需要输入 PIN |
MGMT_EV_USER_CONFIRM_REQUEST |
需要确认数字 |
MGMT_EV_PASSKEY_NOTIFY |
显示 Passkey |
MGMT_EV_CONTROLLER_SUSPEND |
控制器挂起 |
MGMT_EV_CONTROLLER_RESUME |
控制器恢复 |
MGMT_EV_ADV_MONITOR_DEVICE_FOUND |
广播监控匹配到设备 |
mgmt.c 第 219-283 行维护 HCI 错误码到 MGMT 错误码的映射表 mgmt_status_table[],将底层 HCI 错误码翻译为用户态友好的高层错误码。
第 185-211 行的 mgmt_untrusted_commands[] 定义了非特权进程(无 CAP_NET_ADMIN)可以使用的命令子集(仅只读命令,如 MGMT_OP_READ_INDEX_LIST、MGMT_OP_READ_INFO)。
SMP 是 BLE 的安全管理协议,运行在 L2CAP 固定信道 CID=0x0006(LE SMP)或 CID=0x0007(BR/EDR SMP)之上。
net/bluetooth/smp.c 实现了完整的 SMP 协议,包括传统配对(LE Legacy Pairing)和 LE Secure Connections(SC)。
struct smp_dev(smp.c 第 85-94 行):每个 HCI 设备的 SMP 全局状态。
struct smp_dev {
bool local_oob; // 是否有本地 OOB 数据
u8 local_pk[64]; // 本地 ECDH 公钥
u8 local_rand[16]; // 本地随机数(OOB 用)
bool debug_key; // 是否使用 debug 密钥
struct crypto_shash *tfm_cmac; // AES-CMAC 算法实例
struct crypto_kpp *tfm_ecdh; // ECDH 密钥交换算法实例
};struct smp_chan(第 96-132 行):单次配对会话的完整状态。
struct smp_chan {
struct l2cap_conn *conn;
struct delayed_work security_timer; // 配对超时(30s)
unsigned long allow_cmd; // 当前允许接收的 SMP 命令位图
u8 preq[7]; // Pairing Request PDU 缓存
u8 prsp[7]; // Pairing Response PDU 缓存
u8 prnd[16]; // 本地配对随机数
u8 rrnd[16]; // 对端配对随机数
u8 pcnf[16]; // 配对 Confirm 值
u8 tk[16]; // Temporary Key(Legacy 配对)
u8 enc_key_size; // 协商的加密密钥长度
u8 remote_key_dist; // 对端密钥分发掩码
/* 密钥存储 */
struct smp_csrk *csrk;
struct smp_csrk *responder_csrk;
struct smp_ltk *ltk;
struct smp_ltk *responder_ltk;
struct smp_irk *remote_irk;
u8 *link_key;
/* LE SC 专用 */
u8 local_pk[64]; // 本地临时公钥
u8 remote_pk[64]; // 对端公钥
u8 dhkey[32]; // Diffie-Hellman 共享密钥
u8 mackey[16]; // MAC 密钥(f5 输出)
struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
};smp.c 实现了 Bluetooth Core Spec 中规定的全套 LE SC 加密函数,均基于 AES-CMAC(crypto_shash 接口)和 ECDH(crypto_kpp 接口):
aes_cmac()(第 169 行):AES-CMAC 基础函数,消息最大 80 字节(CMAC_MSG_MAX)。
smp_f4()(第 209 行):Confirm 值生成函数。
f4(U, V, X, Z) = AES-CMAC_X(U || V || Z)
smp_f5()(第 232 行):LTK 和 MacKey 生成函数(LE SC 专用)。
f5(W, N1, N2, A1, A2) -> MacKey || LTK
使用盐值 salt 和标识符 "btle" 来派生密钥,通过两次 AES-CMAC 计算分别得到 MacKey(counter=0)和 LTK(counter=1)。
smp_f6()(第 285 行):DHKey Check 验证函数,防止中间人攻击。
Debug 密钥(第 138-155 行):Core Spec 定义的公开调试密钥对,当 smp_debug_mode 开启时使用,仅用于测试目的:
static const u8 debug_pk[64] = { 0xe6, 0x9d, 0x35, 0x0e, ... }; // 公钥
static const u8 debug_sk[32] = { 0xbd, 0x1a, 0x3c, 0xcd, ... }; // 私钥 初始化
|
v
Pairing Request / Response
|
v
[Legacy 配对] [SC 配对]
Just Works / Passkey / Public Key Exchange
OOB |
| v
| DHKey 计算(ECDH)
| |
v v
Confirm / Random 交换 Authentication Stage 1
| (f4/f5/f6 验证)
v |
STK 计算 v
(AES-128) LTK / MacKey 生成(f5)
| |
v v
加密连接 DHKey Check(f6)
| |
v v
密钥分发 加密连接
(LTK/IRK/CSRK/LinkKey) |
v
密钥分发
include/net/bluetooth/hci_core.h 中定义的密钥结构:
// LE Long Term Key(第 201-212 行)
struct smp_ltk {
bdaddr_t bdaddr;
u8 bdaddr_type;
u8 authenticated; // 是否通过 MITM 认证
u8 type; // SMP_LTK / SMP_LTK_RESPONDER / SMP_LTK_P256
u8 enc_size; // 密钥有效字节数
__le16 ediv; // 加密密钥分散器
__le64 rand; // 随机值
u8 val[16]; // LTK 值
};
// Identity Resolving Key(第 214-221 行)
struct smp_irk {
bdaddr_t rpa; // 当前对应的 RPA 地址
bdaddr_t bdaddr; // 身份地址
u8 addr_type;
u8 val[16]; // IRK 值
};最小加密密钥长度:HCI_MIN_ENC_KEY_SIZE = 7(第 342 行)。
- 注册协议号:
BTPROTO_RFCOMM = 3 - L2CAP PSM:
L2CAP_PSM_RFCOMM = 0x0003 - 源文件:
net/bluetooth/rfcomm/(独立目录) - 功能:在 L2CAP 之上模拟 RS-232 串口,提供多路复用(最多 30 个 DLC)
- 应用:蓝牙串口(SPP)、耳机(HSP)、HFP 控制信道
- 注册协议号:
BTPROTO_BNEP = 4 - 源文件:
net/bluetooth/bnep/ - 功能:将以太网帧封装在 L2CAP 之上,实现蓝牙个人局域网(PAN)
- 提供标准网络接口(
bnepX网络设备)
- 注册协议号:
BTPROTO_HIDP = 6 - 源文件:
net/bluetooth/hidp/ - 功能:蓝牙 HID 设备(键盘、鼠标、游戏手柄)的内核驱动
- 使用两条 L2CAP 信道:Control(PSM 0x0011)和 Interrupt(PSM 0x0013)
- 注册协议号:
BTPROTO_ISO = 8 - 源文件:
net/bluetooth/iso.c - 功能:LE Audio 的 ISO 链路管理,支持 CIS(连接等时流)和 BIS(广播等时流)
- QoS 由
struct bt_iso_ucast_qos/struct bt_iso_bcast_qos描述 - 每条 ISO 链路对应一个
hci_conn,类型为ISO_LINK
- 注册协议号:
BTPROTO_SCO = 2 - 源文件:
net/bluetooth/sco.c - 用于 BR/EDR 语音通话(HFP AG/HF 角色)
- 支持多种语音编解码参数(
esco_param_cvsd、esco_param_msbc,hci_conn.c第 52-68 行)
+------------------+
| hci_dev | <-- 一个 HCI 控制器
| (hci_core.h:355)|
| |
| conn_hash ------+----> hci_conn (ACL) ---> l2cap_data --> l2cap_conn
| link_keys | |
| long_term_keys | hci_conn (LE) ---> l2cap_data --> l2cap_conn
| identity_... | |
| adv_instances | hci_conn (SCO) ---> sco_data |
| discovery | |
| smp_data -------+----> l2cap_chan (SMP 全局) |
| | |
| workqueue | l2cap_chan (RFCOMM) |
| req_workqueue | l2cap_chan (BNEP) |
| rx_work | l2cap_chan (ATT) |
| cmd_work | l2cap_chan (SMP) |
| tx_work | l2cap_chan (固定) |
+------------------+
+------------------+ +------------------+
| l2cap_conn |-------->| l2cap_chan |
| (l2cap.h:643) | chan_l | (l2cap.h:514) |
| | 链表 | |
| hcon -----+ | | conn --> l2cap_conn
| feat_mask | | | scid, dcid |
| chan_l | | | psm, mode |
| smp --------+---+-------> l2cap_chan (SMP CID)
| users | | | tx/rx_credits |
+------------------+ | ops |
+------------------+
|
+--------v---------+
| l2cap_pinfo |
| bt_sock |
| (socket 私有数据)|
+------------------+
+------------------+
| smp_chan | <-- 一次配对会话
| (smp.c:96) |
| conn |
| preq/prsp | Pairing Request/Response
| prnd/rrnd | 随机数
| tk / ltk | 密钥
| local_pk | 本地 ECDH 公钥(64 bytes)
| remote_pk | 对端 ECDH 公钥(64 bytes)
| dhkey | DH 共享密钥(32 bytes)
| mackey | f5 输出的 MacKey
| tfm_cmac | AES-CMAC 实例
| tfm_ecdh | ECDH 实例
+------------------+
| 锁 | 类型 | 保护对象 |
|---|---|---|
hci_dev_list_lock |
rwlock_t |
全局 hci_dev_list 链表 |
hci_cb_list_lock |
mutex |
HCI 回调链表 |
bt_proto_lock |
rwlock_t |
bt_proto[] 协议注册表 |
chan_list_lock |
rwlock_t |
L2CAP 全局 chan_list |
| 锁 | 类型 | 位置 | 保护对象 |
|---|---|---|---|
hdev->lock |
mutex |
hci_dev.lock |
设备状态、连接哈希等 |
hdev->req_lock |
mutex |
hci_dev.req_lock |
HCI 请求同步 |
hdev->srcu |
srcu_struct |
hci_dev.srcu |
设备访问的 SRCU 保护 |
conn->chan_list |
通过 hdev->lock |
hci_conn.chan_list |
l2cap_chan 链表 |
// l2cap_chan 使用 kref + mutex 管理生命周期
l2cap_chan_hold(chan); // 引用计数 +1
l2cap_chan_lock(chan); // 获取信道锁
l2cap_chan_unlock(chan); // 释放信道锁
l2cap_chan_put(chan); // 引用计数 -1,可能触发销毁l2cap_get_chan_by_scid() 返回已加锁的信道引用(第 117-131 行),调用者需要显式解锁和释放。
hci_dev 使用两个独立的有序工作队列(WQ_HIGHPRI):
workqueue:处理 RX 接收、TX 发送、发现超时等事件驱动任务req_workqueue:处理需要等待 HCI 响应的同步请求(setup、shutdown 等)
两个工作队列都是有序(ordered)的,同一时刻只有一个 work item 在运行,避免并发。hdev->lock(mutex)用于保护从工作队列以外访问设备状态。
SMP 配对有严格的 30 秒超时(SMP_TIMEOUT = secs_to_jiffies(30),smp.c 第 58 行)。超时后,smp_chan 被销毁,对应的 L2CAP 信道被关闭。
hci_register_dev() 在 /sys/kernel/debug/bluetooth/ 下为每个设备创建目录(hdev->debugfs)。
net/bluetooth/hci_debugfs.c 注册了大量 debugfs 文件,包括:
features:BR/EDR LMP 特性le_features:LE 特性connections:当前连接列表blacklist/whitelist:设备黑/白名单uuids:注册的 UUID 列表adv_instances:广播实例状态smp_debug_keys:SMP 调试密钥开关
include/net/bluetooth/bluetooth.h 第 279-300 行定义了标准日志宏:
#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
#define BT_WARN(fmt, ...) bt_warn(fmt "\n", ##__VA_ARGS__)
#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
#define BT_DBG(fmt, ...) bt_dbg(...) / pr_debug(...) // 取决于 CONFIG_BT_FEATURE_DEBUG
// 设备级别(自动加设备名前缀)
#define bt_dev_info(hdev, fmt, ...) BT_INFO("%s: " fmt, bt_dev_name(hdev), ...)
#define bt_dev_warn(hdev, fmt, ...) BT_WARN("%s: " fmt, ...)
#define bt_dev_err(hdev, fmt, ...) BT_ERR("%s: " fmt, ...)
#define bt_dev_dbg(hdev, fmt, ...) BT_DBG("%s: " fmt, ...)hci_register_dev() 第 2628 行为每个 HCI 设备注册 rfkill 节点(RFKILL_TYPE_BLUETOOTH),支持通过 /sys/class/rfkill/ 软件关闭蓝牙。
include/net/bluetooth/coredump.h 和 net/bluetooth/coredump.c 提供控制器崩溃时的 coredump 收集机制,由 hdev->dump 字段(struct hci_devcoredump)管理。
- MSFT 扩展(
net/bluetooth/msft.c):Microsoft 蓝牙扩展,支持广播监控的 RSSI 过滤卸载到硬件,hdev->msft_opcode存储厂商特定操作码。 - AOSP 扩展(
net/bluetooth/aosp.c):Android 开源项目蓝牙扩展,支持质量报告(hdev->aosp_quality_report)。
// include/net/bluetooth/hci_core.h:338-339
#define HCI_CONN_HANDLE_MAX 0x0eff
#define HCI_CONN_HANDLE_UNSET(_handle) (_handle > HCI_CONN_HANDLE_MAX)// include/net/bluetooth/l2cap.h:34-60
#define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_TX_WINDOW 63
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 // ms
#define L2CAP_DEFAULT_MONITOR_TO 12000 // ms
#define L2CAP_DEFAULT_ACK_TO 200 // ms
#define L2CAP_BREDR_MAX_PAYLOAD 1019 // 3-DH5 包的有效载荷
#define L2CAP_LE_MIN_MTU 23
#define LE_FLOWCTL_MAX_CREDITS 65535// include/net/bluetooth/bluetooth.h:133-156
#define BT_PHY_LE_1M_TX BIT(9)
#define BT_PHY_LE_1M_RX BIT(10)
#define BT_PHY_LE_2M_TX BIT(11)
#define BT_PHY_LE_2M_RX BIT(12)
#define BT_PHY_LE_CODED_TX BIT(13) // LE Coded PHY(长距离)
#define BT_PHY_LE_CODED_RX BIT(14)net/bluetooth/hci_sync.c(7522 行)是 2021 年 Intel 引入的 HCI 同步命令执行框架,旨在替代旧有的异步 hci_request 机制。它提供了一套可串行化的命令队列,使得初始化和配置流程可以以同步的方式描述,极大简化了状态机编写。
核心设计思路:将需要等待响应的 HCI 命令序列封装为可排队的工作项(work entry),在专用工作队列上顺序执行,通过 wait_event_interruptible 等待命令完成。
hci_sync.c 第 23-49 行实现了同步完成回调:
// hci_sync.c:23
static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
struct sk_buff *skb)
{
if (hdev->req_status != HCI_REQ_PEND)
return;
hdev->req_result = result;
hdev->req_status = HCI_REQ_DONE;
// 释放请求 skb,避免作为响应被再次使用
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
if (skb) {
// 保存响应 skb,供调用者读取返回值
hdev->req_rsp = skb_get(skb);
}
wake_up_interruptible(&hdev->req_wait_q); // 唤醒等待的同步调用者
}hci_cmd_sync_alloc()(第 51-80 行)负责分配带完整 HCI 头的 SKB:
// hci_sync.c:51
struct sk_buff *hci_cmd_sync_alloc(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, struct sock *sk)
{
int len = HCI_COMMAND_HDR_SIZE + plen;
struct hci_command_hdr *hdr;
struct sk_buff *skb;
skb = bt_skb_alloc(len, GFP_ATOMIC);
hdr = skb_put(skb, HCI_COMMAND_HDR_SIZE);
hdr->opcode = cpu_to_le16(opcode);
hdr->plen = plen;
if (plen)
skb_put_data(skb, param, plen);
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
hci_skb_opcode(skb) = opcode;
// 绑定发起 socket(用于 MGMT 响应路由)
if (sk) {
hci_skb_sk(skb) = sk;
sock_hold(sk);
}
return skb;
}hci_sync.c 提供了两级提交接口:
hci_cmd_sync_submit()(第 702-733 行):无条件提交,要求设备未注销:
// hci_sync.c:702
int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
mutex_lock(&hdev->unregister_lock);
if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
err = -ENODEV;
goto unlock;
}
entry = kmalloc_obj(*entry);
entry->func = func;
entry->data = data;
entry->destroy = destroy;
mutex_lock(&hdev->cmd_sync_work_lock);
list_add_tail(&entry->list, &hdev->cmd_sync_work_list);
mutex_unlock(&hdev->cmd_sync_work_lock);
queue_work(hdev->req_workqueue, &hdev->cmd_sync_work); // 触发工作队列
...
}hci_cmd_sync_queue()(第 739-750 行):额外检查设备是否处于运行状态(HCI_RUNNING):
// hci_sync.c:739
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -ENETDOWN;
return hci_cmd_sync_submit(hdev, func, data, destroy);
}
EXPORT_SYMBOL(hci_cmd_sync_queue);hci_cmd_sync_queue_once()(第 779-787 行):幂等版本,若相同函数已在队列中则不重复添加。
hdev->cmd_sync_work (work_struct)
|
v hci_cmd_sync_work()
|
v mutex_lock(&hdev->cmd_sync_work_lock)
v 取出下一个 entry(list_first_entry)
v mutex_unlock
|
v entry->func(hdev, entry->data)
(可在函数内部调用 __hci_cmd_sync、__hci_cmd_sync_status 等)
|
v if (entry->destroy)
entry->destroy(hdev, entry->data, err)
|
v kfree(entry)
|
v 若队列非空,重新 queue_work
hci_sync.c 第 3645-3648 行定义了初始化阶段描述宏:
// hci_sync.c:3645
#define HCI_INIT(_func) \
{ .func = _func }
struct hci_init_stage {
int (*func)(struct hci_dev *hdev);
};利用这个宏,初始化阶段可以用清晰的数组格式描述:
// init1 阶段(基础版本读取,所有设备类型)
static const struct hci_init_stage hci_init1[] = {
HCI_INIT(hci_read_local_version_sync), // 读版本信息
HCI_INIT(hci_read_bd_addr_sync), // 读 BD 地址
{}
};
// init2 阶段(LE 特性读取)
static const struct hci_init_stage le_init2[] = {
HCI_INIT(hci_le_read_local_features_sync), // LE 特性
HCI_INIT(hci_le_read_buffer_size_sync), // LE ACL 缓冲区大小
HCI_INIT(hci_le_read_supported_states_sync), // LE 状态支持
{}
};RFCOMM(Radio Frequency Communication)基于 TS 07.10 协议,在 L2CAP 之上模拟多路串行端口。它是蓝牙 SPP(Serial Port Profile)、HFP(Hands-Free Profile)和 HSP(Headset Profile)的传输基础。
源文件:net/bluetooth/rfcomm/core.c(2286 行)、net/bluetooth/rfcomm/sock.c、net/bluetooth/rfcomm/tty.c(1151 行)
RFCOMM 版本(net/bluetooth/rfcomm/core.c:40):
#define VERSION "1.11"struct rfcomm_session {
struct list_head list; // 挂在全局 session_list
struct socket *sock; // 底层 L2CAP socket
struct timer_list timer; // 空闲超时定时器
unsigned long state; // BT_LISTEN / BT_CONNECTED 等
unsigned long flags; // RFCOMM_TIMED_OUT 等
int initiator; // 1 = 本端发起连接
uint mtu; // 最大传输单元(默认 RFCOMM_DEFAULT_MTU=127)
struct list_head dlcs; // 挂载在本 session 上的 DLC 链表
};DLC(Data Link Connection)是 RFCOMM 上的单个逻辑信道,对应一个虚拟串口:
struct rfcomm_dlc {
struct list_head list; // 挂在 rfcomm_session.dlcs
struct rfcomm_session *session;
struct sk_buff_head tx_queue; // 待发送数据队列
struct timer_list timer; // 连接/断连超时
struct mutex lock;
unsigned long state; // BT_OPEN / BT_CONNECTED 等
unsigned long flags; // RFCOMM_RX_THROTTLED / RFCOMM_TX_THROTTLED 等
u8 dlci; // DLCI = (channel << 1) | direction
u8 addr; // 帧地址字节
u8 priority; // 优先级(默认 7)
u8 sec_level; // 安全级别
uint mtu; // 本 DLC 的 MTU(默认 RFCOMM_DEFAULT_MTU=127)
uint rx_credits; // 接收信用(Credit-based Flow Control)
uint tx_credits; // 发送信用
/* 回调函数 */
void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
void (*state_change)(struct rfcomm_dlc *d, int err);
void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
};include/net/bluetooth/rfcomm.h:43-51 定义了 RFCOMM 帧类型:
#define RFCOMM_SABM 0x2f // Set Asynchronous Balanced Mode(连接建立)
#define RFCOMM_DISC 0x43 // Disconnect(断连)
#define RFCOMM_UA 0x63 // Unnumbered Acknowledgement(确认)
#define RFCOMM_DM 0x0f // Disconnected Mode(拒绝)
#define RFCOMM_UIH 0xef // Unnumbered Information with Header check(数据)
// Multiplexer Control Commands(在 DLCI 0 上传输)
#define RFCOMM_TEST 0x08 // 测试命令
#define RFCOMM_FCON 0x28 // 流量控制开(Flow Control On)帧校验序列(FCS)使用反转 CRC-8 多项式(poly=0x07),rfcomm_crc_table[](core.c:114)是预计算表。
SABM/DISC/UA 帧使用 3 字节 FCS(__fcs2()),UIH 帧只使用 2 字节 FCS(__fcs()):
// core.c:160-168
static inline u8 __fcs(u8 *data)
{
return 0xff - __crc(data); // 2 字节
}
static inline u8 __fcs2(u8 *data)
{
return 0xff - rfcomm_crc_table[__crc(data) ^ data[2]]; // 3 字节
}DLCI(Data Link Connection Identifier)由通道号和方向位计算:
// core.c:87-88
#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir)
#define __srv_channel(dlci) (dlci >> 1)dir:__session_dir(s)— 发起方 dir=0,响应方 dir=1chn:通道号(1-30,即RFCOMM_DEFAULT_CHANNELS=30)- DLCI 0 用于多路复用控制信道(MCC)
RFCOMM 使用专用内核线程(rfcomm_thread)而非工作队列:
// core.c:46
static struct task_struct *rfcomm_thread;主循环(rfcomm_run(),第 2120 行):
static int rfcomm_run(void *unused)
{
BT_DBG("started");
set_user_nice(current, -10); // 提升线程优先级
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
rfcomm_process_sessions(); // 处理所有活动 session
schedule(); // 等待唤醒(rfcomm_schedule())
}
return 0;
}rfcomm_schedule()(第 106-109 行)通过 wake_up_all(&rfcomm_wq) 唤醒线程:
static void rfcomm_schedule(void)
{
wake_up_all(&rfcomm_wq);
}rfcomm_process_sessions()(core.c:2016)遍历所有 session 并按状态分发:
rfcomm_process_sessions()
|
+-- BT_LISTEN --> rfcomm_accept_connection(s)
| (接受新的 L2CAP 连接)
|
+-- BT_BOUND --> rfcomm_check_connection(s)
| (发起 L2CAP 连接)
|
+-- 其他状态 --> rfcomm_process_rx(s)
(处理接收帧)
|
v (所有状态)
rfcomm_process_dlcs(s)
(处理各 DLC 的发送、状态机转换)
MCC 命令通过 DLCI 0 的 UIH 帧传输,在 core.c:1659 的 rfcomm_recv_mcc() 中处理:
// core.c:1659
case RFCOMM_PN: // Parameter Negotiation(协商 MTU、信用数等)
rfcomm_recv_pn(s, cr, skb);
break;
case RFCOMM_MSC: // Modem Status Command(传递 V.24 信号)
rfcomm_recv_msc(s, cr, skb);
break;
case RFCOMM_RPN: // Remote Port Negotiation(波特率、数据格式等)
rfcomm_recv_rpn(s, cr, skb);
break;
case RFCOMM_TEST: // 测试连接质量
rfcomm_recv_test(s, cr, skb);
break;用户调用 connect()
|
v
rfcomm_dlc_open() [core.c:425]
| rfcomm_lock() 保护
v
__rfcomm_dlc_open() [core.c:371]
|
+-- 1. 验证通道号(1-30)
+-- 2. 查找或创建 rfcomm_session(rfcomm_session_get/create)
+-- 3. 计算 DLCI = __dlci(__session_dir(s), channel)
+-- 4. 检查 DLCI 不重复
+-- 5. 将 DLC 链接到 session(rfcomm_dlc_link)
+-- 6. 若 session 已连接:
| rfcomm_check_security() 成功 --> rfcomm_send_pn()
| 否则 --> 设 RFCOMM_AUTH_PENDING
|
v 等待 L2CAP 连接完成
rfcomm_session_add() 创建底层 L2CAP socket
|
v L2CAP 连接成功后
rfcomm_send_sabm(s, dlci) 发送 SABM 帧建立 DLC
|
v 收到 UA 帧
DLC 进入 BT_CONNECTED 状态
rfcomm/tty.c 将每个 RFCOMM DLC 注册为标准 Linux TTY 设备(/dev/rfcommN),通过 tty_port_register_device() 创建设备节点。最多支持 RFCOMM_MAX_DEV = 256 个 TTY 设备。
BNEP(Bluetooth Network Encapsulation Protocol)在 L2CAP PSM=0x000F 上传输以太网帧,实现蓝牙个人局域网(PAN)。它支持三种角色:
- PANU(Personal Area Networking User):点对点用户端
- NAP(Network Access Point):网络接入点(类似 AP)
- GN(Group ad-hoc Network):组网节点
源文件:net/bluetooth/bnep/core.c、net/bluetooth/bnep/netdev.c、net/bluetooth/bnep/sock.c
struct bnep_session {
struct list_head list; // 全局 bnep_session_list
unsigned int role; // BNEP_ROLE_* (PANU/NAP/GN)
unsigned long state;
unsigned long flags;
atomic_t terminate; // 会话终止标志
struct task_struct *task; // 处理线程
struct ethhdr eh; // 以太网头缓存
struct msghdr msg; // L2CAP 消息头
struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
unsigned long long mc_filter; // 多播地址过滤位图(64-bit)
struct socket *sock; // 底层 L2CAP socket
struct net_device *dev; // bnep0 等网络设备
};BNEP 帧头中的类型字段区分以下包类型:
BNEP_GENERAL_ETHERNET 0x00 完整以太网帧
BNEP_CONTROL 0x01 控制命令
BNEP_COMPRESSED_ETHERNET 0x02 目的/源地址省略(仅在建立后可用)
BNEP_COMPRESSED_ETHERNET_SRC_ONLY 0x03
BNEP_COMPRESSED_ETHERNET_DST_ONLY 0x04
接收路径(bnep_rx_frame(),第 298 行):
L2CAP 数据到达
|
v bnep_rx_frame()
|
+-- 控制帧 --> bnep_rx_control()
| (Setup / Filter 命令处理)
|
+-- 数据帧 --> 补全以太网头
--> netif_rx() 注入内核网络栈
bnep/netdev.c 中 bnep_net_setup() 设置以太网设备操作:
void bnep_net_setup(struct net_device *dev)
{
memset(dev->broadcast, 0xff, ETH_ALEN);
dev->hard_header_len = ETH_HLEN;
dev->mtu = ETH_DATA_LEN;
dev->addr_len = ETH_ALEN;
dev->type = ARPHRD_ETHER;
dev->netdev_ops = &bnep_netdev_ops;
dev->ethtool_ops = &bnep_ethtool_ops;
}多播过滤使用 CRC32 哈希(bnep_mc_hash(),bnep.h:168):
static inline int bnep_mc_hash(__u8 *addr)
{
return crc32_be(~0, addr, ETH_ALEN) >> 26; // 取高 6 位 -> 64-bit 位图索引
}HIDP(Human Interface Device Profile)实现了蓝牙 HID 规范,在内核中注册为标准 input 设备或 hid 设备。它使用两条 L2CAP 信道:
- Control 信道(PSM=0x0011):传递 HID 控制命令和报告
- Interrupt 信道(PSM=0x0013):传递实时输入数据(键盘/鼠标事件)
源文件:net/bluetooth/hidp/core.c、net/bluetooth/hidp/sock.c
#define HIDP_TRANS_HANDSHAKE 0x00 // 握手响应
#define HIDP_TRANS_HID_CONTROL 0x10 // HID 控制命令
#define HIDP_TRANS_GET_REPORT 0x40 // 获取报告
#define HIDP_TRANS_SET_REPORT 0x50 // 设置报告
#define HIDP_TRANS_GET_PROTOCOL 0x60 // 获取协议(Boot/Report)
#define HIDP_TRANS_SET_PROTOCOL 0x70 // 设置协议
#define HIDP_TRANS_DATA 0xa0 // 数据传输握手响应码(第 48-55 行):
#define HIDP_HSHK_SUCCESSFUL 0x00 // 成功
#define HIDP_HSHK_NOT_READY 0x01 // 设备未就绪
#define HIDP_HSHK_ERR_INVALID_REPORT_ID 0x02
#define HIDP_HSHK_ERR_UNSUPPORTED_REQUEST 0x03
#define HIDP_HSHK_ERR_INVALID_PARAMETER 0x04
#define HIDP_HSHK_ERR_FATAL 0x0f // 致命错误struct hidp_session {
struct list_head list;
struct bt_sock *conn; // 关联的 bt_sock
struct hid_device *hid; // 注册的 HID 设备
struct input_dev *input; // 注册的 input 设备(Boot Protocol 时)
struct timer_list timer; // 空闲超时
struct socket *ctrl_sock; // Control 信道 socket
struct socket *intr_sock; // Interrupt 信道 socket
struct sk_buff_head ctrl_transmit; // Control 发送队列
struct sk_buff_head intr_transmit; // Interrupt 发送队列
__u8 ctrl_id; // Control 信道连接 ID
__u16 flags; // 会话标志
__u32 idle_to; // 空闲超时时间
...
};L2CAP Control 信道数据到达
|
v hidp_recv_ctrl_frame() [core.c:550]
|
+-- HIDP_TRANS_HANDSHAKE --> hidp_process_handshake()
+-- HIDP_TRANS_HID_CONTROL --> hidp_process_hid_control()
+-- HIDP_TRANS_DATA --> hidp_process_data()
L2CAP Interrupt 信道数据到达
|
v hidp_recv_intr_frame() [core.c:587]
|
+-- HIDP_TRANS_DATA --> hidp_input_report()
(通过 hid_input_report() 注入 input 层)
hidp_input_report()(core.c:178)将收到的 HID 报告通过 hid_input_report() 传递给内核 HID 子系统,最终触发 input_event()(键盘按键、鼠标移动等)。
LE Audio 是蓝牙 5.2 引入的核心特性,基于 ISO(Isochronous)链路提供低延迟、高质量音频传输。Linux 内核通过 BTPROTO_ISO(net/bluetooth/iso.c,2735 行)支持 ISO 层。
ISO 链路分两类:
- CIS(Connected Isochronous Stream):点对点单播等时流,用于 TWS 耳机
- BIS(Broadcast Isochronous Stream):广播等时流,用于广播音频(如广场舞音响)
// iso.c:60
struct iso_pinfo {
struct bt_sock bt;
bdaddr_t src;
__u8 src_type;
bdaddr_t dst;
__u8 dst_type;
__u8 bc_sid; // BIG 的 SID(Sync ID)
__u8 bc_num_bis; // BIS 数量
__u8 bc_bis[ISO_MAX_NUM_BIS]; // BIS 索引列表
__u16 sync_handle; // PA Sync Handle
unsigned long flags; // BT_SK_BIG_SYNC / BT_SK_PA_SYNC
struct bt_iso_qos qos; // QoS 参数
bool qos_user_set; // 用户是否显式设置了 QoS
__u8 base_len;
__u8 base[BASE_MAX_LENGTH]; // BASE(Basic Audio Announcement)
struct iso_conn *conn;
};标志位定义(第 55-58 行):
enum {
BT_SK_BIG_SYNC, // 正在同步 BIG
BT_SK_PA_SYNC, // 正在同步 Periodic Advertising
};struct iso_conn {
struct hci_conn *hcon; // 关联的 HCI ISO 连接
spinlock_t lock;
struct sock *sk;
struct delayed_work timeout_work; // ISO_CONN_TIMEOUT=20s / ISO_DISCONN_TIMEOUT=2s
struct sk_buff *rx_skb; // 正在组装的 SDU
__u32 rx_len;
__u16 tx_sn; // 发送序列号(Sequence Number)
struct kref ref;
};超时常量(第 95-96 行):
#define ISO_CONN_TIMEOUT secs_to_jiffies(20)
#define ISO_DISCONN_TIMEOUT secs_to_jiffies(2)struct bt_iso_qos(include/net/bluetooth/bluetooth.h)是联合体,支持单播和广播两种模式:
bt_iso_qos
├── ucast (struct bt_iso_ucast_qos)
│ ├── cig // CIG ID
│ ├── cis // CIS ID
│ ├── sca // Sleep Clock Accuracy
│ ├── packing // 顺序/交错打包
│ ├── framing // 非分帧/分帧
│ ├── in (struct bt_iso_io_qos) // 入方向 QoS
│ └── out (struct bt_iso_io_qos) // 出方向 QoS
│
└── bcast (struct bt_iso_bcast_qos)
├── big // BIG ID
├── bis // BIS ID
├── sync_factor // 同步因子
├── packing / framing / encryption
├── bcode[16] // 广播加密码(Broadcast Code)
└── in / out (struct bt_iso_io_qos)
struct bt_iso_io_qos {
__u32 interval; // SDU 间隔(微秒)
__u16 latency; // 最大传输延迟(毫秒)
__u16 sdu; // 最大 SDU 大小
__u8 phy; // PHY(BT_ISO_PHY_1M / 2M / CODED)
__u8 rtn; // 最大重传次数
};
CIS(单播)建立流程:
用户 bind() + connect()
|
v iso_connect_cis()
|
v hci_connect_cis() [hci_conn.c]
|
v HCI_LE_Set_CIG_Parameters 命令
(设置 CIG_ID、Sdu_Interval、Latency 等)
|
v HCI_LE_Create_CIS 命令
(创建 CIS 连接,需要 ACL 连接已建立)
|
v LE CIS Established 事件
--> hci_conn 进入 BT_CONNECTED
--> iso_connect_cfm() 通知 socket 层
BIS(广播)建立流程:
用户 bind() + connect()
|
v iso_connect_bis()
|
v hci_connect_bis() [hci_conn.c]
|
v HCI_LE_Create_BIG 命令
(设置 BIG_ID、Num_BIS、SDU_Interval、ISO_Interval 等)
|
v LE Create BIG Complete 事件
--> 创建多个 hci_conn(每个 BIS 一个)
--> 广播开始发送 ISO 数据
BIS 广播包含 BASE 数据结构(iso.c:50-51):
#define EIR_SERVICE_DATA_LENGTH 4
#define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH)
#define EIR_BAA_SERVICE_UUID 0x1851 // Basic Audio Announcement UUIDBASE 包含 Codec_ID、Codec_Config 等信息,接收端(如蓝牙音频头戴耳机)据此选择同步的 BIS 并配置解码器。
LE 扫描分为被动扫描(passive scan)和主动扫描(active scan):
LE_SCAN_PASSIVE = 0x00 仅接收广播包,不发送 SCAN_REQ
LE_SCAN_ACTIVE = 0x01 对可扫描广播者发送 SCAN_REQ,获取 SCAN_RSP
扫描参数的单位为 0.625ms:
| 参数 | 常量 | 值 | 说明 |
|---|---|---|---|
| 快速扫描间隔 | DISCOV_LE_SCAN_INT_FAST |
0x0060 | 60ms |
| 快速扫描窗口 | DISCOV_LE_SCAN_WIN_FAST |
0x0030 | 30ms |
| 慢速扫描间隔 | DISCOV_LE_SCAN_INT_SLOW1 |
0x0800 | 1280ms |
| 慢速扫描窗口 | DISCOV_LE_SCAN_WIN_SLOW1 |
0x0012 | 11.25ms |
| Coded PHY 快速 | DISCOV_CODED_SCAN_INT_FAST |
0x0120 | 180ms |
| Coded PHY 慢速 | DISCOV_CODED_SCAN_INT_SLOW1 |
0x1800 | 3.84s |
(include/net/bluetooth/hci_core.h:2403-2408)
当控制器支持 use_ext_scan(hdev) 时,使用扩展扫描命令(BT 5.0+):
hci_le_set_ext_scan_param_sync()(hci_sync.c:2919)可同时为多个 PHY 设置扫描参数:
// hci_sync.c:2919
static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
u16 interval, u16 window,
u8 own_addr_type, u8 filter_policy)
{
// 为 LE 1M PHY 设置扫描参数
if (scan_1m(hdev) || scan_2m(hdev)) {
cp->scanning_phys |= LE_SCAN_PHY_1M;
hci_le_scan_phy_params(phy, type, interval, window);
num_phy++;
phy++;
}
// 为 LE Coded PHY 设置扫描参数(间隔和窗口扩大 3 倍)
if (scan_coded(hdev)) {
cp->scanning_phys |= LE_SCAN_PHY_CODED;
hci_le_scan_phy_params(phy, type, interval * 3, window * 3);
num_phy++;
phy++;
}
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS, ...);
}Coded PHY 的扫描窗口扩大 3 倍是因为 Coded PHY 的符号速率是 1M PHY 的 1/8(S=8 编码),需要更长时间接收同样长度的广播包。
hci_sync.c 中的 interleave_scan_work()(第 586 行)实现了 Accept List 扫描和无过滤扫描之间的交织调度:
// hci_sync.c:586
static void interleave_scan_work(struct work_struct *work)
{
if (hdev->interleave_scan_state == INTERLEAVE_SCAN_ALLOWLIST) {
timeout = msecs_to_jiffies(hdev->advmon_allowlist_duration);
} else if (hdev->interleave_scan_state == INTERLEAVE_SCAN_NO_FILTER) {
timeout = msecs_to_jiffies(hdev->advmon_no_filter_duration);
}
// 定时切换:ALLOWLIST <--> NO_FILTER
queue_delayed_work(hdev->req_workqueue,
&hdev->interleave_scan, timeout);
}这是为了在节能的同时兼顾广播监控(Advertising Monitor)功能:用大部分时间扫描白名单设备,少部分时间扫描所有设备以支持广播监控。
通过 MSFT 扩展或 LE Advertising Filter HCI 命令可以将广播过滤下推到硬件:
用户空间 --> MGMT_OP_ADD_ADV_PATTERNS_MONITOR
|
v mgmt.c 处理
|
v msft_add_address_filter_sync() [msft.c:956]
使用 Microsoft 厂商扩展命令将 RSSI 阈值、UUID 等过滤条件
卸载到 HCI 控制器硬件,减少软件处理开销
|
v 匹配到设备时 --> MGMT_EV_ADV_MONITOR_DEVICE_FOUND 通知用户态
hci_setup_ext_adv_instance_sync()(hci_sync.c:1330)处理扩展广播实例参数设置,核心是根据广播类型填充 hci_cp_le_set_ext_adv_params 结构:
// hci_sync.c:1397-1415
if (connectable) {
if (secondary_adv)
cp.evt_properties = cpu_to_le16(LE_EXT_ADV_CONN_IND); // 可连接扩展广播
else
cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_IND); // 传统可连接广播
} else if (hci_adv_instance_is_scannable(hdev, instance)) {
if (secondary_adv)
cp.evt_properties = cpu_to_le16(LE_EXT_ADV_SCAN_IND); // 可扫描扩展广播
else
cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_SCAN_IND); // 传统可扫描广播
} else {
if (secondary_adv)
cp.evt_properties = cpu_to_le16(LE_EXT_ADV_NON_CONN_IND); // 不可连接扩展广播
else
cp.evt_properties = cpu_to_le16(LE_LEGACY_NONCONN_IND); // 传统不可连接广播
}secondary_adv 为真时表示使用辅助广播信道(Secondary Advertising Channel),是蓝牙 5.0 扩展广播的核心特性。
| 特性 | 版本 | 内核支持位置 |
|---|---|---|
| LE 2M PHY | BT 5.0 | hci_sync.c:4874,le_2m_capable() |
| LE Coded PHY | BT 5.0 | hci_sync.c:4879,le_coded_capable() |
| Extended Advertising | BT 5.0 | hci_sync.c:1330,ext_adv_capable() |
| Extended Scanning | BT 5.0 | hci_sync.c:2919,use_ext_scan() |
| Periodic Advertising | BT 5.0 | hci_sync.c,per_adv_capable() |
| LL Privacy(地址解析) | BT 4.2 | ll_privacy_capable() |
| LE Audio (ISO/CIS/BIS) | BT 5.2 | net/bluetooth/iso.c |
| Enhanced ATT (EATT) | BT 5.3 | L2CAP ECRED 支持 |
LE Coded PHY 使用前向纠错(FEC)编码,以牺牲速率换取更远的传输距离(最远 ~1km):
- S=2 编码:数据速率 500Kbps,距离约 2 倍于 1M PHY
- S=8 编码:数据速率 125Kbps,距离约 4 倍于 1M PHY
内核中的能力检测(include/net/bluetooth/hci_core.h:1986):
// include/net/bluetooth/hci_core.h:1986
#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED) && \
!hci_test_quirk((dev), HCI_QUIRK_BROKEN_LE_CODED))HCI_QUIRK_BROKEN_LE_CODED 用于屏蔽报告支持 Coded PHY 但实际实现有缺陷的控制器。
扫描是否使用 Coded PHY 由 scan_coded() 决定(hci_core.h:1990):
#define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))Coded PHY 扫描参数(快速发现模式,hci_core.h:2403):
#define DISCOV_CODED_SCAN_INT_FAST 0x0120 // 180ms 扫描间隔
#define DISCOV_CODED_SCAN_WIN_FAST 0x0090 // 90ms 扫描窗口
#define DISCOV_CODED_SCAN_INT_SLOW1 0x1800 // 3.84s 扫描间隔(慢速模式)
#define DISCOV_CODED_SCAN_WIN_SLOW1 0x0036 // 33.75ms 扫描窗口2M PHY 将 LE 数据速率从 1Mbps 提升到 2Mbps,降低空中延迟。
初始化时在 hci_le_set_default_phy_sync()(hci_sync.c:4855)中配置默认 PHY:
// hci_sync.c:4855
static int hci_le_set_default_phy_sync(struct hci_dev *hdev)
{
// 默认启用 1M PHY
cp.tx_phys = HCI_LE_SET_PHY_1M; // 0x01
cp.rx_phys = HCI_LE_SET_PHY_1M;
// 若支持 2M PHY,同时启用
if (le_2m_capable(hdev)) {
cp.tx_phys |= HCI_LE_SET_PHY_2M; // 0x02
cp.rx_phys |= HCI_LE_SET_PHY_2M;
}
// 若支持 Coded PHY,同时启用
if (le_coded_capable(hdev)) {
cp.tx_phys |= HCI_LE_SET_PHY_CODED; // 0x04
cp.rx_phys |= HCI_LE_SET_PHY_CODED;
}
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEFAULT_PHY,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}PHY 位定义(include/net/bluetooth/hci.h:1884):
#define HCI_LE_SET_PHY_1M 0x01
#define HCI_LE_SET_PHY_2M 0x02
#define HCI_LE_SET_PHY_CODED 0x04连接建立后可以通过 hci_le_set_phy() 动态切换 PHY:
// hci_sync.c:7506
int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
{
cp->handle = cpu_to_le16(conn->handle);
cp->tx_phys = tx_phys;
cp->rx_phys = rx_phys;
// 使用 queue_once 避免重复排队
return hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
le_phy_update_complete);
}内部通过 HCI_OP_LE_SET_PHY 命令发送,等待 HCI_EV_LE_PHY_UPDATE_COMPLETE 事件确认(hci_sync.c:7500)。
扩展广播(Extended Advertising)支持最大 254 字节广播数据(Legacy 广播只有 31 字节),且可在辅助信道(Secondary Advertising Channel)上传输,实现更灵活的广播场景。
传统广播包(Legacy):
ADV_IND | ADV_NONCONN_IND | ADV_SCAN_IND (主信道,最大 31 字节)
|
v
扩展广播包(Extended,BT 5.0+):
ADV_EXT_IND (主信道,包含 AuxPtr 指向辅助信道)
|
v 通过 AuxPtr 跳转
AUX_ADV_IND (辅助信道,最大 254 字节)
|
v 若数据更长,通过 AuxPtr 链式传递
AUX_CHAIN_IND (辅助信道后续帧)
hci_set_ext_adv_data_sync()(hci_sync.c:1257):
// hci_sync.c:1257
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
{
DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
HCI_MAX_EXT_AD_LENGTH);
// 分片操作:若数据超过单次传输长度,需要分多帧传输
// Operation: 0x00=中间帧, 0x01=首帧, 0x02=末帧, 0x03=完整数据
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA, ...);
return err;
}ext_adv_capable() 宏(hci_core.h:2023):
#define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))HCI_LE_EXT_ADV 位(include/net/bluetooth/hci.h:647):
#define HCI_LE_EXT_ADV 0x10 // le_features[1] 第 4 位周期广播允许广播者以固定周期发送数据,接收者通过同步流程加入:
- 广播者:
HCI_OP_LE_SET_PER_ADV_PARAMS+HCI_OP_LE_SET_PER_ADV_DATA+HCI_OP_LE_SET_PER_ADV_ENABLE - 接收者:
HCI_OP_LE_PA_CREATE_SYNC(通过 Extended Scan 发现广播者后同步)
内核能力检测(hci_core.h:2040):
#define per_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_PERIODIC_ADV))LE 隐私保护通过可解析私有地址(RPA,Resolvable Private Address)实现,防止蓝牙地址被追踪:
RPA 生成:
random_part = rand[22 bits] (随机)
hash = ah(IRK, random_part)[24 bits]
RPA = hash[24 bits] || random_part[24 bits] || 0b11[2 bits]
RPA 解析:
已知 IRK 时,验证 ah(IRK, random_part) == hash 即可确认是同一设备
LL Privacy(控制器层隐私)能力检测(hci_core.h:1993):
#define ll_privacy_capable(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
#define ll_privacy_enabled(dev) (le_enabled(dev) && ll_privacy_capable(dev))当 ll_privacy_capable 时,地址解析和 RPA 生成卸载到控制器,通过 HCI_OP_LE_ADD_DEVICE_TO_RESOLV_LIST 命令管理 Resolving List。
smp_register()(smp.c:3404)在每个支持 LE 的 HCI 设备初始化时被调用,创建对应的 L2CAP 固定信道:
// smp.c:3404
int smp_register(struct hci_dev *hdev)
{
if (!lmp_le_capable(hdev))
return 0;
// 注册 LE SMP 信道(CID=0x0006)
chan = smp_add_cid(hdev, L2CAP_CID_SMP);
hdev->smp_data = chan;
// 若支持 SC(Secure Connections)或强制启用 BR/EDR SMP,
// 同时注册 BR/EDR SMP 信道(CID=0x0007)
if (!lmp_sc_capable(hdev)) {
if (!hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP))
return 0;
}
chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR);
hdev->smp_bredr_data = chan;
return 0;
}SMP 配对请求(Pairing Request,命令码 0x01)和配对响应(Pairing Response,0x02)均为 7 字节:
字节 0: 命令码(0x01 / 0x02)
字节 1: IO Capability
0x00 = DisplayOnly
0x01 = DisplayYesNo
0x02 = KeyboardOnly
0x03 = NoInputNoOutput
0x04 = KeyboardDisplay
字节 2: OOB 数据标志(0x00=无 / 0x01=有)
字节 3: AuthReq 位域
bit[0] = Bonding_Flags[0]
bit[1] = Bonding_Flags[1](01=Bonding)
bit[2] = MITM
bit[3] = SC(Secure Connections)
bit[4] = Keypress
bit[5] = CT2(h7 函数)
字节 4: Maximum Encryption Key Size(7-16)
字节 5: Initiator Key Distribution
字节 6: Responder Key Distribution
smp_chan->preq[7] / smp_chan->prsp[7] 分别缓存请求和响应 PDU(smp.c:96)。
根据双方的 IO Capability 和 MITM 要求选择关联模型:
响应方
| DisplayOnly | DisplayYesNo | KeyboardOnly | NoInputNoOutput | KeyboardDisplay
发起 |
方 |
-----+-------------------------------------------------------------------
DisplayOnly | JW | JW | Passkey | JW | Passkey
DisplayYesNo | JW | NC | Passkey | JW | NC/Passkey
KeyboardOnly | PK | PK | PK | JW | PK
NoInputNoOutput | JW | JW | JW | JW | JW
KeyboardDisplay | PK | NC | PK | JW | NC/PK
JW = Just Works, NC = Numeric Comparison, PK = Passkey Entry
MITM=0 时强制使用 Just Works;MITM=1 则按上表选择。
LE SC 的 Passkey Entry 不同于 Legacy 配对,需要对 20 位 passkey 的每一位进行独立的 Confirm/Random 交换:
for i in 0..19:
发起方:
ra = random()
Confirm_a = f4(PKa, PKb, ra, passkey_bit_i)
发送 SMP_CMD_PAIRING_CONFIRM(Confirm_a)
响应方:
rb = random()
Confirm_b = f4(PKb, PKa, rb, passkey_bit_i)
接收 Confirm_a,发送 SMP_CMD_PAIRING_CONFIRM(Confirm_b)
双方交换 Random(SMP_CMD_PAIRING_RANDOM)后验证 Confirm 值
若所有 20 位验证通过,继续 DHKey Check 流程
OOB 数据通过带外通道(如 NFC)传递,包含:
- 本地随机数(
smp_generate_oob()第 538 行):16 字节 - 本地 OOB 哈希:
smp_f4(pk, pk, rand, 0)结果
// smp.c:538
int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
{
struct smp_dev *smp = hdev->smp_data;
// 生成本地随机数
get_random_bytes(smp->local_rand, 16);
memcpy(rand, smp->local_rand, 16);
// 计算哈希值:f4(local_pk, local_pk, local_rand, 0)
err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk,
smp->local_rand, 0, hash);
return err;
}配对完成后,双方按 Key Distribution 字段进行密钥交换:
密钥分发字段位:
bit[0] = EncKey -> LTK + EDIV + Rand(Legacy 配对)
bit[1] = IdKey -> IRK + Identity Address
bit[2] = Sign -> CSRK(Connection Signature Resolving Key)
bit[3] = LinkKey -> BR/EDR Link Key(LE SC 跨传输密钥派生)
交叉传输密钥派生(SMP_LTK_P256 -> BR/EDR Link Key)使用 h6() / h7() 函数(由 CT2 标志控制),允许 LE SC 配对后同时获得 BR/EDR 密钥,无需再次配对。
从 MGMT_REVISION 20 开始,内核蓝牙子系统通过 MGMT 接口为 Bluetooth Mesh 提供基础支持。Mesh 网络使用 LE 广播作为传输载体,通过 MGMT 层为用户态 Mesh 栈(如 BlueZ mesh daemon)提供收发接口。
相关 MGMT 命令(include/net/bluetooth/mgmt.h):
| 命令 | 操作码 | 说明 |
|---|---|---|
MGMT_OP_SET_MESH_RECEIVER |
0x0057 | 启用/禁用 Mesh 广播接收 |
MGMT_OP_MESH_READ_FEATURES |
0x0058 | 读取 Mesh 特性(最大句柄数等) |
MGMT_OP_MESH_SEND |
0x0059 | 发送 Mesh 广播包 |
MGMT_OP_MESH_SEND_CANCEL |
0x005A | 取消待发送的 Mesh 包 |
mgmt.h:852:
// mgmt.h:852
#define MGMT_OP_SET_MESH_RECEIVER 0x0057
struct mgmt_cp_set_mesh {
__u8 enable; // 0=禁用,1=启用
__le16 window; // 扫描窗口(单位 0.625ms)
__le16 period; // 扫描周期(单位 0.625ms)
__u8 num_ad_types; // 过滤的 AD Type 数量
__u8 ad_types[] __counted_by(num_ad_types); // AD Type 列表
} __packed;mgmt.h:872:
// mgmt.h:872
#define MGMT_OP_MESH_SEND 0x0059
struct mgmt_cp_mesh_send {
struct mgmt_addr_info addr; // 目标地址(Mesh 中通常为广播)
__le64 instant; // 发送时刻(绝对时间)
__le16 delay; // 延迟(微秒)
__u8 cnt; // 重复发送次数
__u8 adv_data_len;
__u8 adv_data[]; // 广播数据(包含 Mesh PDU)
} __packed;// mgmt.h:865
#define MESH_HANDLES_MAX 3 // 最多同时存在 3 个 Mesh 发送句柄
struct mgmt_rp_mesh_read_features {
__le16 index; // HCI 设备索引
__u8 max_handles; // 最大句柄数(= MESH_HANDLES_MAX = 3)
__u8 used_handles; // 当前使用的句柄数
__u8 handles[MESH_HANDLES_MAX]; // 已分配的句柄列表
} __packed;// mgmt.h:1194
#define MGMT_EV_MESH_PACKET_CMPLT 0x0032
// mgmt.c:1082
static void mesh_send_complete(struct hci_dev *hdev,
struct mgmt_mesh_tx *mesh_tx, bool silent)
{
u8 handle = mesh_tx->handle;
if (!silent)
mgmt_event(MGMT_EV_MESH_PACKET_CMPLT, hdev, &handle,
sizeof(handle), NULL);
mgmt_mesh_remove(mesh_tx);
}silent=true 时不发送事件(如取消发送),silent=false 时发送 MGMT_EV_MESH_PACKET_CMPLT 通知用户态发送已完成。
启用 Mesh 接收后,匹配到指定 AD Type 的广播包会通过 MGMT_EV_MESH_DEVICE_FOUND(0x0031)事件上报给用户态 Mesh 栈,由用户态解析 Mesh PDU 并处理网络层逻辑(如中继、加密、分组等)。内核仅提供收发通道,不实现 Mesh 网络协议栈本身。
A2DP(Advanced Audio Distribution Profile)是蓝牙立体声音频标准,使用 AVDTP(Audio/Video Distribution Transport Protocol)作为传输协议。
重要:A2DP/AVDTP 的核心逻辑在用户空间(PulseAudio/PipeWire + BlueZ 插件)实现,内核仅提供必要的 socket 原语。
用户空间通过以下接口与内核交互:
PipeWire / PulseAudio
|
v socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)
connect() 到 PSM=0x0019 (AVDTP)
|
v L2CAP 连接建立(BR/EDR ACL 链路)
协商 MTU = 672 (AVDTP 默认)
|
v AVDTP 信令(Discover / GetCapabilities / SetConfiguration / Open)
|
v 打开媒体传输信道(另一条 L2CAP 连接)
|
v AVDTP_DATA(SBC/AAC/aptX 编码数据)通过媒体信道传输
BTPROTO_AVDTP = 7 在内核中注册锁类(af_bluetooth.c:57),但协议本身不在内核实现。
虽然 AVDTP 协议在用户态实现,但以下内核功能为 A2DP 提供支撑:
- L2CAP 流媒体模式(Streaming Mode):
L2CAP_MODE_STREAMING = 0x04,针对音频优化,无重传,低延迟 - HCI_CODEC 管理:
net/bluetooth/hci_codec.c管理控制器支持的编解码器,通过BT_CODECsocket 选项查询 - 宽带语音:
BTUSB_WIDEBAND_SPEECH标志,支持 mSBC 16kHz 采样语音(HFP HD Voice) - SCO/eSCO 链路:用于 HSP/HFP 语音通话,
hci_conn.c第 52-68 行定义了esco_param_cvsd等参数
// net/bluetooth/hci_codec.c
// 通过 HCI_OP_READ_LOCAL_CODEC_CAPABILITIES 读取控制器支持的编解码器
// 存储在 hdev->local_codecs 链表中
// 用户空间通过 BT_CODEC socket 选项(值=19)查询PCM 音频数据(来自麦克风/音乐播放器)
|
v 编码(SBC / AAC / aptX / LC3)
|
v AVDTP 媒体包格式封装
RTP Header(2 字节)+ AVDTP Header(12 字节)+ 编码数据
|
v write() -> L2CAP Streaming Mode socket
|
v L2CAP Core -> HCI ACL 数据 -> btusb -> USB -> 蓝牙控制器
|
v 无线传输(BR/EDR 2.4GHz)
|
v 接收端蓝牙芯片 -> 解码 -> DAC -> 扬声器
hci_init_sync()(hci_sync.c:4913)将 HCI 初始化分为四个阶段:
// hci_sync.c:4913
static int hci_init_sync(struct hci_dev *hdev)
{
// Stage 1:基础信息读取(所有设备类型)
err = hci_init1_sync(hdev); // 行 4917
// 创建基础 debugfs 文件
if (hci_dev_test_flag(hdev, HCI_SETUP))
hci_debugfs_create_basic(hdev);
// Stage 2:LE / BR/EDR 特性扩展读取
err = hci_init2_sync(hdev); // 行 4924
// Stage 3:进阶功能配置(SSP、EIR、事件掩码等)
err = hci_init3_sync(hdev); // 行 4928
// Stage 4:LE 高级功能(PHY、数据长度扩展)
err = hci_init4_sync(hdev); // 行 4932
}hci_init1_sync()
|
+-- hci_read_local_version_sync() // HCI_OP_READ_LOCAL_VERSION
+-- hci_read_bd_addr_sync() // HCI_OP_READ_BD_ADDR
hci_init2_sync()
|
+-- [LE 支持]
| +-- hci_le_read_local_features_sync() // LE 特性位图
| +-- hci_le_read_buffer_size_sync() // LE ACL 缓冲区大小
| +-- hci_le_read_supported_states_sync() // LE 支持的状态
|
+-- [BR/EDR 支持]
| +-- hci_read_buffer_size_sync() // ACL/SCO 缓冲区大小
| +-- hci_read_local_name_sync() // 本地设备名
| +-- hci_read_voice_setting_sync() // 语音设置
| +-- hci_read_local_ext_features_1_sync() // LMP 扩展特性 Page 1
...
hci_init3_sync()
|
+-- hci_set_event_mask_sync() // 设置 HCI 事件掩码
+-- hci_read_local_cmds_sync() // 读取支持的命令列表
+-- hci_write_ssp_mode_1_sync() // 启用 Simple Secure Pairing
+-- hci_write_eir_sync() // 写扩展查询响应数据
+-- hci_write_inquiry_mode_sync() // 设置查询模式(RSSI/EIR)
+-- hci_write_auth_enable_sync() // 设置认证模式
+-- [LE 支持]
| +-- hci_le_set_event_mask_sync() // LE 事件掩码
| +-- hci_le_read_adv_tx_power_sync()
| +-- hci_le_read_resolv_list_size_sync()
...
hci_init4_sync()
|
+-- le_init4[]
| +-- hci_le_set_write_def_data_len_sync() // LE 数据长度扩展(DLE)
| +-- hci_le_set_default_phy_sync() // 设置默认 PHY(1M/2M/Coded)
|
+-- [支持 SC(Secure Connections)时]
| +-- hci_le_read_local_oob_ext_data() // 读取 OOB 扩展数据
...
HCI_INIT() 宏(hci_sync.c:3645)使初始化序列以声明式数组描述,每个元素是一个函数指针:
// hci_sync.c:3645
#define HCI_INIT(_func) \
{ .func = _func }
static const struct hci_init_stage le_init4[] = {
HCI_INIT(hci_le_set_write_def_data_len_sync),
HCI_INIT(hci_le_set_default_phy_sync),
{} // 哨兵元素(func=NULL 表示结束)
};hci_init_stage_sync()(hci_sync.c:3615)遍历数组并依次调用每个函数,任一函数失败则中止并返回错误。
蓝牙控制器的开关电由 hci_dev.power_on / power_off 工作项驱动,最终调用 hdev->open() / hdev->close()。
MGMT 通过 MGMT_OP_SET_POWERED 控制:
bluetoothd: MGMT_OP_SET_POWERED(enable=1)
|
v set_powered_sync() [mgmt.c]
|
v hci_power_on_sync() [hci_sync.c]
|
v hdev->open() [btusb_open / hci_uart_open 等]
|
v hci_init_sync() (四阶段初始化)
|
v hci_dev_set_flag(hdev, HCI_UP)
|
v mgmt_powered(hdev, 1) 通知 bluetoothd
btusb.c 通过 USB PM 机制支持自动挂起。当无活动连接时,USB 设备进入低功耗状态(usb_enable_autosuspend())。
系统休眠时,蓝牙子系统通过 hci_suspend_notifier 监听 PM 事件:
// hci_core.c
static int hci_suspend_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
switch (action) {
case PM_SUSPEND_PREPARE:
// 停止发现、配置唤醒过滤器(Wakeup filter)
// 仅保留允许唤醒系统的设备的扫描
hci_suspend_dev(hdev);
break;
case PM_POST_SUSPEND:
// 恢复正常扫描参数
hci_resume_dev(hdev);
break;
}
}MGMT 事件 MGMT_EV_CONTROLLER_SUSPEND / MGMT_EV_CONTROLLER_RESUME 通知用户态。
通过 /sys/class/rfkill/rfkillN/state 写 0 可软关闭蓝牙,效果等同于 MGMT_OP_SET_POWERED(0):
// hci_core.c(rfkill 回调)
static int hci_rfkill_set_block(void *data, bool blocked)
{
struct hci_dev *hdev = data;
if (!blocked)
return 0; // 解除软封锁:由 bluetoothd 决定是否上电
// 软封锁:强制关闭控制器
hci_dev_do_close(hdev);
return 0;
}本节通过一个完整的 LE 连接数据发送示例,追踪数据从用户空间到硬件的完整路径。
应用程序通过 BTPROTO_L2CAP socket 向 LE 对端设备的 GATT 服务发送 ATT Write Command。
应用程序:
fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
connect(fd, &addr, sizeof(addr)); // LE 连接,CID=4(ATT)
write(fd, data, len);
|
v 系统调用进入内核
v l2cap_sock_sendmsg() [l2cap_sock.c]
l2cap_sock_sendmsg()
|
v l2cap_chan_send() [l2cap_core.c]
|
+-- LE_FLOWCTL 模式:
| 检查 tx_credits > 0
| 若 credits 耗尽,将 skb 挂入 l2cap_chan->tx_q
|
v l2cap_create_le_flowctl_pdu()
生成 LE Credit Based Frame(K-Frame)
|
v l2cap_do_send()
|
v hci_send_acl(conn->hcon, hchan, skb, flags)
hci_send_acl()
|
v bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT
v skb_queue_tail(&conn->data_q, skb) // 入连接发送队列
|
v hci_sched_acl() 或 queue_work(&hdev->tx_work)
|
v hci_tx_work() [hci_core.c]
|
v while (acl_cnt > 0 && !skb_queue_empty(&conn->data_q)):
skb = skb_dequeue(&conn->data_q)
hdev->acl_cnt--
hdev->send(hdev, skb) // 调用传输层发送
btusb_send_frame() [drivers/bluetooth/btusb.c]
|
v switch (hci_skb_pkt_type(skb)):
case HCI_ACLDATA_PKT:
usb_fill_bulk_urb(urb, data->udev,
usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress),
skb->data, skb->len,
btusb_bulk_out_complete, skb);
|
v usb_submit_urb(urb, GFP_ATOMIC)
提交到 USB Host Controller
USB 发送完成(URB complete callback):
|
v btusb_bulk_out_complete()
|
v 若成功:hdev->acl_cnt++
queue_work(&hdev->tx_work) // 继续发送队列中的下一个包
对端 LE 数据接收后发送 Number of Completed Packets 事件:
|
v hci_event.c: hci_num_comp_pkts_evt()
hdev->acl_cnt += num_completed // 恢复发送配额
hci_sched_acl(hdev) // 调度更多数据发送
应用层 L2CAP HCI Core btusb 硬件
| | | | |
|-- write() -----> | | | |
| |-- l2cap_do_send -->| | |
| | |-- skb入data_q->| |
| | | | |
| | hci_tx_work | |
| | |--hdev->send -->| |
| | | |--URB submit->|
| | | | |
| | | |<-URB done -- |
| | | acl_cnt++ |
| | | | |
| | (对端返回 Num Completed Pkts 事件) |
| | |<-- HCI Event--| |
| | acl_cnt+=completed | |
| | hci_sched_acl() | |
| 步骤 | 函数 | 文件:行号 |
|---|---|---|
| 用户 write() | l2cap_sock_sendmsg() |
net/bluetooth/l2cap_sock.c |
| L2CAP 分帧 | l2cap_create_le_flowctl_pdu() |
net/bluetooth/l2cap_core.c |
| HCI 排队 | hci_send_acl() |
net/bluetooth/hci_core.c |
| HCI TX 调度 | hci_tx_work() |
net/bluetooth/hci_core.c |
| USB 发送 | btusb_send_frame() |
drivers/bluetooth/btusb.c |
| 发送配额恢复 | hci_num_comp_pkts_evt() |
net/bluetooth/hci_event.c |
// include/net/bluetooth/hci_core.h:338-339
#define HCI_CONN_HANDLE_MAX 0x0eff
#define HCI_CONN_HANDLE_UNSET(_handle) (_handle > HCI_CONN_HANDLE_MAX)// include/net/bluetooth/l2cap.h:34-60
#define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_TX_WINDOW 63
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 // ms
#define L2CAP_DEFAULT_MONITOR_TO 12000 // ms
#define L2CAP_DEFAULT_ACK_TO 200 // ms
#define L2CAP_BREDR_MAX_PAYLOAD 1019 // 3-DH5 包的有效载荷
#define L2CAP_LE_MIN_MTU 23
#define LE_FLOWCTL_MAX_CREDITS 65535// include/net/bluetooth/bluetooth.h:133-156
#define BT_PHY_LE_1M_TX BIT(9)
#define BT_PHY_LE_1M_RX BIT(10)
#define BT_PHY_LE_2M_TX BIT(11)
#define BT_PHY_LE_2M_RX BIT(12)
#define BT_PHY_LE_CODED_TX BIT(13) // LE Coded PHY(长距离)
#define BT_PHY_LE_CODED_RX BIT(14)// include/net/bluetooth/hci.h:644-648
#define HCI_LE_PHY_CODED 0x08 // le_features[1] 第 3 位:Coded PHY 支持
#define HCI_LE_EXT_ADV 0x10 // le_features[1] 第 4 位:扩展广播支持
#define HCI_LE_PERIODIC_ADV 0x20 // le_features[1] 第 5 位:周期广播支持// include/net/bluetooth/hci.h:1884
#define HCI_LE_SET_PHY_1M 0x01
#define HCI_LE_SET_PHY_2M 0x02
#define HCI_LE_SET_PHY_CODED 0x04// include/net/bluetooth/rfcomm.h:29-32
#define RFCOMM_CONN_TIMEOUT (HZ * 30) // 30 秒连接超时
#define RFCOMM_DISC_TIMEOUT (HZ * 20) // 20 秒断连超时
#define RFCOMM_AUTH_TIMEOUT (HZ * 25) // 25 秒认证超时
#define RFCOMM_IDLE_TIMEOUT (HZ * 2) // 2 秒空闲后关闭 session#define SMP_TIMEOUT secs_to_jiffies(30) // 配对超时 30 秒#define ISO_CONN_TIMEOUT secs_to_jiffies(20) // CIS 连接超时 20 秒
#define ISO_DISCONN_TIMEOUT secs_to_jiffies(2) // 断连确认超时 2 秒#define MGMT_OP_SET_MESH_RECEIVER 0x0057
#define MGMT_OP_MESH_READ_FEATURES 0x0058
#define MGMT_OP_MESH_SEND 0x0059
#define MGMT_OP_MESH_SEND_CANCEL 0x005A
#define MGMT_EV_MESH_DEVICE_FOUND 0x0031
#define MGMT_EV_MESH_PACKET_CMPLT 0x0032
#define MESH_HANDLES_MAX 3由 Claude Code 分析生成