【BlueZ 】内核态 L2CAP 基础:与 BlueZ 用户态的数据包交互流程

L2CAP(Logical Link Control and Adaptation Protocol)是蓝牙协议栈的数据链路层,负责将上层应用数据分割为蓝牙基带包传输,并提供协议复用、组寻址、流量控制等核心能力。Linux 内核实现了完整的 L2CAP 协议栈,BlueZ 用户态通过 L2CAP Socket 与内核交互。本文基于 BlueZ 5.x 源码与 Linux 内核蓝牙子系统,深度拆解用户态与内核态的完整数据交互链路。


目录

[一、内核 L2CAP 协议栈架构](#一、内核 L2CAP 协议栈架构)

[二、BlueZ 用户态 L2CAP 实现](#二、BlueZ 用户态 L2CAP 实现)

三、数据发送完整链路

四、数据接收完整链路

五、分片重组机制

六、流量控制机制

[七、BLE 与经典 L2CAP 差异化处理](#七、BLE 与经典 L2CAP 差异化处理)

八、用户态与内核态数据交互边界

[九、 异常处理与丢包机制](#九、 异常处理与丢包机制)

十、调试与排坑技巧

十一、核心函数速查表

十二、数据结构映射关系

十三、总结


一、内核 L2CAP 协议栈架构

1.1 整体分层模型

1.2 内核核心结构体

1.2.1 l2cap_chan --- L2CAP 通道

cpp 复制代码
// 内核源码: net/bluetooth/l2cap.h

struct l2cap_chan {
    // 通道标识
    __u16 cid;              // Channel ID (0x0001-0xFFFF)
    __u16 scid;             // Source CID
    __u16 dcid;             // Destination CID
    
    // 协议类型
    __u16 psm;              // Protocol/Service Multiplexer
    __u8  mode;              // 通道模式(Basic/ERTM/Streaming等)
    
    // 连接状态
    __u8  state;            // 通道状态
    bdaddr_t psm_bdaddr;    // 对端设备地址
    __u8  psm_bdaddr_type;  // 对端地址类型
    
    // MTU 参数
    __u16 mtu;              // Maximum Transmission Unit
    __u16 imtu;             // Incoming MTU
    __u16 omtu;             // Outgoing MTU
    __u16 mps;              // Maximum PDU Size
    
    // 流量控制
    __u16 tx_credits;       // 发送信用(LE Credit Based)
    __u16 rx_credits;       // 接收信用
    
    // ERTM 重传参数
    __u8  txseq;            // 发送序列号
    __u8  reqseq;           // 请求序列号
    __u8  ftx;              // 重传标志
    __u16 tx_win_size;      // 发送窗口大小
    __u8  max_tx;           // 最大重传次数
    __u16 retrans_timeout;  // 重传超时
    __u16 monitor_timeout;  // 监控超时
    
    // 分片重组
    struct sk_buff *sdu;    // 重组中的 SDU
    __u32 sdu_len;          // SDU 总长度
    __u32 sdu_copied;       // 已复制字节数
    __u16 sdu_tx_ident;     // 发送 SDU 的标识
    
    // 发送队列
    struct sk_buff_head tx_queue;   // 待发送队列
    struct sk_buff_head tx_reassembly; // 分片重传队列
    struct sk_buff_head rx_queue;   // 接收队列
    
    // 套接字关联
    struct l2cap_sock *sock;
    
    // 操作回调
    int (*recv)(struct l2cap_chan *chan, struct sk_buff *skb);
    void (*close)(struct l2cap_chan *chan);
    void (*state_change)(struct l2cap_chan *chan, int state);
    
    // 私有数据
    void *priv;
};

1.2.2 l2cap_sock --- L2CAP 套接字

cpp 复制代码
// 内核源码: net/bluetooth/l2cap_sock.c

struct l2cap_sock {
    struct sock sk;          // 继承的通用套接字结构
    
    // 本地地址
    struct sockaddr_l2 l2a;  // 绑定的本地地址
    
    // 通道引用
    struct l2cap_chan *chan; // 关联的 L2CAP 通道
    
    // 缓冲区
    struct sk_buff_head rx_queue;  // 接收队列
    struct sk_buff_head tx_queue;  // 发送队列
    
    // 等待队列
    wait_queue_head_t wait;
    
    // 状态标志
    __u8 flags;
    __u8 state;
};

1.2.3 sockaddr_l2 --- 用户态套接字地址

cpp 复制代码
// 用户态头文件: lib/l2cap.h (BlueZ)

struct sockaddr_l2 {
    sa_family_t    l2_family;     // AF_BLUETOOTH
    unsigned short l2_psm;        // PSM(Protocol Service Multiplexer)
    bdaddr_t       l2_bdaddr;    // 蓝牙设备地址
    unsigned short l2_cid;        // Channel ID(固定通道用)
    uint8_t        l2_bdaddr_type; // 地址类型(PUBLIC/RANDOM)
};

1.3 核心操作 回调 表

cpp 复制代码
// 内核 L2CAP Socket 操作集
// net/bluetooth/l2cap_sock.c

static const struct proto_ops l2cap_sock_ops = {
    .family     = PF_BLUETOOTH,
    .owner      = THIS_MODULE,
    
    // 套接字操作
    .bind       = l2cap_sock_bind,
    .connect    = l2cap_sock_connect,
    .listen     = l2cap_sock_listen,
    .accept     = l2cap_sock_accept,
    .getname    = l2cap_sock_getname,
    .peername   = l2cap_sock_peername,
    .sendmsg    = l2cap_sock_sendmsg,
    .recvmsg    = l2cap_sock_recvmsg,
    .shutdown   = l2cap_sock_shutdown,
    .close      = l2cap_sock_close,
    .setsockopt = l2cap_sock_setsockopt,
    .getsockopt = l2cap_sock_getsockopt,
};

二、BlueZ 用户态 L2CAP 实现

2.1 btio 抽象层

BlueZ 通过 btio 库封装蓝牙 IO 操作,为上层 Profile 提供统一接口:

cpp 复制代码
// btio/btio.h

typedef enum {
    BT_IO_L2CAP,     // L2CAP 通道
    BT_IO_RFCOMM,    // RFCOMM 通道
    BT_IO_SCO,       // SCO 通道
    BT_IO_INVALID,
} BtIOType;

// 通道模式
typedef enum {
    BT_IO_MODE_BASIC = 0,          // 基础模式
    BT_IO_MODE_ERTM,              // 增强重传模式
    BT_IO_MODE_STREAMING,         // 流式模式
    BT_IO_MODE_LE_FLOWCTL,        // LE 流控模式
    BT_IO_MODE_EXT_FLOWCTL        // 扩展流控模式(ECRED)
} BtIOMode;

// 创建连接
GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
                         GDestroyNotify destroy, GError **gerr,
                         BtIOOption opt1, ...);

// 创建监听
GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
                        gpointer user_data, GDestroyNotify destroy,
                        GError **err, BtIOOption opt1, ...);

2.2 L2CAP 套接字创建

cpp 复制代码
// btio/btio.c --- create_io()

static GIOChannel *create_io(gboolean server, struct set_opts *opts,
                              GError **err)
{
    int sock;
    GIOChannel *io;

    switch (opts->type) {
    case BT_IO_L2CAP:
        // 1. 创建 L2CAP Socket
        sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
        if (sock < 0) {
            ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
            return NULL;
        }
        
        // 2. 绑定本地地址
        if (l2cap_bind(sock, &opts->src, opts->src_type,
                        server ? opts->psm : 0, opts->cid, err) < 0)
            goto failed;
        
        // 3. 设置通道参数
        if (!l2cap_set(sock, opts->src_type, opts->sec_level,
                        opts->imtu, opts->omtu, opts->mode,
                        opts->central, opts->flushable, opts->priority,
                        err))
            goto failed;
        break;
    // ... RFCOMM, SCO 分支
    }

    // 4. 包装为 GIOChannel(GLib 事件循环集成)
    io = g_io_channel_unix_new(sock);
    g_io_channel_set_close_on_unref(io, TRUE);
    g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);

    return io;
}

2.3 L2CAP 绑定与连接

cpp 复制代码
// btio/btio.c --- l2cap_bind()

static int l2cap_bind(int sock, const bdaddr_t *src, uint8_t src_type,
                      uint16_t psm, uint16_t cid, GError **err)
{
    struct sockaddr_l2 addr;

    memset(&addr, 0, sizeof(addr));
    addr.l2_family = AF_BLUETOOTH;
    bacpy(&addr.l2_bdaddr, src);      // 本地蓝牙地址
    
    // PSM 与 CID 二选一
    if (cid)
        addr.l2_cid = htobs(cid);      // 固定通道用 CID
    else
        addr.l2_psm = htobs(psm);      // 动态通道用 PSM
    
    addr.l2_bdaddr_type = src_type;    // 地址类型

    // 系统调用 -> 内核 l2cap_sock_bind()
    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        int error = -errno;
        ERROR_FAILED(err, "l2cap_bind", errno);
        return error;
    }

    return 0;
}
cpp 复制代码
// btio/btio.c --- l2cap_connect()

