第三章:Linux内核蓝牙子系统:BlueZ架构概览
好,我们正式开始接触BlueZ。说实话,很多做蓝牙开发的工程师,一听到「内核蓝牙子系统」就觉得头大。我当年刚接触时也一样,面对一堆源码文件,完全不知道从哪下手。但后来我发现,只要抓住几个核心模块,整个架构其实很清晰。
3.1 BlueZ的整体架构
BlueZ是Linux官方标准的蓝牙协议栈。它分两层:内核空间和用户空间。内核空间负责底层硬件交互和协议处理,用户空间负责配置管理和上层应用。
我个人习惯把BlueZ比作一个快递系统:
- 硬件驱动 = 快递员,负责收发包裹
- HCI层 = 分拣中心,统一管理数据流
- L2CAP层 = 快递单号,区分不同业务
- 用户空间工具 = 客服系统,让你查物流、改地址
嗯,这个比喻虽然简单,但能帮你快速建立整体认知。
3.2 内核蓝牙模块:bluetooth.ko
bluetooth.ko是蓝牙子系统的核心模块。它不直接操作硬件,而是提供一套框架。所有蓝牙驱动都基于这个框架来工作。
我建议你记住这个模块的几个关键职责:
- 管理蓝牙控制器(HCI设备)的注册与注销
- 提供HCI命令、事件、数据的传输通道
- 实现L2CAP、SCO等核心协议
- 维护连接状态和链路信息
加载这个模块很简单:
sudo modprobe bluetooth
但要注意,很多嵌入式板子默认没开蓝牙内核支持。我曾经在一个项目里折腾了半天,最后发现是内核配置里没勾选CONFIG_BT。嗯,这种低级错误,犯过一次就记住了。
3.3 关键数据结构之一:hci_dev
hci_dev是整个蓝牙控制器的抽象。每个蓝牙硬件(无论是USB、UART还是SDIO接口)在内核里都对应一个hci_dev实例。
它的定义在include/net/bluetooth/hci_core.h里。我挑几个最重要的字段说说:
| 字段名 | 类型 | 作用 |
|---|---|---|
| name | char[8] | 设备名,比如hci0、hci1 |
| bus | int | 总线类型:USB、UART、SDIO等 |
| dev_type | int | 设备类型:BR/EDR还是LE |
| hdev_list | list_head | 全局链表,把所有hci_dev串起来 |
| conn_hash | struct hci_conn_hash | 管理所有连接 |
你想想看,一个蓝牙芯片插到系统里,内核怎么知道它?其实就是通过hci_dev。驱动初始化时,会调用hci_alloc_dev()分配一个实例,然后填充字段,最后hci_register_dev()注册进去。
我见过不少新手在写驱动时,忘了设置bus字段,结果设备注册成功了但上层协议栈不认。这种小细节,往往最坑人。
3.4 关键数据结构之二:hci_conn
hci_conn代表一条蓝牙连接。无论是ACL链路还是SCO/eSCO链路,都用这个结构体表示。
它的核心字段包括:
- hdev:指向所属的hci_dev
- dst:对端蓝牙地址
- type:连接类型(ACL/SCO/LE)
- state:连接状态(OPEN/CLOSED等)
- link_mode:链路模式(加密、认证等标志)
为什么需要这个结构体?说白了,蓝牙通信是面向连接的。你要传数据,必须先建立连接。hci_conn就是这条连接的「身份证」。
我记得有一次调试蓝牙耳机,音频断断续续。查了半天,发现是SCO连接的state在频繁切换。嗯,后来定位到是射频干扰导致链路不稳定。这种问题,光看应用层日志根本看不出来,必须深入内核数据结构。
/sys/kernel/debug/bluetooth/hci0/conn_info查看当前所有hci_conn的状态。我经常用这个文件来快速判断连接是否正常。
3.5 关键数据结构之三:l2cap_chan
L2CAP层是蓝牙协议栈的「交通枢纽」。l2cap_chan就是L2CAP层的一个通道实例。
每个L2CAP通道对应一个逻辑连接。比如A2DP音频流、HID鼠标事件、ATT属性协议,都是通过不同的l2cap_chan来传输的。
它的关键字段:
- conn:指向所属的hci_conn
- psm:协议服务多路复用器,用来区分上层协议
- cid:通道标识符,本地唯一
- state:通道状态(OPEN/WAIT等)
- ops:操作函数集,包括recv、send等回调
你可能会问:为什么已经有了hci_conn,还要l2cap_chan?
原因很简单:一条物理连接上可以跑多个逻辑通道。比如你的手机同时连蓝牙耳机听歌、连手表收通知,它们共用一条ACL链路,但通过不同的l2cap_chan来区分数据。
我建议你记住这个层次关系:
hci_dev (控制器)
└── hci_conn (物理连接)
└── l2cap_chan (逻辑通道)
这个三层结构,是理解蓝牙内核源码的基石。
3.6 三个结构体的协作关系
光知道每个结构体长什么样还不够,你得明白它们怎么配合工作。
我画个简单的数据流:
- 蓝牙硬件收到数据包,驱动通过hci_dev上报
- 内核根据包类型,找到对应的hci_conn
- 再根据L2CAP头部信息,路由到正确的l2cap_chan
- 最后通过chan的ops回调,交给上层协议处理
反过来,发送数据时:
- 上层协议调用l2cap_chan的send接口
- l2cap_chan封装L2CAP头部,交给hci_conn
- hci_conn封装HCI头部,通过hci_dev发送
- 驱动把数据写到硬件
你看,整个流程非常清晰。每个结构体各司其职,环环相扣。
核心要点:
- hci_dev = 控制器抽象,一个蓝牙芯片一个实例
- hci_conn = 物理连接,一条链路一个实例
- l2cap_chan = 逻辑通道,一个服务一个实例
- 三者通过指针互相引用,形成完整的数据通路
好了,这一章的内容就到这里。下一章我们会深入HCI层,看看数据包到底是怎么在内核里流转的。到时候我会拿一个实际的抓包例子来讲解,保证让你印象深刻。