【BlueZ 】Linux 内核蓝牙子系统入门:hci_core 模块与 BlueZ 的交互

蓝牙技术在现代操作系统中扮演着至关重要的角色,从无线键鼠到音频传输,从物联网设备到车联网应用,无处不在。Linux 内核作为开源操作系统的典范,提供了完整的蓝牙协议栈实现------从底层的硬件驱动到高层的应用接口。本文聚焦于 Linux 蓝牙子系统的核心枢纽:hci_core 模块与 BlueZ 用户态协议栈的交互机制


目录

一、蓝牙协议栈分层架构

[二、HCI 套接字通信机制](#二、HCI 套接字通信机制)

[三、BlueZ HCI 封装层实现](#三、BlueZ HCI 封装层实现)

[四、HCI 指令发送流程](#四、HCI 指令发送流程)

[五、HCI 事件接收与处理](#五、HCI 事件接收与处理)

[六、HCI 事件注册机制](#六、HCI 事件注册机制)

[七、mgmt 管理接口](#七、mgmt 管理接口)

[八、adapter 模块与 HCI 交互](#八、adapter 模块与 HCI 交互)

[九、HCI 协议报文格式](#九、HCI 协议报文格式)

十、完整交互流程示例

十一、异常处理与容错机制

十二、调试与抓包

十三、核心函数索引

十四、总结


本文深入源码,剖析这套精密的分层架构:如何通过 PF_BLUETOOTH 套接字实现内核与用户态的高效通信?BlueZ 如何封装 HCI 指令发送与事件接收?mgmt 管理接口如何提供适配器的高级控制?将完整拆解从蓝牙适配器初始化、设备发现、建立连接到数据传输的每一步源码流程,揭示 bt_hci 封装层的指令队列与事件回调机制,解读 mgmt 接口的请求-响应模式,并梳理 adapter 模块如何协调与整合所有操作。

无论您是蓝牙驱动开发者、BlueZ 贡献者,还是对无线协议栈感兴趣的工程师,本篇深度解析将打通内核态与用户态的任督二脉,提供实战级的源码剖析与调试方案。


一、蓝牙协议栈分层架构

Linux 蓝牙子系统采用经典的分层架构设计,从下到上依次为:

核心分工

  • 内核 hci_core:负责 HCI 协议报文收发、L2CAP 协议处理、设备注册管理

  • BlueZ 用户态:负责 Profile 实现、D-Bus 对外接口、设备发现/连接/配对逻辑

二、 HCI 套接字通信机制

2.1 HCI 套接字创建

BlueZ 通过 Linux 特有的 PF_BLUETOOTH 地址族与内核 hci_core 通信:

cpp 复制代码
// src/shared/hci.c

#define BTPROTO_HCI 1

struct sockaddr_hci {
    sa_family_t hci_family;
    unsigned short  hci_dev;      // 设备索引 (hci0, hci1...)
    unsigned short  hci_channel;  // 通道类型
};

// 创建 HCI 套接字
static int create_socket(uint16_t index, uint16_t channel)
{
    struct sockaddr_hci addr;
    int fd;

    // 使用 PF_BLUETOOTH + SOCK_RAW + BTPROTO_HCI
    fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
                BTPROTO_HCI);
    if (fd < 0)
        return -1;

    memset(&addr, 0, sizeof(addr));
    addr.hci_family = AF_BLUETOOTH;
    addr.hci_dev = index;         // 绑定到指定蓝牙适配器
    addr.hci_channel = channel;   // 指定通道类型

    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        close(fd);
        return -1;
    }

    return fd;
}

2.2 HCI 通道类型

Linux 内核定义了三种 HCI 通道:

cpp 复制代码
// 通道类型定义
#define HCI_CHANNEL_RAW     0   // 原始通道:直接与硬件通信
#define HCI_CHANNEL_USER    1   // 用户通道:替代内核协议栈
#define HCI_CHANNEL_MONITOR 2   // 监控通道:抓包分析

通道对比

|-----------------------|-------------|----------------------------|
| 通道类型 | 用途 | 特点 |
| HCI_CHANNEL_RAW | 常规 BlueZ 使用 | 内核处理 L2CAP,用户态处理上层协议 |
| HCI_CHANNEL_USER | 完全用户态实现 | 绕过内核,用户态实现包括 L2CAP 在内的所有协议 |
| HCI_CHANNEL_MONITOR | 抓包/调试 | 只读模式,接收所有 HCI 报文 |

2.3 HCI 过滤器 设置

为控制内核向用户态推送哪些事件,需要设置 HCI 过滤器:

cpp 复制代码
// HCI 过滤器结构
#define SOL_HCI     0
#define HCI_FILTER  2

struct hci_filter {
    uint32_t type_mask;      // 报文类型掩码
    uint32_t event_mask[2];  // 事件掩码(位图)
    uint16_t opcode;         // 特定指令过滤
};

// 示例:监控模式设置过滤器
struct hci_filter flt;
memset(&flt, 0, sizeof(flt));

// 只接收事件包
flt.type_mask = 1 << BT_H4_EVT_PKT;

// 启用所有事件
flt.event_mask[0] = 0xffffffff;
flt.event_mask[1] = 0xffffffff;

// 设置过滤器
setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt));

三、BlueZ HCI 封装层实现

3.1 bt_hci 核心数据结构

BlueZ 在 src/shared/hci.c 中实现了 HCI 通信的封装层:

cpp 复制代码
// src/shared/hci.c

struct bt_hci {
    int ref_count;              // 引用计数
    struct io *io;              // IO 抽象层(封装 socket fd)
    bool is_stream;             // 是否为流式(监控模式)
    bool writer_active;         // 写入状态标记
    uint8_t num_cmds;           // 允许的待处理指令数
    unsigned int next_cmd_id;   // 下一个指令 ID
    unsigned int next_evt_id;   // 下一个事件 ID
    struct queue *cmd_queue;    // 待发送指令队列
    struct queue *rsp_queue;    // 等待响应的指令队列
    struct queue *evt_list;     // 事件回调列表
};

// 指令结构
struct cmd {
    unsigned int id;            // 指令 ID
    uint16_t opcode;            // HCI 操作码
    void *data;                 // 指令参数数据
    uint8_t size;               // 参数长度
    bt_hci_callback_func_t callback;  // 响应回调
    bt_hci_destroy_func_t destroy;    // 销毁回调
    void *user_data;            // 用户数据
};

// 事件回调结构
struct evt {
    unsigned int id;            // 事件 ID
    uint8_t event;              // HCI 事件码
    bt_hci_callback_func_t callback;  // 事件回调
    bt_hci_destroy_func_t destroy;    // 销毁回调
    void *user_data;            // 用户数据
};

3.2 bt_hci 创建流程

BlueZ 提供三种创建 bt_hci 实例的方式:

cpp 复制代码
// src/shared/hci.c

// 方式一:从现有 fd 创建
struct bt_hci *bt_hci_new(int fd)
{
    return create_hci(fd);
}

// 方式二:用户通道模式(完全接管 HCI)
struct bt_hci *bt_hci_new_user_channel(uint16_t index)
{
    struct bt_hci *hci;
    int fd;

    // 创建用户通道套接字
    fd = create_socket(index, HCI_CHANNEL_USER);
    if (fd < 0)
        return NULL;

    hci = create_hci(fd);
    if (!hci) {
        close(fd);
        return NULL;
    }

    hci->is_stream = false;
    bt_hci_set_close_on_unref(hci, true);

    return hci;
}

// 方式三:原始设备模式(常规 BlueZ 使用)
struct bt_hci *bt_hci_new_raw_device(uint16_t index)
{
    struct bt_hci *hci;
    struct hci_filter flt;
    int fd;

    // 创建原始通道套接字
    fd = create_socket(index, HCI_CHANNEL_RAW);
    if (fd < 0)
        return NULL;

    // 设置过滤器接收所有事件
    memset(&flt, 0, sizeof(flt));
    flt.type_mask = 1 << BT_H4_EVT_PKT;
    flt.event_mask[0] = 0xffffffff;
    flt.event_mask[1] = 0xffffffff;
    setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt));

    hci = create_hci(fd);
    if (!hci) {
        close(fd);
        return NULL;
    }

    hci->is_stream = false;
    bt_hci_set_close_on_unref(hci, true);

    return hci;
}

3.3 内部初始化

cpp 复制代码
// 内部创建函数
static struct bt_hci *create_hci(int fd)
{
    struct bt_hci *hci;

    if (fd < 0)
        return NULL;

    hci = new0(struct bt_hci, 1);
    hci->io = io_new(fd);          // 封装 fd 为 io 对象
    if (!hci->io) {
        free(hci);
        return NULL;
    }

    hci->is_stream = true;
    hci->writer_active = false;
    hci->num_cmds = 1;             // 初始允许 1 条指令
    hci->next_cmd_id = 1;
    hci->next_evt_id = 1;

    // 创建三个队列
    hci->cmd_queue = queue_new();  // 待发送队列
    hci->rsp_queue = queue_new();  // 等待响应队列
    hci->evt_list = queue_new();   // 事件回调列表

    // 设置读回调
    if (!io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
        queue_destroy(hci->evt_list, NULL);
        queue_destroy(hci->rsp_queue, NULL);
        queue_destroy(hci->cmd_queue, NULL);
        io_destroy(hci->io);
        free(hci);
        return NULL;
    }

    return bt_hci_ref(hci);
}

四、HCI 指令发送流程

4.1 指令发送接口

cpp 复制代码
// src/shared/hci.c

// 发送 HCI 指令
unsigned int bt_hci_send(struct bt_hci *hci, uint16_t opcode,
                        const void *data, uint8_t size,
                        bt_hci_callback_func_t callback,
                        void *user_data, bt_hci_destroy_func_t destroy)
{
    struct cmd *cmd;

    if (!hci)
        return 0;

    // 创建指令对象
    cmd = new0(struct cmd, 1);
    cmd->opcode = opcode;
    cmd->size = size;

    // 复制指令参数
    if (cmd->size > 0) {
        cmd->data = malloc(cmd->size);
        if (!cmd->data) {
            free(cmd);
            return 0;
        }
        memcpy(cmd->data, data, cmd->size);
    }

    // 分配指令 ID
    if (hci->next_cmd_id < 1)
        hci->next_cmd_id = 1;
    cmd->id = hci->next_cmd_id++;

    // 设置回调
    cmd->callback = callback;
    cmd->destroy = destroy;
    cmd->user_data = user_data;

    // 入队
    if (!queue_push_tail(hci->cmd_queue, cmd)) {
        free(cmd->data);
        free(cmd);
        return 0;
    }

    // 触发写入
    wakeup_writer(hci);

    return cmd->id;
}

4.2 指令排队与发送

cpp 复制代码
// 触发写入
static void wakeup_writer(struct bt_hci *hci)
{
    if (hci->writer_active)
        return;
    if (hci->num_cmds < 1)
        return;
    if (queue_isempty(hci->cmd_queue))
        return;

    // 设置写回调
    if (!io_set_write_handler(hci->io, io_write_callback, hci, NULL))
        return;

    hci->writer_active = true;
}

// 写回调:从队列取出指令并发送
static bool io_write_callback(struct io *io, void *user_data)
{
    struct bt_hci *hci = user_data;
    struct cmd *cmd;

    // 从待发送队列取出指令
    cmd = queue_pop_head(hci->cmd_queue);
    if (cmd) {
        // 实际发送指令
        send_command(hci, cmd->opcode, cmd->data, cmd->size);
        // 移到等待响应队列
        queue_push_tail(hci->rsp_queue, cmd);
    }

    hci->writer_active = false;
    return false;
}

4.3 HCI 报文构造

cpp 复制代码
// 构造并发送 HCI 指令
static void send_command(struct bt_hci *hci, uint16_t opcode,
                        void *data, uint8_t size)
{
    uint8_t type = BT_H4_CMD_PKT;  // H4 数据包类型:Command
    struct bt_hci_cmd_hdr hdr;     // HCI 指令头
    struct iovec iov[3];           // 分散/聚集 IO
    int iovcnt;

    if (hci->num_cmds < 1)
        return;

    // 填充指令头
    hdr.opcode = cpu_to_le16(opcode);  // 小端转换
    hdr.plen = size;                    // 参数长度

    // 组织 IO 向量
    iov[0].iov_base = &type;       // 第一部分:包类型字节
    iov[0].iov_len  = 1;
    iov[1].iov_base = &hdr;        // 第二部分:指令头
    iov[1].iov_len  = sizeof(hdr);

    if (size > 0) {
        iov[2].iov_base = data;    // 第三部分:指令参数
        iov[2].iov_len  = size;
        iovcnt = 3;
    } else
        iovcnt = 2;

    // 通过 io 抽象层发送
    if (io_send(hci->io, iov, iovcnt) < 0)
        return;

    hci->num_cmds--;  // 递减待处理计数
}

H4 报文格式

五、HCI 事件接收与处理

5.1 读回调触发

cpp 复制代码
// src/shared/hci.c

// IO 读回调
static bool io_read_callback(struct io *io, void *user_data)
{
    struct bt_hci *hci = user_data;
    uint8_t buf[512];
    ssize_t len;
    int fd;

    fd = io_get_fd(hci->io);
    if (fd < 0)
        return false;

    if (hci->is_stream)
        return false;

    // 从 socket 读取数据
    len = read(fd, buf, sizeof(buf));
    if (len < 0)
        return false;

    if (len < 1)
        return true;

    // 根据包类型分发
    switch (buf[0]) {
    case BT_H4_EVT_PKT:  // 事件包
        process_event(hci, buf + 1, len - 1);
        break;
    }

    return true;
}

5.2 事件处理分发

cpp 复制代码
// 事件处理主函数
static void process_event(struct bt_hci *hci, const void *data, size_t size)
{
    const struct bt_hci_evt_hdr *hdr = data;
    const struct bt_hci_evt_cmd_complete *cc;
    const struct bt_hci_evt_cmd_status *cs;

    if (size < sizeof(struct bt_hci_evt_hdr))
        return;

    data += sizeof(struct bt_hci_evt_hdr);
    size -= sizeof(struct bt_hci_evt_hdr);

    if (hdr->plen != size)
        return;

    // 根据事件类型处理
    switch (hdr->evt) {
    case BT_HCI_EVT_CMD_COMPLETE:  // 指令完成事件
        if (size < sizeof(*cc))
            return;
        cc = data;
        hci->num_cmds = cc->ncmd;  // 更新允许的指令数
        // 查找对应指令并回调
        process_response(hci, le16_to_cpu(cc->opcode),
                        data + sizeof(*cc), size - sizeof(*cc));
        break;

    case BT_HCI_EVT_CMD_STATUS:  // 指令状态事件
        if (size < sizeof(*cs))
            return;
        cs = data;
        hci->num_cmds = cs->ncmd;
        process_response(hci, le16_to_cpu(cs->opcode), &cs->status, 1);
        break;

    default:  // 其他事件
        // 遍历事件回调列表
        queue_foreach(hci->evt_list, process_notify, (void *) hdr);
        break;
    }
}

5.3 指令响应匹配

cpp 复制代码
// 处理指令响应
static void process_response(struct bt_hci *hci, uint16_t opcode,
                            const void *data, size_t size)
{
    struct cmd *cmd;

    if (opcode == BT_HCI_CMD_NOP) {
        wakeup_writer(hci);
        return;
    }

    // 在等待队列中查找匹配的指令
    cmd = queue_remove_if(hci->rsp_queue, match_cmd_opcode,
                         UINT_TO_PTR(opcode));
    if (!cmd)
        return;

    // 增加引用防止回调中销毁
    bt_hci_ref(hci);

    // 执行用户回调
    if (cmd->callback)
        cmd->callback(data, size, cmd->user_data);

    cmd_free(cmd);

    // 唤醒写入(如果有待发送指令)
    wakeup_writer(hci);

    bt_hci_unref(hci);
}

六、HCI 事件注册机制

6.1 事件回调注册

cpp 复制代码
// src/shared/hci.c

// 注册事件回调
unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
                            bt_hci_callback_func_t callback,
                            void *user_data, bt_hci_destroy_func_t destroy)
{
    struct evt *evt;

    if (!hci)
        return 0;

    // 创建事件回调对象
    evt = new0(struct evt, 1);
    evt->event = event;

    // 分配事件 ID
    if (hci->next_evt_id < 1)
        hci->next_evt_id = 1;
    evt->id = hci->next_evt_id++;

    // 设置回调
    evt->callback = callback;
    evt->destroy = destroy;
    evt->user_data = user_data;

    // 添加到事件列表
    if (!queue_push_tail(hci->evt_list, evt)) {
        free(evt);
        return 0;
    }

    return evt->id;
}

// 取消事件回调
bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
{
    struct evt *evt;

    if (!hci || !id)
        return false;

    // 从列表中移除
    evt = queue_remove_if(hci->evt_list, match_evt_id, UINT_TO_PTR(id));
    if (!evt)
        return false;

    evt_free(evt);
    return true;
}

6.2 事件分发实现

cpp 复制代码
// 事件通知处理
static void process_notify(void *data, void *user_data)
{
    struct bt_hci_evt_hdr *hdr = user_data;
    struct evt *evt = data;

    // 匹配事件码
    if (evt->event == hdr->evt)
        // 调用用户回调,传入事件数据(跳过事件头)
        evt->callback(user_data + sizeof(struct bt_hci_evt_hdr),
                     hdr->plen, evt->user_data);
}

七、mgmt 管理接口

7.1 mgmt 接口概述

除了直接的 HCI 套接字通信,BlueZ 还通过 mgmt(Management)接口 与内核通信:

cpp 复制代码
// src/shared/mgmt.h

struct mgmt;

// 创建 mgmt 实例
struct mgmt *mgmt_new(int fd);
struct mgmt *mgmt_new_default(void);

// 发送管理命令
unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
                      uint16_t length, const void *param,
                      mgmt_request_func_t callback,
                      void *user_data, mgmt_destroy_func_t destroy);