static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
                         uint16_t psm, uint16_t cid)
{
    int err;
    struct sockaddr_l2 addr;

    memset(&addr, 0, sizeof(addr));
    addr.l2_family = AF_BLUETOOTH;
    bacpy(&addr.l2_bdaddr, dst);      // 目标蓝牙地址
    
    if (cid)
        addr.l2_cid = htobs(cid);
    else
        addr.l2_psm = htobs(psm);
    
    addr.l2_bdaddr_type = dst_type;

    // 系统调用 -> 内核 l2cap_sock_connect()
    err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
    if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
        return -errno;

    return 0;
}

2.4 参数配置接口

cpp 复制代码
// btio/btio.c --- l2cap_set()

static gboolean l2cap_set(int sock, uint8_t src_type, int sec_level,
                          uint16_t imtu, uint16_t omtu, uint8_t mode,
                          int central, int flushable, uint32_t priority,
                          GError **err)
{
    // BR/EDR 与 LE 使用不同的 sockopt 接口
    if (imtu || omtu || mode) {
        gboolean ret = FALSE;

        if (src_type == BDADDR_BREDR)
            // BR/EDR: SOL_L2CAP + L2CAP_OPTIONS
            ret = set_l2opts(sock, imtu, omtu, mode, err);
        else
            // LE: SOL_BLUETOOTH + BT_RCVMTU/BT_MODE
            {
                if (imtu)
                    ret = set_le_imtu(sock, imtu, err);
                if (ret && mode)
                    ret = set_le_mode(sock, mode, err);
            }

        if (!ret)
            return ret;
    }

    // 主从角色设置
    if (central >= 0 && l2cap_set_central(sock, central) < 0) {
        ERROR_FAILED(err, "l2cap_set_central", errno);
        return FALSE;
    }

    // 安全性设置
    if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
        return FALSE;

    return TRUE;
}

BR/EDR 参数设置

cpp 复制代码
// btio/btio.c --- set_l2opts()

static gboolean set_l2opts(int sock, uint16_t imtu, uint16_t omtu,
                            uint8_t mode, GError **err)
{
    struct l2cap_options l2o;
    socklen_t len;

    memset(&l2o, 0, sizeof(l2o));
    len = sizeof(l2o);
    
    // 先获取当前选项
    if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
        ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
        return FALSE;
    }

    // 修改 MTU
    if (imtu)  l2o.imtu = imtu;
    if (omtu)  l2o.omtu = omtu;

    // 设置模式
    if (mode) {
        l2o.mode = mode_l2mode(mode);
        // mode_l2mode 映射:
        // BT_IO_MODE_BASIC    -> L2CAP_MODE_BASIC (0x00)
        // BT_IO_MODE_ERTM    -> L2CAP_MODE_ERTM (0x03)
        // BT_IO_MODE_STREAMING-> L2CAP_MODE_STREAMING (0x04)
    }

    // 重新设置
    if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
        ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
        return FALSE;
    }

    return TRUE;
}

LE 参数设置

cpp 复制代码
// btio/btio.c --- set_le_imtu()

static gboolean set_le_imtu(int sock, uint16_t imtu, GError **err)
{
    // LE 使用 SOL_BLUETOOTH 级别选项
    if (setsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, &imtu,
                    sizeof(imtu)) < 0) {
        ERROR_FAILED(err, "setsockopt(BT_RCVMTU)", errno);
        return FALSE;
    }
    return TRUE;
}

// btio/btio.c --- set_le_mode()

static gboolean set_le_mode(int sock, uint8_t mode, GError **err)
{
    // LE 模式: BT_MODE_LE_FLOWCTL (0x80) 或 BT_MODE_ECRED (0x81)
    if (setsockopt(sock, SOL_BLUETOOTH, BT_MODE, &mode,
                    sizeof(mode)) < 0) {
        ERROR_FAILED(err, "setsockopt(BT_MODE)", errno);
        return FALSE;
    }
    return TRUE;
}

三、数据发送完整链路

3.1 用户态发送流程

3.2 内核发送实现

l2cap_sock_sendmsg

cpp 复制代码
// 内核: net/bluetooth/l2cap_sock.c

