4. 蓝牙协议栈架构:Host层与Controller层划分、HCI接口、L2CAP、ATT/GATT、SM(安全管理)层详解
做蓝牙网关这些年,我见过不少工程师一上来就撸代码,结果被协议栈折腾得死去活来。其实,搞懂蓝牙协议栈的分层架构,比多写几行代码重要得多。今天咱们就把这层窗户纸捅破。
4.1 Host层与Controller层:为什么非要拆开?
蓝牙协议栈最核心的设计思想,就是分层。它把整个协议栈砍成两大块:Controller(控制器)和Host(主机)。
你想想看,一个蓝牙芯片既要管射频收发,又要跑协议栈上层逻辑,还要处理应用数据,全揉在一起,调试起来得多痛苦?
我个人习惯把Controller理解为“硬件干活的那部分”,Host则是“软件动脑子的那部分”。
| 层级 | 包含内容 | 典型实现 |
|---|---|---|
| Controller | 物理层(PHY)、链路层(LL)、直接测试模式 | 蓝牙SoC内部固件、射频硬件 |
| Host | L2CAP、ATT、GATT、SM、GAP | 运行在MCU或应用处理器上的协议栈软件 |
我在一个低功耗门锁项目里遇到过这样的坑:当时为了省成本,选了一颗集成度很高的蓝牙芯片,Host和Controller都在同一颗芯片里。结果调试广播参数时,每次改配置都要重新烧录整个固件,效率极低。后来换了支持HCI分离的芯片,Host跑在主MCU上,Controller跑在蓝牙模组上,开发效率直接翻倍。
核心要点:Controller负责实时性要求高的底层操作(如跳频、重传、加密),Host负责逻辑复杂的上层协议。两者通过HCI接口通信,这种分离设计让蓝牙既能跑在单芯片上,也能跑在双芯片架构上。
4.2 HCI接口:Host和Controller的“翻译官”
HCI(Host Controller Interface)说白了就是Host和Controller之间的通信协议。它定义了命令、事件、数据三种类型的包。
- 命令包:Host发给Controller,比如“开始扫描”、“建立连接”。
- 事件包:Controller回给Host,比如“扫描到设备”、“连接断开”。
- 数据包:双向传输,承载真正的用户数据。
HCI的物理传输方式很灵活,可以是UART、USB、SDIO甚至SPI。我做过一个网关项目,Host跑在Linux主板上,Controller用了一个USB蓝牙dongle,HCI就走USB。调试时用hcitool和btmon抓HCI日志,非常方便。
# 抓取HCI日志示例(Linux环境)
sudo btmon -w hci_log.pklg
# 扫描设备
sudo hcitool lescan
实战技巧:调试蓝牙问题时,第一件事就是抓HCI日志。它能告诉你Host发了什么命令,Controller回了什么事件。很多应用层的问题,追到HCI层就真相大白了。
4.3 L2CAP:数据通道的“调度员”
L2CAP(Logical Link Control and Adaptation Protocol)位于Host层,紧挨着HCI。它的主要工作是:
- 分段重组:把上层的大包切成小片,交给Controller发送;收到后再拼回去。
- 通道管理:为上层协议(如ATT、SM)分配独立的逻辑通道。
- 流量控制:防止发送方太快,接收方来不及处理。
在BLE中,L2CAP的MTU(最大传输单元)默认是23字节。嗯,这里要注意,很多新手以为一次只能发23字节,其实可以通过MTU协商扩展到更大。我在一个数据采集网关项目里,把MTU协商到了247字节,吞吐量提升了好几倍。
// MTU协商请求示例(概念代码)
// Host发起MTU请求,建议大小为247字节
l2cap_mtu_req {
channel_id: 0x0004,
mtu: 247
}
4.4 ATT/GATT:属性协议与通用属性协议
这两个协议经常被混在一起说,其实分工很明确。
ATT(Attribute Protocol)是底层传输协议,定义了如何读写属性。它只有6种操作:Request、Response、Command、Notification、Indication、Confirmation。
GATT(Generic Attribute Profile)是建立在ATT之上的框架,定义了属性的组织方式——Service、Characteristic、Descriptor。说白了,GATT告诉你“数据应该长什么样”,ATT负责“怎么把数据发出去”。
避坑指南:我曾经在一个项目中,把GATT的Notification和Indication搞混了。Notification不需要对方确认,适合高频数据;Indication需要对方确认,适合重要数据。选错了,要么丢数据,要么把带宽吃满。
GATT的层次结构是这样的:
Profile(应用规范)
└── Service(服务)
├── Characteristic(特征)
│ ├── Value(值)
│ ├── Descriptor(描述符)
│ └── Descriptor
└── Characteristic
└── ...
4.5 SM(安全管理)层:蓝牙的“保安队长”
SM层负责配对、绑定和加密。BLE的配对过程分为三个阶段:
- 配对特征交换:双方交换IO能力、认证要求、密钥大小等信息。
- 短期密钥(STK)生成:根据配对方式(Just Works、Passkey Entry、OOB、Numeric Comparison)生成STK。
- 传输特定密钥:用STK加密通道,交换长期密钥(LTK)、身份解析密钥(IRK)等。
我做过一个智能门锁项目,配对方式选了Passkey Entry。用户需要在手机上输入门锁上显示的6位数字。听起来挺安全,但实际体验很差——用户经常输错。后来改成了Numeric Comparison,两边同时显示一个数字,用户确认一致就行,体验好多了。
| 配对方式 | 安全性 | 适用场景 |
|---|---|---|
| Just Works | 低(无用户交互) | 传感器、信标 |
| Passkey Entry | 中(需输入PIN) | 门锁、键盘 |
| Numeric Comparison | 高(需确认数字) | 手机、平板 |
| OOB | 最高(带外传输) | NFC配对、安全支付 |
4.6 整体架构图:一张图看懂所有
下面这张图是我画的一个蓝牙协议栈分层架构,包含了Host、Controller、HCI以及各层协议的关系。你仔细看,就能明白数据是怎么从应用层一路跑到空中的。
从这张图可以清楚看到,数据从应用层出发,经过GAP、SM、ATT/GATT这些高层协议,然后被L2CAP封装成L2CAP包,再通过HCI交给Controller。Controller里的链路层负责组帧、重传、加密,最后物理层把比特流发到空中。
我的建议:做蓝牙网关开发,一定要把这张图刻在脑子里。遇到问题先定位是Host层的问题还是Controller层的问题,然后逐层排查。我每次带新人,第一件事就是让他们对着这张图讲一遍数据流,讲不清楚的,代码写得再好也容易出bug。
好了,这一章的内容就到这里。蓝牙协议栈的分层设计,说白了就是为了让不同厂商的芯片和协议栈能互相配合。你只要把Host和Controller的边界搞清楚,把HCI、L2CAP、ATT/GATT、SM这几个核心模块的职责记牢,后面写代码的时候就会顺手很多。