// 注册事件通知
unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
                          mgmt_notify_func_t callback,
                          void *user_data, mgmt_destroy_func_t destroy);

7.2 mgmt 核心数据结构

cpp 复制代码
// src/shared/mgmt.c

struct mgmt {
    int ref_count;
    int fd;                     // socket 文件描述符
    bool close_on_unref;
    struct io *io;              // IO 抽象
    bool writer_active;
    struct queue *request_queue;  // 待发送请求
    struct queue *reply_queue;    // 等待响应请求
    struct queue *pending_list;   // 挂起请求
    struct queue *notify_list;    // 事件通知注册
    unsigned int next_request_id;
    unsigned int next_notify_id;
    // ...
};

// mgmt 请求结构
struct mgmt_request {
    struct mgmt *mgmt;
    unsigned int id;
    uint16_t opcode;           // 操作码
    uint16_t index;            // 适配器索引
    void *buf;                 // 数据缓冲区
    uint16_t len;              // 数据长度
    mgmt_request_func_t callback;  // 响应回调
    mgmt_destroy_func_t destroy;
    void *user_data;
    int timeout;               // 超时时间
    unsigned int timeout_id;   // 超时定时器 ID
};

// mgmt 通知结构
struct mgmt_notify {
    unsigned int id;
    uint16_t event;            // 事件码
    uint16_t index;            // 适配器索引
    bool removed;
    mgmt_notify_func_t callback;  // 通知回调
    mgmt_destroy_func_t destroy;
    void *user_data;
};