static int l2cap_sock_sendmsg(struct sock *sk, struct msghdr *msg,
                             size_t len)
{
    struct l2cap_sock *l2cap_sk = l2cap_pi(sk);
    struct l2cap_chan *chan = l2cap_sk->chan;
    struct sk_buff *skb;
    int err;

    // 1. 检查通道状态
    if (chan->state != L2CAP_CONNECTED)
        return -ENOTCONN;

    // 2. 分配 sk_buff
    skb = sock_alloc_send_skb(sk, len, 0, &err);
    if (!skb)
        return err;

    // 3. 复制用户数据到内核缓冲区
    if (memcpy_from_msgiori(skb_put(skb, len), msg, len) < 0) {
        kfree_skb(skb);
        return -EFAULT;
    }

    // 4. 调用通道发送
    err = l2cap_chan_send(chan, skb);
    if (err < 0)
        kfree_skb(skb);

    return err;
}

l2cap_chan_send --- 核心发送逻辑

cpp 复制代码
// 内核: net/bluetooth/l2cap_core.c

int l2cap_chan_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
    // 1. MTU 检查
    if (skb->len > chan->mtu)
        return -EMSGSIZE;

    // 2. 流量控制检查
    if (chan->mode == L2CAP_MODE_ERTM || 
        chan->mode == L2CAP_MODE_STREAMING) {
        // ERTM/Streaming: 检查发送窗口
        if (chan->tx_win_size == 0) {
            // 窗口满,排队等待
            skb_queue_tail(&chan->tx_queue, skb);
            return 0;
        }
    } else if (chan->mode == L2CAP_MODE_LE_FLOWCTL ||
               chan->mode == L2CAP_MODE_ECRED) {
        // LE 信用模式: 检查信用
        if (chan->tx_credits == 0) {
            skb_queue_tail(&chan->tx_queue, skb);
            return 0;
        }
        chan->tx_credits--;
    }

    // 3. 模式特定处理
    switch (chan->mode) {
    case L2CAP_MODE_BASIC:
        // 基础模式:直接发送
        return l2cap_do_send(chan, skb);
        
    case L2CAP_MODE_ERTM:
        // ERTM:添加重传头
        return l2cap_ertm_send(chan, skb);
        
    case L2CAP_MODE_STREAMING:
        // Streaming:添加序号
        return l2cap_streaming_send(chan, skb);
        
    case L2CAP_MODE_LE_FLOWCTL:
    case L2CAP_MODE_ECRED:
        // LE 流控:发送并扣减信用
        return l2cap_le_send_data(chan, skb);
    }
}

l2cap_do_send --- 基础模式发送

cpp 复制代码
// 内核: net/bluetooth/l2cap_core.c

static int l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
    // 构造 L2CAP 报文
    // [L2CAP Header: len(2B) + cid(2B)] [Payload]
    
    __le16 *hdr;
    
    // 预留 L2CAP 头部空间
    skb_push(skb, L2CAP_HDR_SIZE);
    
    // 填充头部
    hdr = (__le16 *)skb->data;
    put_le16(hdr, skb->len - L2CAP_HDR_SIZE);  // 长度
    put_le16(hdr + 1, chan->dcid);              // 目的 CID
    
    // 通过 HCI ACL 链路发送
    // 调用 hci_send_acl() 或直接提交给驱动
    return l2cap_send_acl(chan->conn, skb);
}

四、数据接收完整链路

4.1 内核接收流程

4.2 内核接收实现

L2CAP 帧接收

cpp 复制代码
// 内核: net/bluetooth/l2cap_core.c

static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
{
    struct l2cap_hdr *hdr;
    u16 cid, len;
    struct l2cap_chan *chan;

    // 1. 检查最小长度
    if (skb->len < L2CAP_HDR_SIZE) {
        kfree_skb(skb);
        return;
    }

    // 2. 解析 L2CAP 头
    hdr = (struct l2cap_hdr *)skb->data;
    len = __le16_to_cpu(hdr->len);
    cid = __le16_to_cpu(hdr->cid);

    skb_pull(skb, L2CAP_HDR_SIZE);

    // 3. 固定通道处理
    if (cid == L2CAP_CID_SIGNALING || 
        cid == L2CAP_CID_LE_SIGNALING) {
        l2cap_recv_signal(conn, skb, len);   // 信令通道
        return;
    }

    // 4. 查找动态通道
    chan = l2cap_chan_find_by_cid(conn, cid);
    if (!chan) {
        // 未知通道,丢弃
        kfree_skb(skb);
        return;
    }

    // 5. 调用通道接收回调
    chan->recv(chan, skb);
}

l2cap_sock_recv_cb --- 套接字数据回填

cpp 复制代码
// 内核: net/bluetooth/l2cap_sock.c

static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{
    struct l2cap_sock *sk = chan->sock;
    struct sock *sock = &sk->sk;

    // 1. 检查队列长度限制
    if (skb_queue_len(&sk->rx_queue) > L2CAP_RX_QUEUE_LEN) {
        // 队列满,丢包
        kfree_skb(skb);
        return -ENOMEM;
    }

    // 2. 数据入接收队列
    skb_queue_tail(&sk->rx_queue, skb);

    // 3. 触发套接字可读事件
    sock->sk_data_ready(sock);   // 唤醒 epoll/select 等待者

    return 0;
}

l2cap_sock_recvmsg --- 用户态数据读取

cpp 复制代码
// 内核: net/bluetooth/l2cap_sock.c

static int l2cap_sock_recvmsg(struct sock *sk, struct msghdr *msg,
                              size_t len, int flags, int *addr_len)
{
    struct l2cap_sock *l2cap_sk = l2cap_pi(sk);
    struct sk_buff *skb;
    int err = 0;

    // 1. 等待数据
    skb = skb_recv_datagram(sk, flags, &err);
    if (!skb)
        return err;

    // 2. 处理控制消息
    if (skb->len < len)
        len = skb->len;

    // 3. 复制数据到用户空间
    if (memcpy_to_msgiori(msg, skb->data, len) < 0) {
        kfree_skb(skb);
        return -EFAULT;
    }

    // 4. 更新接收者地址
    if (msg->msg_name) {
        struct sockaddr_l2 *addr = (struct sockaddr_l2 *)msg->msg_name;
        addr->l2_family = AF_BLUETOOTH;
        bacpy(&addr->l2_bdaddr, &l2cap_sk->l2a.l2_bdaddr);
        addr->l2_cid = l2cap_sk->l2a.l2_cid;
        *addr_len = sizeof(*addr);
    }

    kfree_skb(skb);
    return len;
}

4.3 用户态接收

cpp 复制代码
// BlueZ 用户态:io_session_event() 回调
// src/sdpd-server.c

