2. L2CAP信道类型与CID分配机制

L2CAP(Logical Link Control and Adaptation Protocol)位于蓝牙协议栈的基带层之上,负责向上层协议(如RFCOMM、ATT、SMP)提供逻辑信道抽象。根据连接方式与用途,L2CAP信道分为三大类:面向连接信道(COC)、无连接信道(CL)和固定信道。每类信道通过唯一的信道标识符(CID)进行寻址与区分。

核心要点:CID是L2CAP层实现多路复用的关键机制。每个信道在本地和远端各分配一个CID,构成(本地CID,远端CID)二元组,唯一标识一条逻辑信道。

2.1 信道类型总览

下表从连接建立方式、典型用途、CID范围三个维度对比三类信道:

信道类型 连接建立方式 典型用途 CID范围
面向连接信道(COC) 动态建立(L2CAP CONNECTION REQ/RSP) RFCOMM、BNEP、EATT 0x0040 – 0xFFFF(动态分配)
无连接信道(CL) 无需建立,直接发送数据报 广播数据、L2CAP组播 0x0002(固定CID)
固定信道 预分配,L2CAP层初始化时即存在 Signaling、SMP、ATT 0x0001 – 0x003F(固定CID)
开发提示:在Linux内核源码 net/bluetooth/l2cap_core.c 中,l2cap_chan_create() 函数负责为COC信道动态分配CID,分配算法采用线性扫描,从0x0040开始查找未使用的CID。

2.2 面向连接信道(COC)

COC是L2CAP层最常用的信道类型,提供可靠的、面向连接的数据传输服务。其生命周期包含四个阶段:建立、配置、数据传输、关闭。

2.2.1 COC建立流程

COC的建立通过L2CAP信令信道(CID 0x0001)交换控制帧完成。典型流程如下:

  1. 请求端发送 L2CAP_CONNECTION_REQ,携带PSM(Protocol/Service Multiplexer)和本地CID。
  2. 响应端收到后,分配本地CID,回复 L2CAP_CONNECTION_RSP,包含结果码和远端CID。
  3. 双方进入 CONFIG 阶段,交换 L2CAP_CONFIG_REQ/RSP,协商MTU、Flush Timeout等参数。
  4. 配置完成后,信道进入 OPEN 状态,开始数据传输。
性能陷阱:COC建立过程需要2次RTT(连接请求/响应 + 配置请求/响应)。在低延迟场景(如LE Audio)中,建议使用EATT(Enhanced ATT)的多信道COC模式,通过并行建立多个COC减少连接建立开销。

2.2.2 COC CID分配机制

COC的CID由L2CAP层动态分配,分配规则如下:

  • 起始值:0x0040(BR/EDR)或 0x0040(LE,但LE COC从0x0040开始,与BR/EDR共用范围)。
  • 分配方向:每个方向独立分配。发起端分配本地CID,响应端分配远端CID。
  • 回收复用:信道关闭后,CID标记为可用,后续新信道可复用该CID。
  • 范围限制:0x0040 – 0xFFFF,理论上最多支持 65472 个COC信道(实际受内存和控制器资源限制)。
COC信道建立与CID分配流程 发起端 响应端 ① CONNECTION_REQ (PSM, CID_L=0x0041) ② CONNECTION_RSP (Result=Success, CID_R=0x0042) ③ CONFIG_REQ (MTU=1024, FlushTO=0xFFFF) ④ CONFIG_RSP (Result=Success) OPEN (CID_L=0x0041) OPEN (CID_R=0x0042) 说明: 发起端分配本地CID=0x0041,响应端分配本地CID=0x0042。双方通过信令信道(CID=0x0001)交换控制帧。

2.3 无连接信道(CL)

无连接信道使用固定CID 0x0002,提供不可靠的、无连接的数据报服务。其特点包括:

  • 无需建立连接:发送方直接构造L2CAP帧,目标CID固定为0x0002。
  • 广播支持:可用于向多个设备发送广播数据(如蓝牙信标)。
  • 无确认机制:数据包可能丢失,上层协议需自行处理可靠性。
  • 协议数据单元(PDU)格式:包含协议/服务复用器(PSM)字段,用于区分上层协议。
应用场景:无连接信道常用于蓝牙低功耗(BLE)的广播数据和基于L2CAP的组播应用。在Linux中,通过 L2CAP_CONNINFO 套接字选项可查询CL信道状态。

2.4 固定信道