7.3 mgmt 与 HCI 的关系

对比说明

|--------|--------------|----------------|
| 特性 | mgmt 接口 | bt_hci 接口 |
| 套接字类型 | AF_MGMT | PF_BLUETOOTH |
| 通信协议 | MGMT 协议 | H4/HCI 协议 |
| 抽象层级 | 高层(电源/扫描/连接) | 低层(直接 HCI 指令) |
| 使用场景 | 适配器管理 | 设备通信 |

八、adapter 模块与 HCI 交互

8.1 适配器结构

cpp 复制代码
// src/adapter.c

struct btd_adapter {
    int ref_count;
    uint16_t dev_id;              // 设备索引
    struct mgmt *mgmt;            // mgmt 接口实例
    bdaddr_t bdaddr;              // 蓝牙地址
    uint8_t bdaddr_type;          // 地址类型
    uint32_t dev_class;           // 设备类型
    char *name;                   // 设备名
    uint32_t supported_settings;  // 支持的设置
    uint32_t pending_settings;    // 待应用设置
    uint32_t current_settings;    // 当前设置
    // ... 其他字段
};

8.2 设置模式变更

cpp 复制代码
// src/adapter.c

// 设置适配器模式
static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
                    uint8_t mode)
{
    struct mgmt_mode cp;
    uint32_t setting = 0;

    memset(&cp, 0, sizeof(cp));
    cp.val = mode;

    // 根据操作码确定设置类型
    switch (opcode) {
    case MGMT_OP_SET_POWERED:
        setting = MGMT_SETTING_POWERED;
        break;
    case MGMT_OP_SET_CONNECTABLE:
        setting = MGMT_SETTING_CONNECTABLE;
        break;
    case MGMT_OP_SET_DISCOVERABLE:
        setting = MGMT_SETTING_DISCOVERABLE;
        break;
    case MGMT_OP_SET_BONDABLE:
        setting = MGMT_SETTING_BONDABLE;
        break;
    }

    adapter->pending_settings |= setting;

    // 通过 mgmt 接口发送命令
    if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id,
                sizeof(cp), &cp, set_mode_complete, adapter, NULL) > 0)
        return true;

    return false;
}