static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, 
                                gpointer data)
{
    sdp_pdu_hdr_t hdr;
    uint8_t *buf;
    int sk, len, size;

    if (cond & G_IO_NVAL)
        return FALSE;

    sk = g_io_channel_unix_get_fd(chan);

    // 1. 事件错误处理
    if (cond & (G_IO_HUP | G_IO_ERR))
        goto cleanup;

    // 2. 预读获取报文头
    len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
    if (len < 0 || (unsigned int)len < sizeof(sdp_pdu_hdr_t))
        goto cleanup;

    // 3. 计算完整报文长度
    size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
    buf = malloc(size);
    if (!buf)
        return TRUE;

    // 4. 读取完整报文
    len = recv(sk, buf, size, 0);
    if (len <= 0) {
        free(buf);
        goto cleanup;
    }

    // 5. 交给协议处理层
    handle_request(sk, buf, len);

    return TRUE;

cleanup:
    sdp_svcdb_collect_all(sk);
    sdp_cstate_cleanup(sk);
    return FALSE;
}

五、分片重组机制

5.1 SAR 位与分片标识

cpp 复制代码
// L2CAP 控制字段中的 SAR 位
// btio/btio.c 与 monitor/l2cap.c 中的定义

#define L2CAP_CTRL_SAR_MASK     0xC000  // SAR 位掩码(16位控制字段)
#define L2CAP_SAR_UNSEGMENTED   0x00    // 不分片
#define L2CAP_SAR_START         0x01    // 起始分片
#define L2CAP_SAR_END           0x02    // 结束分片
#define L2CAP_SAR_CONTINUE      0x03    // 中间分片

// 扩展控制字段(32位)
#define L2CAP_EXT_CTRL_SAR_MASK 0x00030000

5.2 内核分片处理

cpp 复制代码
// 内核: net/bluetooth/l2cap_core.c

// 发送侧分片
static int l2cap_sdu_send_segment(struct l2cap_chan *chan, 
                                  struct sk_buff *sdu, int offset)
{
    struct sk_buff *skb;
    u8 sar;
    
    // 1. 确定 SAR 位
    if (offset == 0 && sdu->len <= chan->mtu)
        sar = L2CAP_SAR_UNSEGMENTED;     // 不分片
    else if (offset == 0)
        sar = L2CAP_SAR_START;          // 起始分片
    else if (offset + chan->mtu >= sdu->len)
        sar = L2CAP_SAR_END;            // 结束分片
    else
        sar = L2CAP_SAR_CONTINUE;       // 中间分片
    
    // 2. 构造分片报文
    skb = alloc_skb(L2CAP_HDR_SIZE + 2 + chan->mtu);
    
    // 3. 填充控制字段(含 SAR 位)
    // 基础模式:sar 在 16 位控制字段的 bit14-15
    // ERTM/Streaming:sar 在 32 位扩展控制字段的 bit16-17
    __le16 *ctrl = (__le16 *)skb_put(skb, 2);
    put_le16(ctrl, sar << L2CAP_CTRL_SAR_SHIFT);
    
    // 4. 复制分片数据
    int seg_len = min(chan->mtu, sdu->len - offset);
    skb_put_data(skb, sdu->data + offset, seg_len);
    
    // 5. 发送分片
    return l2cap_do_send(chan, skb);
}

5.3 内核重组实现

cpp 复制代码
// 内核: net/bluetooth/l2cap_core.c

static int l2cap_sdu_recv_data(struct l2cap_chan *chan, struct sk_buff *skb)
{
    u8 sar;

    // 1. 解析 SAR 位
    if (chan->mode == L2CAP_MODE_BASIC)
        sar = (skb->data[0] & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
    else
        sar = (skb->data[0] & L2CAP_EXT_CTRL_SAR_MASK) >> 
              L2CAP_EXT_CTRL_SAR_SHIFT;

    // 2. 根据 SAR 处理
    switch (sar) {
    case L2CAP_SAR_UNSEGMENTED:
        // 不分片,直接上报
        return l2cap_sock_recv_cb(chan, skb);
        
    case L2CAP_SAR_START:
        // 起始分片,创建重组缓冲区
        if (chan->sdu) {
            // 已有重组数据,丢弃
            kfree_skb(chan->sdu);
            chan->sdu = NULL;
        }
        chan->sdu = skb_clone(skb, GFP_ATOMIC);
        chan->sdu_copied = skb->len;
        break;
        
    case L2CAP_SAR_CONTINUE:
        // 中间分片,追加到缓冲区
        if (chan->sdu) {
            skb_append(chan->sdu, skb->data, skb->len);
            chan->sdu_copied += skb->len;
        }
        kfree_skb(skb);
        break;
        
    case L2CAP_SAR_END:
        // 结束分片,完成重组
        if (chan->sdu) {
            skb_append(chan->sdu, skb->data, skb->len);
            // 完整 SDU 上报
            l2cap_sock_recv_cb(chan, chan->sdu);
            chan->sdu = NULL;
        }
        kfree_skb(skb);
        break;
    }

    return 0;
}

5.4 用户态监控分析

cpp 复制代码
// monitor/l2cap.c --- 分片状态跟踪

struct index_data {
    void *frag_buf;      // 重组缓冲区
    uint16_t frag_pos;   // 当前位置
    uint16_t frag_len;   // 总长度
    uint16_t frag_cid;   // 通道 ID
};

static struct index_data index_list[MAX_INDEX][2];

// 清空分片缓冲区
static void clear_fragment_buffer(uint16_t index, bool in)
{
    free(index_list[index][in].frag_buf);
    index_list[index][in].frag_buf = NULL;
    index_list[index][in].frag_pos = 0;
    index_list[index][in].frag_len = 0;
}

六、流量控制机制

6.1 三种流量控制模式

|-----------|------------------------------|-----------|--------------|
| 模式 | 常量 | 适用场景 | 流控方式 |
| Basic | L2CAP_MODE_BASIC (0x00) | 传统 BR/EDR | 无流控,依赖基带重传 |
| ERTM | L2CAP_MODE_ERTM (0x03) | 可靠传输 | 滑动窗口 + 重传定时器 |
| Streaming | L2CAP_MODE_STREAMING (0x04) | 实时音视频 | 窗口控制,不重传 |
| LE Credit | L2CAP_MODE_LE_FLOWCTL (0x80) | BLE 单连接 | 信用计数 |
| ECRED | L2CAP_MODE_ECRED (0x81) | BLE 多连接 | 扩展信用 |

6.2 ERTM 重传流程

cpp 复制代码
// 内核: net/bluetooth/l2cap_ertm.c

struct l2cap_ertm_state {
    u8 txseq;              // 发送序列号 (0-63)
    u8 reqseq;             // 期望接收序列号
    u8 ftx;                // 重传标志
    
    u16 tx_win_size;       // 发送窗口大小
    u8  max_tx;            // 最大重传次数
    u16 retrans_timeout;   // 重传超时(ms)
    u16 monitor_timeout;   // 监控超时(ms)
    
    struct timer_list retrans_timer;   // 重传定时器
    struct timer_list monitor_timer;   // 监控定时器
    
    struct sk_buff_head tx_reassembly; // 未确认的发送帧队列
};

// 发送 I-Frame
static int l2cap_ertm_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
    struct l2cap_ertm_state *state = chan->priv;
    
    // 1. 检查窗口
    if (state->tx_win_size == 0)
        return -EAGAIN;  // 窗口满,等待
    
    // 2. 添加 ERTM 控制字段
    // [Control: TxSeq(6bit) + ReqSeq(6bit) + SAR(2bit) + ...]
    
    // 3. 设置重传定时器
    mod_timer(&state->retrans_timer, 
              jiffies + msecs_to_jiffies(state->retrans_timeout));
    
    // 4. 入未确认队列
    skb_queue_tail(&state->tx_reassembly, skb);
    
    // 5. 扣减窗口
    state->tx_win_size--;
    
    // 6. 发送
    return l2cap_do_send(chan, skb);
}