固定信道在L2CAP层初始化时即预分配,无需动态建立。其CID范围固定为 0x0001 – 0x003F,每个CID对应一个特定的协议或功能。

2.4.1 主要固定信道

CID 信道名称 用途 协议
0x0001 L2CAP Signaling L2CAP控制帧交换(连接、配置、断开) L2CAP
0x0002 无连接信道(CL) 无连接数据报 L2CAP
0x0003 AMP Manager AMP(Alternate MAC/PHY)管理 AMP
0x0004 BR/EDR Security Manager (SMP) 配对与密钥分发(BR/EDR) SMP
0x0005 LE Security Manager (SMP) 配对与密钥分发(LE) SMP
0x0006 ATT 属性协议(Attribute Protocol) ATT
0x0007 LE Signaling LE L2CAP控制帧 L2CAP
0x0008 LE Security Manager (SMP) - LE LE安全管理器 SMP
内核视角:在Linux内核中,固定信道的初始化在 l2cap_chan_create() 中通过 l2cap_fixed_chan_register() 完成。每个固定信道对应一个 struct l2cap_chan 实例,其 chan_type 字段设置为 L2CAP_CHAN_FIXED。

2.4.2 固定信道与COC的对比

对比维度 固定信道 COC
CID分配 预分配(0x0001 – 0x003F) 动态分配(0x0040 – 0xFFFF)
建立开销 无(初始化即存在) 需要连接/配置信令交换
可靠性 取决于底层(固定信道本身无重传) 支持重传与流控
典型延迟 低(无建立延迟) 中(2次RTT建立延迟)
适用场景 控制信令、安全协议、属性协议 数据流、文件传输、音频流

2.5 CID分配机制详解

CID是L2CAP层实现多路复用的核心标识符。每个L2CAP信道在本地和远端各有一个CID,构成(本地CID,远端CID)二元组,唯一标识一条逻辑信道。

2.5.1 CID空间划分

CID是一个16位无符号整数,其空间划分如下:

  • 0x0000:保留,未使用。
  • 0x0001 – 0x003F:固定信道CID,由蓝牙规范预定义。
  • 0x0040 – 0xFFFF:动态CID,用于COC信道,由L2CAP层动态分配。

2.5.2 动态CID分配算法

Linux内核中,动态CID分配采用线性扫描 + 位图管理策略:

/* l2cap_core.c - CID分配核心逻辑 */
static u16 l2cap_alloc_cid(struct l2cap_chan *chan)
{
    u16 cid;
    
    /* 从0x0040开始扫描 */
    for (cid = L2CAP_CID_DYN_START; cid < L2CAP_CID_DYN_END; cid++) {
        /* 检查CID是否已被使用 */
        if (!__l2cap_get_chan_by_scid(chan->conn, cid)) {
            chan->scid = cid;
            return cid;
        }
    }
    return 0; /* 分配失败 */
}
性能调优点:线性扫描算法在CID使用率高时(如同时存在数千个COC信道),分配延迟会线性增长。优化方案包括:
① 使用位图(bitmap)记录空闲CID,分配复杂度降为O(1)。
② 引入CID缓存池,预分配常用CID范围。
③ 在多信道EATT场景中,建议将CID分配与信道优先级关联,优先分配低CID值。

2.6 信道类型选择策略

在实际开发中,选择哪种信道类型取决于应用需求:

应用场景 推荐信道类型 理由
属性读写(GATT) 固定信道(ATT,CID=0x0006) 低延迟,无需建立连接
安全配对 固定信道(SMP,CID=0x0005/0x0008) 控制信令,固定CID保证可达
文件传输 COC 需要可靠传输和流控
音频流 COC(EATT多信道) 低延迟、多信道并行传输
广播数据 无连接信道(CL,CID=0x0002) 无需建立连接,支持多设备
L2CAP信道类型选择决策树 应用需求分析 需要可靠传输? 控制信令? 广播/组播? COC信道 固定信道 无连接信道 选择建议: 根据应用对可靠性、延迟和连接方式的需求,选择最合适的信道类型。混合使用多种信道类型可优化整体性能。

2.7 性能调优要点

调优总结:CID分配效率直接影响L2CAP层吞吐量。在多信道并发场景(如EATT同时使用5个COC信道),建议:
① 使用位图分配替代线性扫描。
② 将CID分配与NUMA节点绑定,减少跨内存访问延迟。
③ 在中断上下文中避免CID分配操作,使用工作队列异步处理。