8.3 事件回调处理

cpp 复制代码
// 设置变更回调
static void new_settings_callback(uint16_t index, uint16_t length,
                                const void *param, void *user_data)
{
    struct btd_adapter *adapter = user_data;
    uint32_t settings;

    if (length < sizeof(settings))
        return;

    settings = get_le32(param);

    if (settings == adapter->current_settings)
        return;

    // 处理设置变更
    settings_changed(adapter, settings);
}

// 设置变更处理
static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
{
    uint32_t changed_mask;

    changed_mask = adapter->current_settings ^ settings;
    adapter->current_settings = settings;
    adapter->pending_settings &= ~changed_mask;

    // 处理电源状态变更
    if (changed_mask & MGMT_SETTING_POWERED) {
        if (adapter->current_settings & MGMT_SETTING_POWERED)
            adapter_start(adapter);
        else
            adapter_stop(adapter);
    }

    // 处理可发现状态变更
    if (changed_mask & MGMT_SETTING_DISCOVERABLE)
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                    ADAPTER_INTERFACE, "Discoverable");

    // 处理可配对状态变更
    if (changed_mask & MGMT_SETTING_BONDABLE)
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                    ADAPTER_INTERFACE, "Pairable");
}

九、HCI 协议报文格式

9.1 HCI 指令格式