// 接收 RR 帧(Receiver Ready)
static void l2cap_ertm_recv_rr(struct l2cap_chan *chan, u8 reqseq)
{
    struct l2cap_ertm_state *state = chan->priv;
    
    // 1. 确认 up to reqseq-1 的帧
    while (!skb_queue_empty(&state->tx_reassembly)) {
        struct sk_buff *skb = skb_peek(&state->tx_reassembly);
        u8 frame_seq = l2cap_get_txseq(skb);
        
        if (frame_seq == reqseq)
            break;  // 到达已确认位置
        
        // 释放已确认帧
        skb_dequeue(&state->tx_reassembly);
        kfree_skb(skb);
    }
    
    // 2. 更新窗口
    state->tx_win_size = min(chan->mps, 
            state->tx_win_size + (reqseq - state->reqseq));
    state->reqseq = reqseq;
    
    // 3. 重传定时器重启
    if (!skb_queue_empty(&state->tx_reassembly))
        mod_timer(&state->retrans_timer,
                  jiffies + msecs_to_jiffies(state->retrans_timeout));
}

6.3 LE Credit 流控

cpp 复制代码
// 内核: net/bluetooth/l2cap_le.c

// LE Credit Based Flow Control 接收
static void l2cap_le_flowctl_recv_credits(struct l2cap_chan *chan, 
                                          u16 credits)
{
    // 增加发送信用
    chan->tx_credits += credits;
    
    // 触发发送队列中的数据
    l2cap_le_resume_tx(chan);
}

// 检查并执行发送
static int l2cap_le_send_data(struct l2cap_chan *chan, struct sk_buff *skb)
{
    // 1. 检查信用
    if (chan->tx_credits == 0) {
        skb_queue_tail(&chan->tx_queue, skb);
        return 0;  // 等待信用补充
    }
    
    // 2. 扣减信用
    chan->tx_credits--;
    
    // 3. 发送数据
    return l2cap_do_send(chan, skb);
}

// 信用补充后恢复发送
static void l2cap_le_resume_tx(struct l2cap_chan *chan)
{
    struct sk_buff *skb;
    
    while (chan->tx_credits > 0 && 
           (skb = skb_dequeue(&chan->tx_queue))) {
        l2cap_do_send(chan, skb);
        chan->tx_credits--;
    }
}

七、BLE 与经典 L2CAP 差异化处理

7.1 核心差异对比

|------------|------------------------------------|----------------------------|
| 特性 | 经典 L2CAP (BR/EDR) | BLE L2CAP |
| 套接字类型 | SOCK_SEQPACKET | SOCK_SEQPACKET |
| 寻址方式 | PSM (Protocol Service Multiplexer) | CID (Channel ID) |
| 信令通道 | CID 0x0001 | CID 0x0005 |
| 默认 MTU | 672 字节 | 23 字节(可协商至 65535) |
| 流控模式 | Basic/ERTM/Streaming | LE Flow Control / ECRED |
| 信用机制 | 窗口大小(Window Size) | 信用值(Credits) |
| 连接建立 | 3 步握手(Conf Req/Rsp) | 直接连接(LE Create Connection) |
| 地址类型 | 仅 Public | Public / Random |

7.2 BlueZ 中的差异化处理

cpp 复制代码
// btio/btio.c --- l2cap_set()

static gboolean l2cap_set(int sock, uint8_t src_type, int sec_level,
                          uint16_t imtu, uint16_t omtu, uint8_t mode,
                          int central, int flushable, uint32_t priority,
                          GError **err)
{
    if (imtu || omtu || mode) {
        gboolean ret = FALSE;

        // 根据地址类型选择不同 sockopt
        if (src_type == BDADDR_BREDR)
            // BR/EDR: 使用 SOL_L2CAP 级别的 L2CAP_OPTIONS
            ret = set_l2opts(sock, imtu, omtu, mode, err);
        else
            // LE: 使用 SOL_BLUETOOTH 级别的 BT_RCVMTU/BT_MODE
            {
                if (imtu)
                    ret = set_le_imtu(sock, imtu, err);
                if (ret && mode)
                    ret = set_le_mode(sock, mode, err);
            }

        if (!ret)
            return ret;
    }
    // ...
}

7.3 地址类型判断

cpp 复制代码
// 用户态地址类型定义
// lib/bluetooth.h

#define BDADDR_BREDR    0x00  // BR/EDR(经典蓝牙)
#define BDADDR_LE_PUBLIC 0x01  // LE 公共地址
#define BDADDR_LE_RANDOM 0x02  // LE 随机地址

// BlueZ 在创建连接时根据设备类型选择
// src/device.c --- 地址类型选择

uint8_t determine_addr_type(struct btd_device *device)
{
    if (device->type == BT_TRANSPORT_LE) {
        if (device->info.flags & MGMT_DEV_INFO_RANDOM)
            return BDADDR_LE_RANDOM;
        else
            return BDADDR_LE_PUBLIC;
    }
    return BDADDR_BREDR;
}

7.4 信令协议差异

cpp 复制代码
// monitor/l2cap.c --- 信令操作码表

// BR/EDR 信令
static const struct sig_opcode_data bredr_sig_opcode_table[] = {
    { 0x01, "Command Reject",          sig_cmd_reject, 2, false },
    { 0x02, "Connection Request",      sig_conn_req,   4, true  },
    { 0x03, "Connection Response",     sig_conn_rsp,   8, true  },
    { 0x04, "Configure Request",       sig_config_req, 4, false },
    { 0x05, "Configure Response",      sig_config_rsp, 6, false },
    { 0x06, "Disconnection Request",   sig_disconn_req,4, true  },
    { 0x07, "Disconnection Response",  sig_disconn_rsp,4, true  },
    { 0x0c, "Create Channel Request", sig_create_chan_req, 5, true },
    { 0x0d, "Create Channel Response",sig_create_chan_rsp, 8, true },
    // ... AMP 相关
};