cpp 复制代码
// lib/hci.h

// HCI 指令包头
struct {
    uint16_t opcode;     // 操作码 (OCF + OGF)
    uint8_t plen;        // 参数长度
} __attribute__((packed));

// 指令操作码编码
#define OGF_LINK_CTL        0x01  // 链路控制
#define OGF_LINK_POLICY     0x02  // 链路策略
#define OGF_HOST_CTL        0x03  // 主机控制
#define OGF_INFO_PARAM      0x04  // 信息参数
#define OGF_STATUS_PARAM    0x05  // 状态参数
#define OGF_LE_CTL          0x08  // LE 控制
#define OGF_VENDOR_CMD      0x3f  // 厂商命令

// 示例:创建连接指令
#define OCF_CREATE_CONN     0x0005
typedef struct {
    bdaddr_t bdaddr;        // 目标地址
    uint16_t pkt_type;      // 包类型
    uint8_t pscan_rep_mode; // 扫描模式
    uint8_t pscan_mode;     // 扫描模式
    uint16_t clock_offset;  // 时钟偏移
    uint8_t role_switch;    // 角色切换
} __attribute__((packed)) create_conn_cp;

9.2 HCI 事件格式

cpp 复制代码
// lib/hci.h

// 事件头
struct {
    uint8_t evt;         // 事件码
    uint8_t plen;        // 事件数据长度
} __attribute__((packed));

// 常用事件码
#define EVT_INQUIRY_COMPLETE    0x01  // 查询完成
#define EVT_INQUIRY_RESULT      0x02  // 查询结果
#define EVT_CONN_COMPLETE       0x03  // 连接完成
#define EVT_CONN_REQUEST        0x04  // 连接请求
#define EVT_DISCONN_COMPLETE    0x05  // 断连完成
#define EVT_AUTH_COMPLETE       0x06  // 认证完成
#define EVT_CMD_COMPLETE        0x0E  // 指令完成
#define EVT_CMD_STATUS          0x0F  // 指令状态

// 示例:连接完成事件
typedef struct {
    uint8_t status;       // 状态码
    uint16_t handle;      // 连接句柄
    bdaddr_t bdaddr;      // 远程地址
    uint8_t link_type;    // 链路类型
    uint8_t encr_mode;    // 加密模式
} __attribute__((packed)) evt_conn_complete;

9.3 H4 包类型

cpp 复制代码
// H4 数据包类型
#define HCI_COMMAND_PKT    0x01  // 命令包
#define HCI_ACLDATA_PKT    0x02  // ACL 数据包
#define HCI_SCODATA_PKT    0x03  // SCO 数据包
#define HCI_EVENT_PKT      0x04  // 事件包
#define HCI_ISODATA_PKT    0x05  // ISO 数据包
#define HCI_VENDOR_PKT     0xff  // 厂商包

十、完整交互流程示例

10.1 初始化蓝牙适配器

cpp 复制代码
1. BlueZ 启动
   └─> main() 初始化
       └─> adapter_init() 初始化适配器管理
           └─> 枚举 /sys/class/bluetooth 发现设备
               └─> mgmt_new() 创建 mgmt 接口
                   └─> 绑定 AF_MGMT 套接字

2. 适配器上电
   └─> set_mode(adapter, MGMT_OP_SET_POWERED, 1)
       └─> mgmt_send() 发送管理命令
           └─> 通过 mgmt socket 发送到内核
               └─> hci_core 处理命令
                   └─> 驱动上电
                       └─> 返回命令完成事件
                           └─> mgmt 回调通知 BlueZ

3. 设置适配器参数
   └─> set_name() 设置设备名
   └─> set_dev_class() 设置设备类型
   └─> set_event_mask() 设置事件掩码

10.2 发现远程设备

cpp 复制代码
1. 启动扫描
   └─> adapter_start_discovery()
       └─> mgmt_send(MGMT_OP_START_DISCOVERY, ...)
           └─> 内核发送 HCI Inquiry 指令

2. 接收扫描结果
   └─> 内核接收 EVT_INQUIRY_RESULT 事件
       └─> 通过 mgmt socket 上报
           └─> mgmt 通知回调
               └─> adapter 处理设备发现
                   └─> 创建设备对象