// LE 信令
static const struct sig_opcode_data le_sig_opcode_table[] = {
    { 0x01, "Command Reject",              sig_cmd_reject, 2, false },
    { 0x06, "Disconnection Request",        sig_disconn_req, 4, true  },
    { 0x07, "Disconnection Response",       sig_disconn_rsp, 4, true  },
    { 0x12, "Connection Param Update Req", sig_conn_param_req, 8, true  },
    { 0x13, "Connection Param Update Rsp", sig_conn_param_rsp,2, true },
    { 0x14, "LE Connection Request",       sig_le_conn_req,   10, true },
    { 0x15, "LE Connection Response",      sig_le_conn_rsp,   10, true },
    { 0x16, "LE Flow Control Credit",      sig_le_flowctl_creds, 4, true },
    // ... ECRED 相关
};

7.5 LE Create Connection 参数

cpp 复制代码
// monitor/l2cap.c --- LE 连接请求解析

static void sig_le_conn_req(const struct l2cap_frame *frame)
{
    const struct bt_l2cap_pdu_le_conn_req *pdu = frame->data;

    print_psm(pdu->psm);
    print_cid("Source", pdu->scid);
    print_field("MTU: %u", le16_to_cpu(pdu->mtu));     // 协商 MTU
    print_field("MPS: %u", le16_to_cpu(pdu->mps));     // 最大 PDU 大小
    print_field("Credits: %u", le16_to_cpu(pdu->credits)); // 初始信用

    // 记录通道信息
    assign_scid(frame, le16_to_cpu(pdu->scid), 
               le16_to_cpu(pdu->psm),
               L2CAP_MODE_LE_FLOWCTL, 0);
}

八、用户态与内核态数据交互边界

8.1 分层职责矩阵

|-------------------|------------|------------------------|
| 层级 | 职责范围 | 关键操作 |
| BlueZ Profile | 协议语义处理 | SDP/RFCOMM/GATT/A2DP |
| btio 封装 | Socket 抽象 | 创建/连接/监听/模式设置 |
| L2CAP Socket | 传输通道抽象 | bind/connect/send/recv |
| 内核 l2cap_core | L2CAP 协议实现 | 分片/重组/流控/重传 |
| 内核 hci_core | HCI 协议 | 指令/事件/ACL 管理 |
| 蓝牙驱动 | 硬件通信 | USB/UART/SDIO 通信 |

8.2 数据格式转换

8.3 状态同步机制

cpp 复制代码
// 用户态监听内核事件
// src/profile.c --- 扩展 Profile 注册

static int ext_register(struct btd_adapter *adapter, struct ext_profile *ext)
{
    // L2CAP 服务器
    if (ext->local_psm) {
        io = bt_io_listen(connect, confirm, l2cap, NULL, &err,
                    BT_IO_OPT_SOURCE_BDADDR,
                    btd_adapter_get_address(adapter),
                    BT_IO_OPT_MODE, ext->mode,
                    BT_IO_OPT_PSM, psm,
                    BT_IO_OPT_SEC_LEVEL, ext->sec_level,
                    BT_IO_OPT_INVALID);
        // ...
    }
}

// GIOChannel 事件监听
g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
               io_accept_event, &l2cap_sock);

8.4 异步通知流程

九、 异常处理与丢包机制

9.1 用户态错误检测

cpp 复制代码
// btio/btio.c --- 连接建立错误处理

GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
                           GDestroyNotify destroy, GError **gerr,
                           BtIOOption opt1, ...)
{
    // ...
    
    err = l2cap_connect(sock, &opts.dst, opts.dst_type,
                        opts.psm, opts.cid);
    if (err < 0) {
        ba2str(&opts.dst, addr);
        g_set_error(gerr, BT_IO_ERROR, -err,
                    "connect to %s: %s (%d)", 
                    addr, strerror(-err), -err);
        g_io_channel_unref(io);
        return NULL;
    }
    
    // ...
}

9.2 内核异常处理

cpp 复制代码
// 内核: net/bluetooth/l2cap_core.c

// 通道错误状态处理
static void l2cap_chan_state_change(struct l2cap_chan *chan, int state)
{
    // 状态异常
    if (state == L2CAP_DISCONNECTED) {
        // 清理重组缓冲区
        if (chan->sdu) {
            kfree_skb(chan->sdu);
            chan->sdu = NULL;
        }
        
        // 清空发送队列
        skb_queue_purge(&chan->tx_queue);
        skb_queue_purge(&chan->rx_queue);
        
        // 通知上层
        if (chan->state_change)
            chan->state_change(chan, state);
    }
}

// MTU 不匹配
int l2cap_chan_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
    if (skb->len > chan->mtu) {
        // 超过 MTU,需要分片或返回错误
        if (chan->mode == L2CAP_MODE_BASIC)
            return -EMSGSIZE;  // 基础模式直接拒绝
        // 其他模式执行分片
    }
    // ...
}

9.3 丢包恢复策略

cpp 复制代码
// 内核: ERTM 重传定时器处理

static void l2cap_ertm_retrans_timeout(struct timer_list *t)
{
    struct l2cap_chan *chan = from_timer(chan, t, 
                              priv.ertm.retrans_timer);
    struct l2cap_ertm_state *state = chan->priv;
    struct sk_buff *skb;

    // 检查是否有未确认帧
    while ((skb = skb_peek(&state->tx_reassembly))) {
        u8 frame_seq = l2cap_get_txseq(skb);
        
        // 达到最大重传次数
        if (l2cap_get_ftx(skb) >= state->max_tx) {
            // 通道失败
            l2cap_chan_state_change(chan, L2CAP_DISCONNECTED);
            return;
        }
        
        // 增加重传标志
        l2cap_set_ftx(skb, 1);
        l2cap_inc_ftx(skb);
        
        // 重传
        l2cap_do_send(chan, skb);
    }
    
    // 重启定时器
    if (!skb_queue_empty(&state->tx_reassembly))
        mod_timer(&state->retrans_timer,
                  jiffies + msecs_to_jiffies(state->retrans_timeout));
}

十、调试与排坑技巧

10.1 内核态调试

cpp 复制代码
# 1. 查看 L2CAP 套接字
cat /proc/net/bluetooth/l2cap

# 2. 查看蓝牙设备信息
hciconfig -a
btmgmt info

# 3. 启用内核蓝牙调试
echo 1 > /sys/module/bluetooth/parameters/disable_ertm
echo 'module bt_hc +p' > /sys/kernel/debug/dynamic_debug/control