3. 停止扫描
   └─> mgmt_send(MGMT_OP_STOP_DISCOVERY, ...)

10.3 建立蓝牙连接

cpp 复制代码
1. 发起连接
   └─> device_connect()
       └─> mgmt_send(MGMT_OP_LE_CREATE_CONN / MGMT_OP_CREATE_CONN, ...)
           └─> 内核发送 HCI Create Connection 指令

2. 接收连接完成
   └─> 内核接收 EVT_CONN_COMPLETE 事件
       └─> 通过 mgmt socket 上报
           └─> BlueZ 接收连接完成通知
               └─> 执行 SDP 搜索 / GATT 发现
                   └─> 完成 Profile 连接

十一、异常处理与容错机制

11.1 超时处理

cpp 复制代码
// src/shared/mgmt.c

// 请求超时回调
static bool request_timeout(void *data)
{
    struct mgmt_request *request = data;

    if (!request)
        return false;

    request->timeout_id = 0;
    queue_remove_if(request->mgmt->pending_list, NULL, request);

    // 超时回调
    if (request->callback)
        request->callback(MGMT_STATUS_TIMEOUT, 0, NULL, request->user_data);

    destroy_request(request);
    return false;
}

// 发送带超时的请求
unsigned int mgmt_send_timeout(struct mgmt *mgmt, uint16_t opcode,
                              uint16_t index, uint16_t length,
                              const void *param,
                              mgmt_request_func_t callback,
                              void *user_data, mgmt_destroy_func_t destroy,
                              int timeout)
{
    struct mgmt_request *request;
    // ... 创建请求 ...

    if (timeout)
        request->timeout_id = timeout_add_seconds(timeout,
                                                  request_timeout, request, NULL);

    return request->id;
}

11.2 取消操作

cpp 复制代码
// src/shared/hci.c

// 取消指定指令
bool bt_hci_cancel(struct bt_hci *hci, unsigned int id)
{
    struct cmd *cmd;

    if (!hci || !id)
        return false;

    // 从待发送队列移除
    cmd = queue_remove_if(hci->cmd_queue, match_cmd_id, UINT_TO_PTR(id));
    if (!cmd) {
        // 从等待响应队列移除
        cmd = queue_remove_if(hci->rsp_queue, match_cmd_id, UINT_TO_PTR(id));
        if (!cmd)
            return false;
    }

    cmd_free(cmd);
    wakeup_writer(hci);
    return true;
}

// 清空所有指令
bool bt_hci_flush(struct bt_hci *hci)
{
    if (!hci)
        return false;

    // 取消写入
    if (hci->writer_active) {
        io_set_write_handler(hci->io, NULL, NULL, NULL);
        hci->writer_active = false;
    }

    // 清空两个队列
    queue_remove_all(hci->cmd_queue, NULL, NULL, cmd_free);
    queue_remove_all(hci->rsp_queue, NULL, NULL, cmd_free);
    return true;
}

11.3 内核错误码

cpp 复制代码
// lib/hci.h

// HCI 错误码
#define HCI_UNKNOWN_COMMAND             0x01  // 未知命令
#define HCI_NO_CONNECTION              0x02  // 无连接
#define HCI_HARDWARE_FAILURE           0x03  // 硬件故障
#define HCI_PAGE_TIMEOUT               0x04  // 页面超时
#define HCI_AUTHENTICATION_FAILURE     0x05  // 认证失败
#define HCI_CONNECTION_TIMEOUT        0x08  // 连接超时
#define HCI_COMMAND_DISALLOWED         0x0c  // 命令不允许
#define HCI_REJECTED_SECURITY          0x0e  // 安全拒绝
#define HCI_UNSUPPORTED_FEATURE        0x11  // 不支持功能
#define HCI_INVALID_PARAMETERS        0x12  // 无效参数
#define HCI_REMOTE_USER_TERMINATED    0x13  // 远端终止
#define HCI_CONNECTION_TERMINATED     0x16  // 连接终止

十二、调试与抓包

12.1 启用 BlueZ 调试日志

cpp 复制代码
# 编译时启用调试
./configure --enable-debug

# 运行时设置环境变量
export BLUEZ_DEBUG=all
bluetoothd -n -d

12.2 使用 btmon 抓包

cpp 复制代码
# 安装 btmon (BlueZ 监控工具)
# btmon 通常随 BlueZ 一起编译

# 启动抓包
btmon

# 保存到文件
btmon -w capture.log

# 过滤特定设备
btmon -f hci0

# 实时查看并保存
btmon -f hci0 -w capture.log &

12.3 使用 hcitool 诊断