# 4. 使用 btmon 抓取 HCI 报文
sudo btmon -f hci0

# 5. 使用 btmgr 查看 L2CAP 连接
sudo btmgmt

# 6. ftrace 跟踪内核 L2CAP
echo 1 > /sys/kernel/tracing/events/l2cap/enable
cat /sys/kernel/tracing/trace_pipe

10.2 用户态调试

cpp 复制代码
# 1. 使用 strace 跟踪系统调用
strace -e trace=socket,bind,connect,sendto,recvfrom \
       -f bluetoothd

# 2. 使用 ltrace 跟踪库函数
ltrace -f -l libbluetooth.so bluetoothd

# 3. GDB 调试 BlueZ
gdb bluetoothd
# 断点: btpktsrc.c, l2cap_sock.c 相关函数

# 4. 启用 BlueZ 调试日志
bluetoothd -d  # 增加调试输出
# 或修改 main.conf 中 [General] 段的 Debug 选项

# 5. 使用 btmon 配合分析
sudo btmon | tee /tmp/bt_trace.log

# 6. Python 脚本解析 btmon 日志
# tools/parser/ 下的解析工具
python3 tools/parser/main.py /tmp/bt_trace.log

10.3 常见问题与解决方案

问题一:L2CAP 连接超时

cpp 复制代码
# 症状:connect() 返回 ETIMEDOUT

# 排查步骤:
# 1. 确认设备在范围内且已连接
hcitool lq XX:XX:XX:XX:XX:XX  # Link Quality

# 2. 检查 ACL 连接状态
btmgmt info
cat /proc/net/bluetooth/l2cap

# 3. 内核日志
dmesg | grep -i l2cap
dmesg | grep -i error

# 4. 常见原因:
#    - 设备未支持目标 PSM
#    - 链路质量差
#    - 安全级别不匹配

问题二:MTU 协商失败

cpp 复制代码
// 症状:getsockopt(L2CAP_OPTIONS) 返回的 MTU 不符合预期

// 解决方案:
// 1. 检查对端支持的 MTU
int sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
struct l2cap_options opts;
socklen_t len = sizeof(opts);
getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &len);
printf("MTU: imtu=%u, omtu=%u\n", opts.imtu, opts.omtu);

// 2. 强制设置 MTU(在 connect 之前)
opts.omtu = 1024;  // 尝试协商更大的 MTU
setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));

问题三:分片数据丢失

cpp 复制代码
// 症状:接收方收到不完整的 SDU

// 排查:
// 1. 检查发送方 MTU 与接收方 imtu 是否匹配
// 2. 确认 SAR 位设置正确
// 3. 监控 sk->sk_receive_queue 的深度

// 解决方案:
// 增加接收缓冲区
int opt = 262144;  // 256KB
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));

问题四:信用耗尽无法发送

cpp 复制代码
// 症状:LE Credit 模式下发送阻塞

// 原因:
// - 接收方未及时返回信用
// - 信用值为 0 时,发送队列阻塞

// 解决方案:
// 1. 增大初始信用值
struct bt_l2cap_pdu_le_conn_req req;
req.credits = htobs(10);  // 初始信用 10

// 2. 及时补充信用
// 接收方处理完数据后,发送 LE_FLOWCTL_CREDITS
struct bt_l2cap_pdu_le_flowctl_creds creds;
creds.credits = htobs(5);  // 补充 5 个信用
send_cmd(BT_L2CAP_OP_LE_FLOWCTL_CREDITS, &creds);

10.4 开发调试最佳实践

10.4.1 代码中的关键日志点

cpp 复制代码
// 建议在以下位置添加日志:

// 用户态:
// 1. 连接建立前后
DBG("L2CAP connect: src=%s, dst=%s, psm=%u",
    src_addr, dst_addr, psm);

// 2. 数据发送
DBG("L2CAP send: %zu bytes to psm %u", len, psm);

// 3. 数据接收
DBG("L2CAP recv: %zu bytes from psm %u", len, psm);

// 内核态(使用 dynamic debug):
// 1. l2cap_sock_sendmsg() 入口
// 2. l2cap_sock_recvmsg() 出口
// 3. l2cap_chan_state_change() 状态转换

10.4.2 状态机跟踪

cpp 复制代码
// 跟踪 L2CAP 通道状态转换
// 内核: net/bluetooth/l2cap_core.c

static const char *l2cap_state_str(enum l2cap_state state)
{
    switch (state) {
    case L2CAP_OPEN:          return "OPEN";
    case L2CAP_BR_CONNECT:     return "BR_CONNECT";
    case L2CAP_BR_CONNECTING:  return "BR_CONNECTING";
    case L2CAP_BR_CONFIG:      return "BR_CONFIG";
    case L2CAP_BR_RECONFIG:   return "BR_RECONFIG";
    case L2CAP_ERTM_CONNECT:  return "ERTM_CONNECT";
    case L2CAP_ERTM_CONFIG:   return "ERTM_CONFIG";
    case L2CAP_STREAM_CONNECT: return "STREAM_CONNECT";
    case L2CAP_STREAM_CONFIG: return "STREAM_CONFIG";
    case L2CAP_LE_CONNECT:    return "LE_CONNECT";
    case L2CAP_LE_CONN_REQ:   return "LE_CONN_REQ";
    case L2CAP_LE_CFG_INFO:   return "LE_CFG_INFO";
    case L2CAP_LE_CFG_RECV:   return "LE_CFG_RECV";
    case L2CAP_DISCONNECTED:  return "DISCONNECTED";
    default:                  return "UNKNOWN";
    }
}

十一、核心函数速查表

11.1 BlueZ 用户态关键函数

|-------------------|---------------|--------------------------|
| 函数名 | 文件路径 | 功能描述 |
| bt_io_connect() | btio/btio.c | 创建 L2CAP/RFCOMM/SCO 出站连接 |
| bt_io_listen() | btio/btio.c | 创建 L2CAP/RFCOMM/SCO 入站监听 |
| bt_io_accept() | btio/btio.c | 接受入站连接 |
| l2cap_bind() | btio/btio.c | 绑定本地 L2CAP 地址 |
| l2cap_connect() | btio/btio.c | 发起 L2CAP 连接 |
| l2cap_set() | btio/btio.c | 设置 L2CAP 通道参数 |
| set_l2opts() | btio/btio.c | 设置 BR/EDR L2CAP 选项 |
| set_le_imtu() | btio/btio.c | 设置 LE 接收 MTU |
| set_le_mode() | btio/btio.c | 设置 LE 通道模式 |
| bt_io_set() | btio/btio.c | 动态修改已建立通道的参数 |
| bt_io_get() | btio/btio.c | 查询已建立通道的参数 |
| sdp_connect() | lib/sdp_lib.h | 创建 SDP 会话 |
| sdp_process() | lib/sdp_lib.h | 处理 SDP 异步响应 |

11.2 内核关键函数

|-----------------------------|----------------------------|--------------------|
| 函数名 | 内核文件 | 功能描述 |
| l2cap_sock_bind() | net/bluetooth/l2cap_sock.c | 处理 bind 系统调用 |
| l2cap_sock_connect() | net/bluetooth/l2cap_sock.c | 处理 connect 系统调用 |
| l2cap_sock_listen() | net/bluetooth/l2cap_sock.c | 处理 listen 系统调用 |
| l2cap_sock_accept() | net/bluetooth/l2cap_sock.c | 处理 accept 系统调用 |
| l2cap_sock_sendmsg() | net/bluetooth/l2cap_sock.c | 处理 sendmsg 系统调用 |
| l2cap_sock_recvmsg() | net/bluetooth/l2cap_sock.c | 处理 recvmsg 系统调用 |
| l2cap_sock_setsockopt() | net/bluetooth/l2cap_sock.c | 处理 setsockopt 系统调用 |
| l2cap_sock_getsockopt() | net/bluetooth/l2cap_sock.c | 处理 getsockopt 系统调用 |
| l2cap_chan_send() | net/bluetooth/l2cap_core.c | 通道数据发送核心逻辑 |
| l2cap_sock_recv_cb() | net/bluetooth/l2cap_sock.c | 通道数据接收回调 |
| l2cap_recv_frame() | net/bluetooth/l2cap_core.c | L2CAP 帧解析与分发 |
| l2cap_sdu_recv_data() | net/bluetooth/l2cap_core.c | SDU 重组处理 |
| l2cap_ertm_send() | net/bluetooth/l2cap_ertm.c | ERTM 模式发送 |
| l2cap_le_send_data() | net/bluetooth/l2cap_le.c | LE 模式发送 |
| l2cap_chan_state_change() | net/bluetooth/l2cap_core.c | 通道状态变更处理 |

十二、数据结构映射关系

12.1 地址结构映射

暂时无法在飞书文档外展示此内容

12.2 选项结构映射

暂时无法在飞书文档外展示此内容

12.3 通道状态映射

暂时无法在飞书文档外展示此内容

12.4 错误码映射

暂时无法在飞书文档外展示此内容

十三、总结

BlueZ 与内核 L2CAP 的数据交互是 Linux 蓝牙子系统的核心数据通路,其架构设计体现了经典的 Unix 套接思想与蓝牙协议的深度融合。本文从架构、结构体、发送链路、接收链路、分片重组、流量控制、BLE 差异化、异常处理等多个维度进行了完整的源码解析。

13.1 核心要点回顾

  1. 分层架构清晰:BlueZ 通过 btio 抽象层统一 L2CAP/RFCOMM/SCO 接口,内核通过 Socket 层隔离协议实现细节,形成了良好的关注点分离。

  2. 数据路径明确:用户态数据经bt_io_connect() → l2cap_sock_sendmsg() → l2cap_chan_send() → l2cap_do_send() 路径发送,接收路径反向对应,每一步都有明确的职责边界。

  3. 分片重组透明:内核自动处理 SAR 位(Start/End/Continuation)的分片与重组,用户态只需关注 MTU 限制,无需手动分片。

  4. 流量控制分级:从基础模式(无流控)到 ERTM(窗口+重传),再到 LE Credit(信用计数),不同场景采用不同流控策略,平衡可靠性与实时性。

  5. BLE 差异化处理:通过 src_type 判断设备类型,BR/EDR 使用 SOL_L2CAP 级别选项,LE 使用 SOL_BLUETOOTH 级别选项,实现了双栈支持。

13.2 开发建议

  1. 优先使用 btio 封装:避免直接操作原始 L2CAP Socket,利用 BlueZ 已封装的 bt_io_connect()/bt_io_listen()接口,减少协议处理错误。

  2. 合理设置 MTU:根据应用场景选择合适的 MTU(默认 672 字节,可协商至更大值),在吞吐量与分片开销间取得平衡。

  3. 正确处理信用:LE Credit 模式下,接收方处理完数据后应及时补充信用,避免发送方因信用耗尽阻塞。

  4. 充分利用流控模式:根据业务需求选择合适的流控模式,如可靠传输用 ERTM,实时音视频用 Streaming,BLE 场景用 LE Flow Control。

  5. 完善错误处理:检查 connect()、send()、recv() 的返回值,处理 EAGAIN、EMSGSIZE、ETIMEDOUT 等错误码,实现健壮的连接管理。

13.3 后续研究方向

  • AMP(Alternate MAC/PHY):研究 802.11 AMP 控制器的 L2CAP 通道迁移

  • ECRED(Enhanced Credit):深入分析 BLE 多连接的信用管理机制

  • L2CAP 固定通道:探索 CID 0x0004(ATT)、0x0005(LE 信令)等固定通道的特殊处理

  • 内核优化:研究 L2CAP 驱动的内存管理、队列调度、并发处理等性能优化点

通过深入理解 BlueZ 与内核 L2CAP 的交互机制,开发者可以更好地定位问题、优化性能、扩展功能,为构建高质量的蓝牙应用奠定坚实基础。


参考文献

  • Linux Kernel Source Code: net/bluetooth/l2cap_core.c, net/bluetooth/l2cap_sock.c

  • BlueZ Source Code: btio/btio.c, lib/l2cap.h, monitor/l2cap.c

  • Bluetooth Specification Version 5.3: Volume 3, Part A (L2CAP)

  • RFC 2473: Packet Segment Reassembly

相关推荐
byte轻骑兵8 天前
【BlueZ 】Linux 内核蓝牙子系统入门:hci_core 模块与 BlueZ 的交互
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵9 天前
【BlueZ 】input 模块:蓝牙鼠标/键盘等输入设备的基础适配逻辑
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵11 天前
【BlueZ 】sdp 模块:服务发现协议的用户态实现基础
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵12 天前
【BlueZ】 log 模块:日志系统的实现与自定义日志输出配置
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵17 天前
【BlueZ 】util 模块:通用工具函数,源码中高频复用的基础组件
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵18 天前
【BlueZ 】hci 模块:用户态 HCI 层的核心封装与消息处理
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵23 天前
【BlueZ 】Adapter 模块:蓝牙适配器(主设备)的初始化与核心逻辑
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵1 个月前
【BlueZ 】用户态入口:main.c 核心函数与程序启动流程
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
byte轻骑兵1 个月前
【BlueZ 】蓝牙配对/绑定基础:BlueZ 中安全机制的入门级源码解析
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