cpp 复制代码
# 查看本地适配器
hcitool dev

# 扫描远程设备
hcitool scan

# LE 扫描
hcitool lescan

# 查看连接状态
hcitool con

# 查询远程设备信息
hcitool info XX:XX:XX:XX:XX:XX

# 读取远程名称
hcitool name XX:XX:XX:XX:XX:XX

12.4 使用 systemd 日志

cpp 复制代码
# 查看 BlueZ 服务日志
journalctl -u bluetooth -f

# 查看内核蓝牙日志
dmesg | grep -i bluetooth

# 查看 HCI 设备信息
hciconfig hci0
hciconfig hci0 up
hciconfig hci0 down

十三、核心函数索引

13.1 bt_hci 相关函数

|-----------------------------|------------------|-------------------|
| 函数 | 文件 | 功能 |
| bt_hci_new() | src/shared/hci.c | 从 fd 创建 bt_hci 实例 |
| bt_hci_new_user_channel() | src/shared/hci.c | 创建用户通道模式 |
| bt_hci_new_raw_device() | src/shared/hci.c | 创建原始设备模式 |
| bt_hci_send() | src/shared/hci.c | 发送 HCI 指令 |
| bt_hci_cancel() | src/shared/hci.c | 取消指定指令 |
| bt_hci_flush() | src/shared/hci.c | 清空所有指令 |
| bt_hci_register() | src/shared/hci.c | 注册事件回调 |
| bt_hci_unregister() | src/shared/hci.c | 取消事件回调 |

13.2 mgmt 相关函数

|-----------------------|-------------------|--------------|
| 函数 | 文件 | 功能 |
| mgmt_new() | src/shared/mgmt.c | 创建 mgmt 实例 |
| mgmt_new_default() | src/shared/mgmt.c | 创建默认 mgmt 实例 |
| mgmt_send() | src/shared/mgmt.c | 发送管理命令 |
| mgmt_send_timeout() | src/shared/mgmt.c | 发送带超时的命令 |
| mgmt_register() | src/shared/mgmt.c | 注册事件通知 |
| mgmt_cancel() | src/shared/mgmt.c | 取消指定请求 |

13.3 adapter 相关函数

|-----------------------------|---------------|----------|
| 函数 | 文件 | 功能 |
| adapter_init() | src/adapter.c | 初始化适配器管理 |
| btd_adapter_get_default() | src/adapter.c | 获取默认适配器 |
| btd_adapter_get_index() | src/adapter.c | 获取适配器索引 |
| btd_adapter_set_class() | src/adapter.c | 设置设备类型 |
| adapter_set_name() | src/adapter.c | 设置设备名 |

十四、总结

Linux 蓝牙子系统通过精心设计的分层架构,实现了内核与用户态的清晰分离:

  1. 内核 hci_core 模块:处理 HCI 协议报文收发、L2CAP 协议、设备驱动管理

  2. HCI 套接字机制:通过 PF_BLUETOOTH 地址族提供标准化通信接口

  3. bt_hci 封装层:BlueZ 对 HCI 套接字的高级封装,提供指令队列、事件回调机制

  4. mgmt 管理接口:提供适配器管理的高层抽象

  5. adapter 模块:协调与整合所有 HCI 相关操作

理解这套交互机制,对于蓝牙外设适配、协议栈开发、问题调试都具有重要意义。


相关推荐
Dr_Fourier1 小时前
AWQ量化
c++·人工智能·pytorch·ai
Casbin开源社区1 小时前
OpenAgent 详解:单二进制自托管 AI Agent 平台,30+ 模型接入、RAG 知识库、MCP 工具调用与 Casbin 工具权限
人工智能·golang·开源
江屿风1 小时前
【Linux系统】【Linux 进程程序替换机制解析及自定义 Shell 核心逻辑实现 】流食般投喂
linux·运维·服务器·开发语言·笔记
BJ_Bonree1 小时前
博睿数据加入ITSS分会,成为国家级信息技术服务标准化体系单位成员!
大数据·运维·数据库·人工智能·可观测性
河图洛水1 小时前
Behavior-1k:2026 挑战赛纯仿真 benchmark
人工智能·机器人
好不玩呀1 小时前
一次PXE服务器上IPV6问题的记录
linux·运维·服务器
光锥智能1 小时前
Agentic Cloud,云厂商们的新叙事
人工智能·华为
ZDN_is_beauty1 小时前
綦江烟草部署(在wsl2里部署)
人工智能·python
子非鱼eva1 小时前
昇腾开源仓Issue分析解答-mindspore精选(二)·mindformers深耕与三大户续采
人工智能·ai·gitcode