【android bluetooth 协议分析 06】【l2cap详解 10】【通过avdtp连接流程,感受l2cap通道的生命周期变化】

本篇我们通过分析一个具体的实例,来直观感受一下 l2cap 中通道的 状态变化。

1. 环境描述:

  • 车机: a2dp sink
  • 手机: a2dp source
  • 场景: 手机主动 触发 连车机

声明一下: 分析的btsnoop 和 logcat 还有源码, 均是作为车机来分析的。

在这里插入图片描述

图中 总共分为 第一部分和第二部分。
本文的重点是分析 第一部分。 第二部分不再本篇分析之内,会将第二部分的分析单独分享在 avdtp 章节。

2. 案例分析

从第一部分看,可以分为一下6步:

  1. Rcvd Connection Request (AVDTP, SCID: 0x0041) : 车机侧接收到 手机发起的 avdtp 连接请求【手机 --> 车机】
  2. Sent Connection Response - Success (SCID: 0x0041, DCID: 0x0046): 车机向手机发送同意连接【手机 <-- 车机】
  3. Sent Configure Request (DCID: 0x0041): 车机发起配置请求 【手机 <-- 车机】
  4. Rcvd Configure Request (DCID: 0x0046):接收到手机的配置请求 【手机 --> 车机】
  5. Sent Configure Response - Success (SCID: 0x0041): 向手机发送配置应答 【手机 <-- 车机】
  6. Rcvd Configure Response - Success (SCID: 0x0046): 接收到手机的配置应答 【手机 --> 车机】

我们就依次来分析一下这6 步,在我们协议栈中是如何处理的。

上述几步都是发生在 l2cap 信令通道里面的。

  • CID: L2CAP Signaling Channel (0x0001)

所以调用路径基本是在

// system/stack/l2cap/l2c_main.cc
void l2c_rcv_acl_data(BT_HDR* p_msg) {

  // 信令通道基本都是调用 process_l2cap_cmd 来处理
  /* Send the data through the channel state machine */
  if (rcv_cid == L2CAP_SIGNALLING_CID) {
    process_l2cap_cmd(p_lcb, p, l2cap_len);
    osi_free(p_msg);
    return;
  }


}


static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
  tL2C_CONN_INFO con_info;

  /* if l2cap command received in CID 1 on top of an LE link, ignore this
   * command */
  if (p_lcb->transport == BT_TRANSPORT_LE) {
    LOG_INFO("Dropping data on CID 1 for LE link");
    return;
  }

  /* Reject the packet if it exceeds the default Signalling Channel MTU */
  bool pkt_size_rej = false;
  if (pkt_len > L2CAP_DEFAULT_MTU) {
    /* Core Spec requires a single response to the first command found in a
     * multi-command L2cap packet.  If only responses in the packet, then it
     * will be ignored. Here we simply mark the bad packet and decide which cmd
     * ID to reject later */
    pkt_size_rej = true;
    LOG_WARN("Signaling pkt_len=%d exceeds MTU size %d", pkt_len,
             L2CAP_DEFAULT_MTU);
  }

  uint8_t* p_next_cmd = p;
  uint8_t* p_pkt_end = p + pkt_len;

  tL2CAP_CFG_INFO cfg_info;
  memset(&cfg_info, 0, sizeof(cfg_info));

  /* An L2CAP packet may contain multiple commands */
  // 一个 l2cap 包中可能包含多个 命令, 所以这里 需要 while 循环遍历每一个 cmd.
  /*
  想象你是一个邮局的接信柜台:
	1.每个 L2CAP 信令包就像一沓装在一个信封里的指令信。

	2.你每次拆开信封(调用 process_l2cap_cmd),要一封一封读信(while 循环)。

	3.每封信的信头告诉你是什么业务(连接请求、配置、断开等)。

	4. 你交给不同科室处理(switch-case 分发)。

	5. 每个科室根据信的内容,更新内部状态(状态机驱动)。
  */
  while (true) {
    /* Smallest command is 4 bytes */
    p = p_next_cmd;
    if (p > (p_pkt_end - 4)) break;

    uint8_t cmd_code, id;
    uint16_t cmd_len;
    STREAM_TO_UINT8(cmd_code, p);
    STREAM_TO_UINT8(id, p);
    STREAM_TO_UINT16(cmd_len, p);

    if (cmd_len > BT_SMALL_BUFFER_SIZE) {
      LOG_WARN("Command size %u exceeds limit %d", cmd_len,
               BT_SMALL_BUFFER_SIZE);
      l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id, 0, 0);
      return;
    }

    /* Check command length does not exceed packet length */
    p_next_cmd = p + cmd_len;
    if (p_next_cmd > p_pkt_end) {
      LOG_WARN("cmd_len > pkt_len, pkt_len=%d, cmd_len=%d, code=%d", pkt_len,
               cmd_len, cmd_code);
      break;
    }

    LOG_DEBUG("cmd_code: %d, id:%d, cmd_len:%d", cmd_code, id, cmd_len);

    /* Bad L2CAP packet length, look for cmd to reject */
    if (pkt_size_rej) {
      /* If command found rejected it and we're done, otherwise keep looking */
      if (l2c_is_cmd_rejected(cmd_code, id, p_lcb)) {
        LOG_WARN("Rejected command %d due to bad packet length", cmd_code);
        return;
      } else {
        LOG_WARN("No need to reject command %d for bad packet len", cmd_code);
        continue; /* Look for next cmd/response in current packet */
      }
    }


    // 将提前到的 cmd 分发到对应分支处理
    switch (cmd_code) {
	  case L2CAP_CMD_REJECT:
		  ...
		  break;
	  case L2CAP_CMD_CONN_REQ:
		  ...
		  break;
      
	  case L2CAP_CMD_CONN_RSP:
		  ...
		  break;

      case L2CAP_CMD_CONFIG_REQ:
	      ...
	      break;

	  case L2CAP_CMD_CONFIG_RSP:
		  ...
		  break;

      case L2CAP_CMD_DISC_REQ:
	      ...
	      break;
      case L2CAP_CMD_DISC_RSP:
	      ...
	      break;

      case L2CAP_CMD_ECHO_REQ:
	      ...
	      break;

      case L2CAP_CMD_INFO_REQ:
	      ...
	      break;

      case L2CAP_CMD_INFO_RSP:
	      ...
	      break;


      default:
        LOG_WARN("Bad cmd code: %d", cmd_code);
        l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0,
                                  0);
        return;
    }
  }
}

  • 我们直接从 process_l2cap_cmd 函数开始分析。

1. 车机侧接收到 avdtp 连接请求

1. log 部分

1081	2025-04-24 15:56:22.504410	vivoMobi_91:b0:62 (cbx)	22:22:96:de:b1:39 (leo 8295 chan)	L2CAP	17	Rcvd Connection Request (AVDTP, SCID: 0x0041)


Frame 1081: 17 bytes on wire (136 bits), 17 bytes captured (136 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 8
    CID: L2CAP Signaling Channel (0x0001)
    Command: Connection Request
        Command Code: Connection Request (0x02)
        Command Identifier: 0x11
        Command Length: 4
        PSM: AVDTP (0x0019)
        Source CID: Dynamically Allocated Channel (0x0041)
    [Disconnect in frame: 0]

04-24 15:56:22.504630  6130  6190 I bt_l2c_main: packages/modules/Bluetooth/system/stack/l2cap/l2c_main.cc:310 process_l2cap_cmd: cmd_code: 2, id:17, cmd_len:4


04-24 15:56:22.504647  6130  6190 I l2c_utils: packages/modules/Bluetooth/system/stack/l2cap/l2c_utils.cc:1356 l2cu_allocate_ccb: is_dynamic = 1, cid 0x0000


04-24 15:56:22.504669  6130  6190 I bt_l2cap: packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: l2cu_enqueue_ccb CID: 0x0046  priority: 2


04-24 15:56:22.504765  6130  6190 I l2c_link: packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc:739 l2c_link_adjust_chnl_allocation: CID:0x0046 FCR Mode:0 Priority:2 TxDataRate:1 RxDataRate:1 Quota:200


04-24 15:56:22.504776  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_CLOSED [0], event=PEER_CONNECT_REQ [10]


04-24 15:56:22.504783  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:199 l2c_csm_closed: LCID: 0x0046  st: CLOSED  evt: PEER_CONNECT_REQ

04-24 15:56:22.504798  6130  6190 I bt_btm_sec: packages/modules/Bluetooth/system/stack/btm/btm_sec.cc:1826 btm_sec_l2cap_access_req: is_originator:0, psm=0x0019

04-24 15:56:22.504813  6130  6190 I bt_btm_sec: packages/modules/Bluetooth/system/stack/btm/btm_sec.cc:1608 btm_sec_l2cap_access_req_by_requirement: Checking l2cap access requirements peer:xx:xx:xx:xx:b0:62 security:0x1082 is_initiator:false

04-24 15:56:22.504822  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: btm_find_or_alloc_dev

04-24 15:56:22.504833  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: btm_sec_l2cap_access_req_by_requirement()  sm4:0x11, sec_flags:0x40be, security_required:0x1086 chk:1

04-24 15:56:22.504840  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: (SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x2, enc: x4

04-24 15:56:22.504846  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: btm_sec_check_upgrade()

04-24 15:56:22.504854  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: btm_sec_is_upgrade_possible() is_possible: 0 sec_flags: 0x40be

04-24 15:56:22.504862  6130  6190 I bt_btm_sec: packages/modules/Bluetooth/system/stack/btm/btm_sec.cc:4493 btm_sec_execute_procedure: security_required:0x1086 security_flags:0x40be security_state:BTM_SEC_STATE_IDLE[0]

04-24 15:56:22.504869  6130  6190 I bt_btm_sec: packages/modules/Bluetooth/system/stack/btm/btm_sec.cc:4591 btm_sec_execute_procedure: Encryption not required

# 安全模块检查通过
04-24 15:56:22.504876  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: Security Manager: access granted

04-24 15:56:22.504883  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: btm_sec_l2cap_access_req_by_requirement: p_dev_rec=0xb800004b18420208, clearing callback. old p_callback=0x7a3fcaf9cc

# 回调 l2c_link_sec_comp
04-24 15:56:22.504893  6130  6190 I l2c_link: packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc:284 l2c_link_sec_comp2: btm_status=BTM_SUCCESS, BD_ADDR=xx:xx:xx:xx:b0:62, transport=BT_TRANSPORT_BR_EDR

2. 源码分析

#define L2CAP_CMD_CONN_REQ 0x02
// process_l2cap_cmd 中对于  Connection Request 的处理
case L2CAP_CMD_CONN_REQ: {
        uint16_t rcid; // 变量 rcid,用于存储对端分配的 Channel ID(Remote CID)。
        if (p + 4 > p_next_cmd) {
          // 检查当前剩余数据是否足够解析 PSM(2 字节)+ Remote CID(2 字节),总共 4 字节。如果不足说明包不完整,记录警告并直接返回。
          LOG_WARN("Not enough data for L2CAP_CMD_CONN_REQ");
          return;
        }
        // 从 PDU 中解析出 PSM 和对端为本连接指定的 CID。这里的 con_info 是一个局部或上下文结构,用于传递连接相关信息。
        STREAM_TO_UINT16(con_info.psm, p); // con_info.psm = 0x0019:AVDTP
        STREAM_TO_UINT16(rcid, p); // rcid = 0x0041

		// 查找是否有注册过该 PSM 的服务(RCB = Registration Control Block),PSM 就像是协议层的端口号,只有注册了的 PSM 才能接受连接。
        tL2C_RCB* p_rcb = l2cu_find_rcb_by_psm(con_info.psm); // 我们在初始化就已经注册了 0x0019, 所以这里肯定是可以找到 p_rcb 的

        if (!p_rcb || con_info.psm == BT_PSM_ATT) {
         
        } else {

		// 尝试为此次连接请求分配一个新的 Channel Control Block(信道控制块),这代表一次独立的 L2CAP 信道。
        tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0); // p_ccb->chnl_state = CST_CLOSED

        // 初始化 CCB:
        p_ccb->remote_id = id; // : 当前信令命令的 ID,用于后续响应时对上。
        p_ccb->p_rcb = p_rcb; // 记录该连接使用的是哪个 PSM 的注册服务。
        p_ccb->remote_cid = rcid; // 对端分配的 Channel ID。
        p_ccb->connection_initiator = L2CAP_INITIATOR_REMOTE; // 标记连接是对端发起的

		// 启动状态机,处理 `L2CAP_CONNECT_REQ` 事件,进入连接建立流程,通常会发一个 Connection Response 作为回应。
        l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
        break;
      }

总结:

  1. 通过 l2cu_find_rcb_by_psm 传入 psm, 找到对应的服务。 这里找到了我们之前蓝牙初始化注册进 l2cap 的 avdtp 服务。
  2. 通过 l2cu_allocate_ccb 分配 一个 Channel Control Block ,并且将 该通道控制块的状态设置为 CST_CLOSED。 这是该通道的初始状态。
  3. 通过 l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info), 触发状态机处理 L2CEVT_L2CAP_CONNECT_REQ 事件。
1. l2cu_find_rcb_by_psm
  • 函数声明:定义一个名叫 l2cu_find_rcb_by_psm 的函数。
  • 输入参数psm,是一个 uint16_t 类型的数,表示要查找的 PSM (Protocol/Service Multiplexer)
  • 返回值:返回一个指向 tL2C_RCB 结构体的指针。如果找到匹配的 RCB(Registration Control Block),就返回它;如果找不到,就返回 NULL
tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t psm) {

  /*
  l2cb: 是 L2CAP 层的一个全局控制块(通常是 tL2C_CB 结构体),里面有一个 rcb_pool[]数组.
  rcb_pool[]:保存了所有注册到 L2CAP 层的 PSM 服务,属于服务注册表。
  */
  tL2C_RCB* p_rcb = &l2cb.rcb_pool[0]; // 准备从第一个注册表条目开始遍历。
  uint16_t xx;

  // 遍历到最大条目数 MAX_L2CAP_CLIENTS(即最大支持的 L2CAP 客户端数), 目前是 15
  for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
    /*
    p_rcb->in_use:这个 RCB 是否正在使用?(即注册了)
    p_rcb->psm == psm:这个 RCB 的 PSM 是否和我们要找的 psm相同?
    
    */
    if ((p_rcb->in_use) && (p_rcb->psm == psm)) return (p_rcb);
  }

  /* If here, no match found */
  return (NULL);
}

代码的作用:

项目内容
功能l2cb.rcb_pool[] 中查找一个 符合给定 PSM 的服务注册块(RCB)
输入一个 16 位的 psm
输出匹配到的 tL2C_RCB 指针,或者 NULL
遍历方式顺序遍历,从索引 0 开始直到 MAX_L2CAP_CLIENTS
匹配条件in_use == true 并且 psm == 输入 psm

应用场景:

  • 当 L2CAP 收到某个连接请求时(例如接收到 L2CAP_CONNECT_REQ),需要根据 psm 查找对应的服务。
  • 如果找不到,就要拒绝连接请求。

比如:

  • 手机请求通过 0x0019(AVDTP)连接车机。
  • 车机收到后,会调用 l2cu_find_rcb_by_psm(0x0019) 查找是否有注册的 AVCTP 服务处理它。
2. l2cu_allocate_ccb
  • 函数名字l2cu_allocate_ccb

  • 作用:从 CCB池(Channel Control Block池)里分配一个新的 CCB,建立一个逻辑信道。

  • 参数

    • p_lcb:指向对应物理链路(LCB)的指针,代表哪个设备的连接。
    • cid:如果是 0,表示系统自己分配;如果非 0,表示希望指定 cid 分配。
// system/stack/l2cap/l2c_utils.cc
tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) {
  LOG_INFO("is_dynamic = %d, cid 0x%04x", p_lcb != nullptr, cid); // 输出 p_lcb 是否为空(动态通道?)以及要分配的 CID。

  /*
	  l2cb.p_free_ccb_first:指向第一个空闲的 CCB。
	  如果为空,说明没有可用 CCB了,直接报错并返回 nullptr。
  */
  if (!l2cb.p_free_ccb_first) {
    LOG_ERROR("First free ccb is null for cid 0x%04x", cid);
    return nullptr;
  }
  tL2C_CCB* p_ccb; // 定义一个指针 p_ccb,用于保存即将分配的 CCB。

  // 判断 cid 是不是系统自动分配
  /* If a CID was passed in, use that, else take the first free one */
  if (cid == 0) {
    // 如果 cid==0,需要从自由链表(free list)拿第一个空闲的 CCB。
    p_ccb = l2cb.p_free_ccb_first; // 拿走第一个空闲的 CCB。
    l2cb.p_free_ccb_first = p_ccb->p_next_ccb; // 把空闲链表的头指针移动到下一个空闲节点。
  } else { // 用户指定 cid,
    // 如果 cid != 0,需要找出对应 cid 的 CCB
    tL2C_CCB* p_prev = nullptr;

    /*
	    1. L2CAP 的动态信道 CID 是从 L2CAP_BASE_APPL_CID 开始的(0x0040).
	    2. 数组是连续的,所以可以直接通过 (cid - BASE) 定位到对应的 CCB.
    */
    p_ccb = &l2cb.ccb_pool[cid - L2CAP_BASE_APPL_CID];

    // 从空闲链表里移除
    if (p_ccb == l2cb.p_free_ccb_first) {
      // 如果这块 CCB恰好是链表头,直接更新空闲链表头指针。
      l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
    } else {
      // 如果不是链表头,需要在链表中查找这个 CCB 的前一个节点
      for (p_prev = l2cb.p_free_ccb_first; p_prev != nullptr;
           p_prev = p_prev->p_next_ccb) {
        if (p_prev->p_next_ccb == p_ccb) {
          // 找到以后,把前一个节点的 next 指针指向 p_ccb->p_next_ccb,实现链表断开。
          p_prev->p_next_ccb = p_ccb->p_next_ccb;

          if (p_ccb == l2cb.p_free_ccb_last) {
            // 如果删的是链表最后一个,更新 p_free_ccb_last
            l2cb.p_free_ccb_last = p_prev;
          }

          break;
        }
      }
      if (p_prev == nullptr) {
        // 如果循环结束没找到,说明链表里没有这个 CCB,报错并返回空。
        LOG_ERROR("Could not find CCB for CID 0x%04x in the free list", cid);
        return nullptr;
      }
    }
  }

  // 初始化 CCB 内容
  p_ccb->p_next_ccb = p_ccb->p_prev_ccb = nullptr; // 断开当前 CCB 的链表关系(确保干净)

  p_ccb->in_use = true; // 标记:正在使用

  /* Get a CID for the connection */
  p_ccb->local_cid = L2CAP_BASE_APPL_CID + (uint16_t)(p_ccb - l2cb.ccb_pool); // 根据数组偏移重新计算本地 CID. 在当前场景下计算出来是 0x0046

 // 初始化 CCB 其他关联字段
  p_ccb->p_lcb = p_lcb; // 绑定 LCB
  p_ccb->p_rcb = nullptr; // 还没绑定 RCB(服务)

  /* Set priority then insert ccb into LCB queue (if we have an LCB) */
  p_ccb->ccb_priority = L2CAP_CHNL_PRIORITY_LOW; // 默认优先级是低优先级。

  // 将 CCB 插入到 LCB 的 CCB链表
  if (p_lcb) l2cu_enqueue_ccb(p_ccb); // 如果有对应物理连接,把 CCB 挂到物理连接(LCB)的 CCB链表里


  // 配置默认配置项
  /* Put in default values for configuration */
  memset(&p_ccb->our_cfg, 0, sizeof(tL2CAP_CFG_INFO)); // 清空本地配置和对端配置结构体
  memset(&p_ccb->peer_cfg, 0, sizeof(tL2CAP_CFG_INFO));

  // 配置默认参数(两边一样), 初始化 MTU、Flush超时时间、QOS参数等,都是默认值。
  /* Put in default values for local/peer configurations */
  p_ccb->our_cfg.flush_to = p_ccb->peer_cfg.flush_to = L2CAP_NO_AUTOMATIC_FLUSH;
  p_ccb->our_cfg.mtu = p_ccb->peer_cfg.mtu = L2CAP_DEFAULT_MTU;
  p_ccb->our_cfg.qos.service_type = p_ccb->peer_cfg.qos.service_type =
      L2CAP_DEFAULT_SERV_TYPE;
  p_ccb->our_cfg.qos.token_rate = p_ccb->peer_cfg.qos.token_rate =
      L2CAP_DEFAULT_TOKEN_RATE;
  p_ccb->our_cfg.qos.token_bucket_size = p_ccb->peer_cfg.qos.token_bucket_size =
      L2CAP_DEFAULT_BUCKET_SIZE;
  p_ccb->our_cfg.qos.peak_bandwidth = p_ccb->peer_cfg.qos.peak_bandwidth =
      L2CAP_DEFAULT_PEAK_BANDWIDTH;
  p_ccb->our_cfg.qos.latency = p_ccb->peer_cfg.qos.latency =
      L2CAP_DEFAULT_LATENCY;
  p_ccb->our_cfg.qos.delay_variation = p_ccb->peer_cfg.qos.delay_variation =
      L2CAP_DEFAULT_DELAY;

  // FCR(流控制/重传)部分初始化
  p_ccb->peer_cfg_already_rejected = false; // 流控配置默认没拒绝,还能尝试多次。
  p_ccb->fcr_cfg_tries = L2CAP_MAX_FCR_CFG_TRIES;

  // 创建ACK、监控重传定时器
  alarm_free(p_ccb->fcrb.ack_timer); // 之前如果存在老的,先释放掉。
  p_ccb->fcrb.ack_timer = alarm_new("l2c_fcrb.ack_timer"); // 创建ACK超时定时器

  /*  CSP408639 Fix: When L2CAP send amp move channel request or receive
    * L2CEVT_AMP_MOVE_REQ do following sequence. Send channel move
    * request -> Stop retrans/monitor timer -> Change channel state to
   * CST_AMP_MOVING. */
  alarm_free(p_ccb->fcrb.mon_retrans_timer);
  p_ccb->fcrb.mon_retrans_timer = alarm_new("l2c_fcrb.mon_retrans_timer"); // 创建监控重传定时器

  // 接收MTU、发送MPS设置, 最大接收SDU大小、最大传输单元大小。
  p_ccb->max_rx_mtu = BT_DEFAULT_BUFFER_SIZE -
                      (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
  p_ccb->tx_mps = BT_DEFAULT_BUFFER_SIZE - 32;

  // 创建四个   发送/接收队列, 四个队列分别保存发送缓存、重传缓存、选择重传缓存等。
  p_ccb->xmit_hold_q = fixed_queue_new(SIZE_MAX);
  p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
  p_ccb->fcrb.retrans_q = fixed_queue_new(SIZE_MAX);
  p_ccb->fcrb.waiting_for_ack_q = fixed_queue_new(SIZE_MAX);

  // 初始化其他小字段, 是否发生拥塞的标志、缓冲区配额。
  p_ccb->cong_sent = false;
  p_ccb->buff_quota = 2; /* This gets set after config */

  /* If CCB was reserved Config_Done can already have some value */
  if (cid == 0) { // 如果是系统分配 CID, 配置是否完成标志位。
    p_ccb->config_done = 0;
  } else {
    LOG_INFO("cid 0x%04x config_done:0x%x", cid, p_ccb->config_done);
  }

  // 初始化频道状态机状态
  p_ccb->chnl_state = CST_CLOSED; // 初始是 关闭状态
  p_ccb->flags = 0; // 各种 flag 置 0

  // 数据传输速率、是否可 flush
  // 默认都是低速率传输,不支持 flush,不支持 ECOC (Enhanced Credit-Based flow control)。
  p_ccb->tx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
  p_ccb->rx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;

  p_ccb->is_flushable = false;
  p_ccb->ecoc = false;

  // 创建 CCB 通用超时定时器
  alarm_free(p_ccb->l2c_ccb_timer);
  p_ccb->l2c_ccb_timer = alarm_new("l2c.l2c_ccb_timer"); // 超时时钟,用于各种 L2CAP 超时操作

  // 标记是否待移除, 初始不待删除
  p_ccb->pending_remove = false;

  // 调整 LCB 上信道的内存资源分配。
  l2c_link_adjust_chnl_allocation();

  // 更新 LCB 状态
  if (p_lcb != NULL) {
    // 如果 LCB 存在,说明本地客户端已经活跃了
    // once a dynamic channel is opened, timeouts become active
    p_lcb->with_active_local_clients = true;
  }

 // 最后返回新分配的 CCB
  return p_ccb;
}
项目内容
主要功能分配/初始化一个新的 L2CAP 信道控制块(CCB)
输入参数p_lcb (链路指针), cid (信道ID)
是否支持动态/指定CID支持
核心步骤从空闲链表拿一个 CCB,初始化默认参数,绑定LCB,配置超时定时器
失败情况空闲链表为空;或者指定cid找不到
返回新分配的 tL2C_CCB*
3. L2CEVT_L2CAP_CONNECT_REQ 事件处理
  L2CEVT_L2CAP_CONNECT_REQ = 10,     /* request */

l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
// system/stack/l2cap/l2c_csm.cc

void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {


  LOG_INFO("Entry chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);

  switch (p_ccb->chnl_state) {
    case CST_CLOSED:
      l2c_csm_closed(p_ccb, event, p_data);
      break;
    ...
  }
}


  • l2c_csm_closedL2CAP 信道状态机中处理 “CLOSED” 状态的函数。
  • p_ccb:当前信道的控制块(Channel Control Block)。
  • event:触发的事件(如:连接请求、断开等)。
  • p_data:附带数据,不同事件传递的内容不一样(这里只针对 CONNECT_REQ)。
static void l2c_csm_closed(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
  // 把 p_data 强转成连接信息结构体 tL2C_CONN_INFO*,虽然本段后面没实际用到 p_ci。
  tL2C_CONN_INFO* p_ci = (tL2C_CONN_INFO*)p_data;
  uint16_t local_cid = p_ccb->local_cid; // local_cid 保存本地 CID,后续打印方便
  tL2CA_DISCONNECT_IND_CB* disconnect_ind; // disconnect_ind 准备保存"断开连接回调函数"指针

  // 检查是否注册了对应的 RCB
  if (p_ccb->p_rcb == NULL) {
    /*
	    p_rcb(Registration Control Block)如果为空,表示这个信道没有注册应用者,那就直接打印错误日志并返回。
	    因为如果没人注册,就没必要继续处理了.
    */
    LOG_ERROR("LCID: 0x%04x  st: CLOSED  evt: %s p_rcb == NULL",
              p_ccb->local_cid, l2c_csm_get_event_name(event));
    return;
  }

  /*
	  取断开回调函数

	  从 RCB 结构中取出断开连接的回调函数(虽然本段代码中暂时没用到 disconnect_ind,留作未来其他分支扩展)。
  */
  disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;

  // 打印当前 LCID、状态(CLOSED)、事件名称。
  LOG_INFO("LCID: 0x%04x  st: CLOSED  evt: %s", p_ccb->local_cid,
            l2c_csm_get_event_name(event));

  switch (event) {

    // 处理我们刚设置的 L2CEVT_L2CAP_CONNECT_REQ 事件
    case L2CEVT_L2CAP_CONNECT_REQ:
       // 收到来自对端的连接请求时,如果当前状态是 CLOSED,要走建立连接流程。
      /* stop link timer to avoid race condition between A2MP, Security, and
       * L2CAP 
       * 
       * 取消 link 层定时器(避免 race condition):
       *      停止 link 级别的超时定时器,避免和 A2MP(Alternate MAC/PHY)、Security、L2CAP 同时抢占流程导致竞态问题。
       * */
          
      alarm_cancel(p_ccb->p_lcb->l2c_lcb_timer);

      // 判断是不是 BLE 连接
      if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
        // 如果是 BLE 连接(而不是传统 BR/EDR 蓝牙)。
        
        // BLE 下安全验证
        p_ccb->chnl_state = CST_TERM_W4_SEC_COMP; // 先切换状态机到 "等待安全完成"(W4_SEC_COMP)。


        // 发起 BLE 认证请求(比如加密/配对),要求远端满足安全条件。
        // 回调函数是 l2c_link_sec_comp2,附带 p_ccb
        tL2CAP_LE_RESULT_CODE result = l2ble_sec_access_req(
            p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, false,
            &l2c_link_sec_comp2, p_ccb);

        // 根据安全检查结果处理
        switch (result) {
          case L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION:
          case L2CAP_LE_RESULT_UNACCEPTABLE_PARAMETERS:
          case L2CAP_LE_RESULT_INVALID_PARAMETERS:
          case L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION:
          case L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE:
          case L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP:
            // 如果认证失败(各种错误原因),需要:
            l2cu_reject_ble_connection(p_ccb, p_ccb->remote_id, result); // 发送拒绝连接
            l2cu_release_ccb(p_ccb); // 释放掉分配的 p_ccb 控制块
            break;
          case L2CAP_LE_RESULT_CONN_OK:
          case L2CAP_LE_RESULT_NO_PSM:
          case L2CAP_LE_RESULT_NO_RESOURCES:
          case L2CAP_LE_RESULT_INVALID_SOURCE_CID:
          case L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED:
            // 如果是连接成功或者一些允许继续的情况,不做处理,后续等待回调
            break;
        }
      } else {
        // 传统 BR/EDR 连接下的处理

		// 尝试设置 Link Policy(Active Mode)
		// 把连接设置为 Active Mode(主动通讯模式),防止进入低功耗模式导致通信卡住。
        if (!BTM_SetLinkPolicyActiveMode(p_ccb->p_lcb->remote_bd_addr)) {
          // 如果设置失败,打印警告。
          LOG_WARN("Unable to set link policy active");
        }
        p_ccb->chnl_state = CST_TERM_W4_SEC_COMP; // 先切换状态机到 "等待安全完成"(W4_SEC_COMP)。
        // 发起传统蓝牙安全认证
        // 通过 BTM(蓝牙管理模块)发起安全检查(加密认证等)。
        // 成功返回 BTM_CMD_STARTED,代表认证正在进行。
        auto status = btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr,
                                               p_ccb->p_rcb->psm, false,
                                               &l2c_link_sec_comp, p_ccb);
        if (status == BTM_CMD_STARTED) {
          // 如果认证正在进行,回复"连接等待中"
          // started the security process, tell the peer to set a longer timer
          // 回复 Peer 一个连接挂起(Pending)消息,告诉对方“我在验证中,请稍等”。
          l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
        } else {
          // 如果不是正在进行,打印认证状态日志。
          LOG_INFO("Check security for psm 0x%04x, status %d",
                   p_ccb->p_rcb->psm, status);
        }
      }
      break;
    default:
      LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
  }

  // 最后统一打印一下当前信道状态和处理的事件,便于跟踪调试。
  LOG_INFO("Exit chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);
}
步骤作用
检查 RCB 是否存在确保有注册应用
处理 CONNECT_REQ根据是 BLE 还是 BR/EDR 分别走安全验证流程
设置 Link Active Mode保持连接活跃
BLE 下可能直接拒绝连接如果认证失败
传统蓝牙下可能发 Pending如果认证在进行
其他事件打印异常日志CLOSED 状态不应该接其他事件
4. 传统蓝牙安全认证
  • 定义了一个函数 btm_sec_l2cap_access_req

  • 功能:处理 L2CAP 在尝试建立连接时,询问安全模块(BTM,即 Bluetooth Manager)是否允许这条连接。

  • 输入参数

    • bd_addr:对端设备的蓝牙地址。

    • psm:L2CAP 层的协议/服务多路复用器编号(Protocol/Service Multiplexer,比如 AVDTP 是 0x0019)。

    • is_originator:表示发起方是本地设备(true)还是对端设备(false)。

    • p_callback:当需要异步处理(比如需要等待安全认证完成)时调用的回调函数。

    • p_ref_data:透传数据,回调时一起带回。

// system/stack/btm/btm_sec.cc

/*******************************************************************************
 *
 * Function         btm_sec_l2cap_access_req
 *
 * Description      This function is called by the L2CAP to grant permission to
 *                  establish L2CAP connection to or from the peer device.
 *
 * Parameters:      bd_addr       - Address of the peer device
 *                  psm           - L2CAP PSM
 *                  is_originator - true if protocol above L2CAP originates
 *                                  connection
 *                  p_callback    - Pointer to callback function called if
 *                                  this function returns PENDING after required
 *                                  procedures are complete. MUST NOT BE NULL.
 *
 * Returns          tBTM_STATUS
 *
 ******************************************************************************/
tBTM_STATUS btm_sec_l2cap_access_req(const RawAddress& bd_addr, uint16_t psm,
                                     bool is_originator,
                                     tBTM_SEC_CALLBACK* p_callback,
                                     void* p_ref_data) {

  /*
	  定义固定变量 transport,设置为 BR/EDR 传输类型(经典蓝牙)。
	  注:并没有处理 LE(低功耗蓝牙) 的情况,因为这是给 BR/EDR 传统连接用的。
  */
  // should check PSM range in LE connection oriented L2CAP connection
  constexpr tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;

  // 打日志,记录当前是不是发起方 (is_originator),以及用的是什么 psm
  LOG_INFO("is_originator:%d, psm=0x%04x", is_originator, psm);

  /*
		找出注册在安全模块中、匹配这个 psm 的服务记录(tBTM_SEC_SERV_REC 类型)。

		btm_sec_find_first_serv 会查一张内部表,看看这个 psm 是不是有应用程序注册过。

		如果找不到,说明这个 psm 未注册,不应该允许连接。
  */
  // Find the service record for the PSM
  tBTM_SEC_SERV_REC* p_serv_rec = btm_sec_find_first_serv(is_originator, psm);

  // If there is no application registered with this PSM do not allow connection
  if (!p_serv_rec) {
    /*
	    如果没有找到服务记录:

			打一条警告日志,说没有应用注册这个 psm。

			调用传进来的回调函数 p_callback,告知请求失败(BTM_MODE_UNSUPPORTED)。

			返回 BTM_MODE_UNSUPPORTED,表示不支持连接。
    */
    LOG_WARN("PSM: 0x%04x no application registered", psm);
    (*p_callback)(&bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
    return (BTM_MODE_UNSUPPORTED);
  }

  /* Services level0 by default have no security */
  if (psm == BT_PSM_SDP) {
    /*
	    特殊处理:如果是 SDP(Service Discovery Protocol),不需要任何安全认证。
	    直接调用回调函数,返回成功(BTM_SUCCESS_NO_SECURITY),并退出.
	    解释:SDP 只是用来查服务列表,不涉及数据传输或隐私,所以不要求加密认证。
    */
    LOG_INFO("No security required for SDP");
    (*p_callback)(&bd_addr, transport, p_ref_data, BTM_SUCCESS_NO_SECURITY);
    return (BTM_SUCCESS);
  }

  uint16_t security_required;
  if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
    /*
	    接下来,根据当前蓝牙堆栈的安全模式(btm_cb.security_mode),确定需要什么级别的安全措施。
		如果是 安全模式 4(Secure Connections Only,强制 LE Secure Connection 加密),就调整一下服务的 security_flags。
    */
    security_required = btm_sec_set_serv_level4_flags(
        p_serv_rec->security_flags, is_originator);
  } else {
    // 否则,直接使用服务本身注册时要求的安全标志。
    security_required = p_serv_rec->security_flags;
  }

  /*
	  最后,把地址、最终确定的 security_required、是否是发起方、回调函数、透传数据,都传给更细粒度的处理函数 btm_sec_l2cap_access_req_by_requirement。
  */

  /*
	  这个函数负责具体执行:
		检查配对情况,
    
		是否加密,
    
		是否认证,
    
		是否触发配对流程等。
  */
  return btm_sec_l2cap_access_req_by_requirement(
      bd_addr, security_required, is_originator, p_callback, p_ref_data);
}
  • 当 L2CAP 想建立连接时,调用这个函数,请求安全模块 BTM 检查是否允许建立连接。安全模块根据 PSM 类型和安全要求,决定直接通过、触发安全认证,还是直接拒绝。
安全等级介绍

// system/stack/include/btm_api_types.h
/* BTM_SEC security masks */
enum : uint16_t {
  /* Nothing required */
  BTM_SEC_NONE = 0x0000,
  /* Inbound call requires authentication */
  BTM_SEC_IN_AUTHENTICATE = 0x0002,
  /* Inbound call requires encryption */
  BTM_SEC_IN_ENCRYPT = 0x0004,
  /* Outbound call requires authentication */
  BTM_SEC_OUT_AUTHENTICATE = 0x0010,
  /* Outbound call requires encryption */
  BTM_SEC_OUT_ENCRYPT = 0x0020,
  /* Secure Connections Only Mode */
  BTM_SEC_MODE4_LEVEL4 = 0x0040,
  /* Need to switch connection to be central */
  BTM_SEC_FORCE_CENTRAL = 0x0100,
  /* Need to switch connection to be central */
  BTM_SEC_ATTEMPT_CENTRAL = 0x0200,
  /* Need to switch connection to be peripheral */
  BTM_SEC_FORCE_PERIPHERAL = 0x0400,
  /* Try to switch connection to be peripheral */
  BTM_SEC_ATTEMPT_PERIPHERAL = 0x0800,
  /* inbound Do man in the middle protection */
  BTM_SEC_IN_MITM = 0x1000,
  /* outbound Do man in the middle protection */
  BTM_SEC_OUT_MITM = 0x2000,
  /* enforce a minimum of 16 digit for sec mode 2 */
  BTM_SEC_IN_MIN_16_DIGIT_PIN = 0x4000,
};
宏定义含义适用方向常见使用场景
BTM_SEC_NONE (0x0000)不要求任何安全性入站+出站非敏感数据传输,比如一些开放设备广播、简单配对连接
BTM_SEC_IN_AUTHENTICATE (0x0002)入站连接需要身份验证(配对)入站(被连接方)设备作为服务器,要求连接进来的客户端至少完成配对,如蓝牙耳机接收连接
BTM_SEC_IN_ENCRYPT (0x0004)入站连接需要加密入站设备被连接时,要求链路加密,比如医疗设备传输隐私数据
BTM_SEC_OUT_AUTHENTICATE (0x0010)出站连接需要身份验证(配对)出站(发起连接方)手机主动连接智能手表,要求连接前认证对方身份
BTM_SEC_OUT_ENCRYPT (0x0020)出站连接需要加密出站手机主动连接蓝牙锁,要求链路加密保障通信安全
BTM_SEC_MODE4_LEVEL4 (0x0040)只允许 Secure Connections Only 模式连接(使用更强的 ECDH 算法)入站+出站高安全需求场景,如车载蓝牙连接手机时要求强加密,拒绝传统配对
BTM_SEC_FORCE_CENTRAL (0x0100)强制切换角色为 Central(主机)出站手机强制作为 Central 主动连接外围设备,比如蓝牙耳机
BTM_SEC_ATTEMPT_CENTRAL (0x0200)尝试切换为 Central(若失败也继续)出站优先作为 Central 连接,但失败不会终止连接,比如车机同时可以是 Peripheral 和 Central
BTM_SEC_FORCE_PERIPHERAL (0x0400)强制切换角色为 Peripheral(从机)入站设备必须作为 Peripheral 接受连接,例如体重秤作为从设备
BTM_SEC_ATTEMPT_PERIPHERAL (0x0800)尝试切换为 Peripheral入站优先作为 Peripheral,如果不行再考虑其它,比如耳机可以接收连接也可以发起
BTM_SEC_IN_MITM (0x1000)入站连接要求防中间人攻击(需要 MITM 保护的认证)入站接收连接时要求用户确认(比如 PIN 码、数字比较),提高安全性,如支付终端
BTM_SEC_OUT_MITM (0x2000)出站连接要求防中间人攻击出站主动发起连接时要求进行 MITM 保护认证,如安全支付用手机连接 POS 机
BTM_SEC_IN_MIN_16_DIGIT_PIN (0x4000)入站要求使用至少16位 PIN 码(传统配对方式)入站医疗设备或企业环境中要求高强度 PIN 码配对,防止弱 PIN 导致的安全风险

总结一下:

  • IN_* 的宏是指被连接时要求的安全措施
  • OUT_* 的宏是指主动发起连接时要求的安全措施
  • MODE4_LEVEL4 是专门为了**强制使用 LE Secure Connections (SC Only)**而设的,只有支持 ECDH 的设备才能连;
  • FORCEATTEMPT 是关于**角色切换(Central/Peripheral)**的,不是直接和安全有关;
  • MITMMIN_16_DIGIT_PIN 都是加强认证强度,防止暴力破解或中间人攻击。
#define BTM_SEC_OUT_LEVEL4_FLAGS                                       \
  (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_MITM | \
   BTM_SEC_MODE4_LEVEL4)

#define BTM_SEC_IN_LEVEL4_FLAGS                                     \
  (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_MITM | \
   BTM_SEC_MODE4_LEVEL4)

// system/stack/btm/btm_sec.cc
static uint16_t btm_sec_set_serv_level4_flags(uint16_t cur_security,
                                              bool is_originator) {
  uint16_t sec_level4_flags =
      is_originator ? BTM_SEC_OUT_LEVEL4_FLAGS : BTM_SEC_IN_LEVEL4_FLAGS;

  return cur_security | sec_level4_flags;
}
项目含义为什么需要备注
BTM_SEC_OUT_AUTHENTICATE(或 BTM_SEC_IN_AUTHENTICATE需要进行认证(完成配对过程,建立可信连接)Level 4 要求必须经过身份认证,不允许匿名连接需要交换身份信息(如密钥、证书)
BTM_SEC_OUT_ENCRYPT(或 BTM_SEC_IN_ENCRYPT需要链路加密(建立加密连接)Level 4 要求链路必须加密,防止数据被窃听通常在认证成功后自动加密
BTM_SEC_OUT_MITM(或 BTM_SEC_IN_MITM需要防中间人攻击的认证(MITM protection)Level 4 要求配对过程中必须防止中间人攻击常见方式:用户确认、数字比较、密钥输入
BTM_SEC_MODE4_LEVEL4要求使用 Secure Connections Only 模式(基于 ECDH 的强安全配对)这是 Level 4 的核心要求:只允许 LE Secure Connections (LESC),不接受传统配对(Legacy Pairing)需要设备双方都支持 Bluetooth 4.2+ 的 LESC 特性

BTM_SEC_OUT_LEVEL4_FLAGS
👉 表示当主动发起连接时,要强制要求:

  • 配对认证
  • 加密链路
  • 有中间人保护
  • 使用 LE Secure Connections Only 模式

BTM_SEC_IN_LEVEL4_FLAGS
👉 表示当被连接时,同样要强制要求:

  • 配对认证
  • 加密链路
  • 有中间人保护
  • 使用 LE Secure Connections Only 模式

这两个宏分别用于不同方向的连接,但要求完全一样,都是 Level 4。

什么是 Bluetooth Secure Connections Only Mode Level 4?

等级描述特点
Level 1不要求认证也不要求加密开放连接,最弱
Level 2不要求认证但要求加密加密但不认证
Level 3需要认证和加密,但可以是传统配对(Legacy Pairing)有一定防护
Level 4需要认证、加密,并且必须使用 LE Secure Connections(ECDH密钥交换)最高级别安全,防中间人攻击,适合敏感数据传输,比如支付、医疗、车载蓝牙连接

Level 4 是从 Bluetooth 4.2 标准开始要求的,需要设备硬件和软件都支持 Secure Connections (SC) 特性。

例子:

  • 车机连接手机(比如 BMW 蓝牙连接 iPhone)
    👉 必须使用 Secure Connections Only,避免有人中途劫持蓝牙连接控制车机
  • 手机连接支付 POS 机
    👉 必须要求认证、防中间人攻击、并且加密,保护交易安全
  • 智能门锁连接手机
    👉 不仅要认证,还要防止别人假冒设备或劫持指令

BTM_SEC_OUT_LEVEL4_FLAGSBTM_SEC_IN_LEVEL4_FLAGS出站/入站连接时强制应用 Secure Connections Only Level 4 安全要求的一组标志,确保连接经过认证、加密、防中间人攻击,并使用最新的安全机制(LESC)。

btm_sec_l2cap_access_req_by_requirement

这个函数是 L2CAP 建立连接时,蓝牙安全管理模块(BTM)用来检查是否满足安全要求 的关键步骤。
如果安全性(比如加密、认证)不够,就会触发配对/加密流程。

入参:

  • bd_addr:对方蓝牙设备地址。
  • security_required:希望达到的安全要求(比如必须认证、加密、Secure Connections等)。
  • is_originator:自己是发起方(true)还是接受方(false)。
  • p_callback:安全处理完成后的回调函数。
  • p_ref_data:回调时传递的用户自定义数据。
// system/stack/btm/btm_sec.cc

tBTM_STATUS btm_sec_l2cap_access_req_by_requirement(
    const RawAddress& bd_addr, uint16_t security_required, bool is_originator,
    tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) {
  // 记录当前请求的设备地址、请求的安全等级,以及我是发起方还是接受方。
  LOG_INFO(
      "Checking l2cap access requirements peer:%s security:0x%x "
      "is_initiator:%s",
      PRIVATE_ADDRESS(bd_addr), security_required,
      logbool(is_originator).c_str());


  // 1. 初始化变量
  tBTM_STATUS rc = BTM_SUCCESS; // 初始设为成功
  bool chk_acp_auth_done = false; // 标记是否需要检查认证状态
  /* should check PSM range in LE connection oriented L2CAP connection */
  constexpr tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; // 这里明确只针对 传统蓝牙(BR/EDR) 处理

  /* Find or get oldest record */
  // 2. 查找设备记录
  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bd_addr); // 找到或创建一条安全记录(每个连接的设备在 BTM 都有一份安全记录)。

  p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR); // 绑定 HCI 连接句柄。

  // 3. 被动连接且要求 Secure Connections Level 4 的校验
  if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4)) {
    /*
	    如果我是接受方,且要求Mode 4 Level 4(即 Secure Connections 的最高等级),那么:
		    1. 检查本地和对方是否支持 Secure Connections。
		    2. 如果任何一方不支持,拒绝连接。
		    3. 比如要求超高安全性的支付终端,只接受支持 Secure Connections 的设备
    */
    bool local_supports_sc =
        controller_get_interface()->supports_secure_connections();
    /* acceptor receives L2CAP Channel Connect Request for Secure Connections
     * Only service */
    if (!local_supports_sc || !p_dev_rec->SupportsSecureConnections()) {
      LOG_WARN(
          "Policy requires mode 4 level 4, but local_support_for_sc=%d, "
          "rmt_support_for_sc=%s, failing connection",
          local_supports_sc,
          logbool(p_dev_rec->SupportsSecureConnections()).c_str());
      if (p_callback) {
        (*p_callback)(&bd_addr, transport, (void*)p_ref_data,
                      BTM_MODE4_LEVEL4_NOT_SUPPORTED);
      }

      return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
    }
  }

  /* there are some devices (moto KRZR) which connects to several services at
   * the same time */
  /* we will process one after another */
  // 4. 处理并发连接情况(多个安全过程同时进行)
  if ((p_dev_rec->p_callback) ||
      (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)) {
      /*
	      如果当前设备已经在处理其他安全过程(比如 pairing).
	      或全局 pairing 状态不是空闲,就要排队。
      */
    LOG_INFO("security_flags:x%x, sec_flags:x%x", security_required,
              p_dev_rec->sec_flags);
    rc = BTM_CMD_STARTED; // 暂时返回命令已启动(不是立刻成功)。

    // 判断是否满足 legacy 安全模式的要求
    if ((btm_cb.security_mode == BTM_SEC_MODE_SERVICE) ||
        (BTM_SM4_KNOWN == p_dev_rec->sm4) ||
        (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
         (!btm_sec_is_upgrade_possible(p_dev_rec, is_originator)))) {
      /* legacy mode - local is legacy or local is lisbon/peer is legacy
       * or SM4 with no possibility of link key upgrade */

      /*
	      如果系统处于老版本(Legacy)安全模式或某些情况不能升级:
		      是否需要认证?是否需要加密?
			  如果需要 16位 PIN(强认证),也检查。

		  简单理解:  
			只要满足当前安全要求(加密/认证/16位PIN),就直接返回成功,否则需要等待后续处理。
      */
      if (is_originator) {
        if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
            ((((security_required & BTM_SEC_OUT_FLAGS) ==
               BTM_SEC_OUT_AUTHENTICATE) &&
              btm_dev_authenticated(p_dev_rec))) ||
            ((((security_required & BTM_SEC_OUT_FLAGS) ==
               (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) &&
              btm_dev_encrypted(p_dev_rec)))) {
          rc = BTM_SUCCESS;
        }
      } else {
        if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
            (((security_required & BTM_SEC_IN_FLAGS) ==
              BTM_SEC_IN_AUTHENTICATE) &&
             btm_dev_authenticated(p_dev_rec)) ||
            (((security_required & BTM_SEC_IN_FLAGS) ==
              (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) &&
             btm_dev_encrypted(p_dev_rec))) {
          // Check for 16 digits (or MITM)
          if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
              (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) ==
                BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
               btm_dev_16_digit_authenticated(p_dev_rec))) {
            rc = BTM_SUCCESS;
          }
        }
      }

      if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
          (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
        rc = BTM_CMD_STARTED;
      }

      if (rc == BTM_SUCCESS) {
        // 特别注意:临时配对的限制
        // 如果是临时绑定状态(例如没保存的配对信息),禁止访问高安全性服务。
        
        if (access_secure_service_from_temp_bond(p_dev_rec, is_originator, security_required)) {
          LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting");
          rc = BTM_FAILED_ON_SECURITY;
        }

        if (p_callback)
          (*p_callback)(&bd_addr, transport, (void*)p_ref_data, rc);
        return (rc);
      }
    }

    btm_cb.sec_req_pending = true;
    return (BTM_CMD_STARTED);
  }

  // 记录安全请求
  // 如果需要等待进一步配对、加密,保存相关信息:
  /* Save the security requirements in case a pairing is needed */
  p_dev_rec->required_security_flags_for_pairing = security_required;

  // 根据不同的安全模式,动态调整安全要求(比如一定要加密):
  /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */
  if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
      btm_cb.security_mode == BTM_SEC_MODE_SC) {
    if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
      if (is_originator) {
        /* SM4 to SM4 -> always encrypt */
        security_required |= BTM_SEC_OUT_ENCRYPT;
      } else /* acceptor */
      {
        /* SM4 to SM4: the acceptor needs to make sure the authentication is
         * already done */
        chk_acp_auth_done = true;
        /* SM4 to SM4 -> always encrypt */
        security_required |= BTM_SEC_IN_ENCRYPT;
      }
    } else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) { // 如果对方特性未知,先等待特性交换
      /* the remote features are not known yet */
      LOG_INFO(
          "Remote features have not yet been received sec_flags:0x%02x %s",
          p_dev_rec->sec_flags, (is_originator) ? "initiator" : "acceptor");

      p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;// 如果对方设备特性(比如是否支持 SC)还不知道,先标记 pending,稍后再处理。
      return (BTM_CMD_STARTED); 
    }
  }

  BTM_TRACE_DEBUG(
      "%s()  sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", __func__,
      p_dev_rec->sm4, p_dev_rec->sec_flags, security_required,
      chk_acp_auth_done);

  // 更新设备安全记录
  // 保存更新后的安全要求、回调、发起方信息:
  p_dev_rec->security_required = security_required;
  p_dev_rec->p_ref_data = p_ref_data;
  p_dev_rec->is_originator = is_originator;

  if (chk_acp_auth_done) {
    BTM_TRACE_DEBUG(
        "(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: "
        "x%x",
        (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED),
        (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED));
    /* SM4, but we do not know for sure which level of security we need.
     * as long as we have a link key, it's OK */
    if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||
        (0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) {
      rc = BTM_DELAY_CHECK;
      /*
      2046 may report HCI_Encryption_Change and L2C Connection Request out of
      sequence
      because of data path issues. Delay this disconnect a little bit
      */
      LOG_INFO(

          "%s peer should have initiated security process by now (SM4 to SM4)",
          __func__);
      p_dev_rec->p_callback = p_callback;
      p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
      (*p_callback)(&bd_addr, transport, p_ref_data, rc);

      return BTM_SUCCESS;
    }
  }

  p_dev_rec->p_callback = p_callback;

  // 进一步针对 Secure Connections 校验
  if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
    if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
        (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
      /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case
       */
      if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) {
        p_dev_rec->sm4 |= BTM_SM4_UPGRADE; // 如果要求 Mode4 Level4,但 link key 不够强(不是 P-256),就标记要升级:
      }
      p_dev_rec->sec_flags &=
          ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
            BTM_SEC_AUTHENTICATED);
      BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags);
      // 如果 link key 已经有但不够强,就清掉以前的信息,强制重新认证。
    } else {
      /* If we already have a link key to the connected peer, is it secure
       * enough? */
      btm_sec_check_upgrade(p_dev_rec, is_originator);
    }
  }

  // 启动安全处理流程,比如配对、加密协商等。
  rc = btm_sec_execute_procedure(p_dev_rec); // 在我们分析的这个案例中,在这里返回了 BTM_SUCCESS
  if (rc != BTM_CMD_STARTED) {
    // 如果不是 BTM_CMD_STARTED(比如失败了),立即回调上层。
    BTM_TRACE_DEBUG("%s: p_dev_rec=%p, clearing callback. old p_callback=%p",
                    __func__, p_dev_rec, p_dev_rec->p_callback);
    p_dev_rec->p_callback = NULL;
    (*p_callback)(&bd_addr, transport, p_dev_rec->p_ref_data, rc); // 在这里触发了 l2c_link_sec_comp 调用
  }

  // 最后根据执行结果返回。
  return (rc);
}

这个函数做的事情可以简单理解为:

步骤目的
找到设备记录了解设备当前的安全状态
检查本地和远端是否支持需要的特性比如 Secure Connections
判断现有链接是否已经足够安全是否需要加密/认证/重新配对
根据需要触发配对、加密启动安全过程或者直接回调成功

使用场景:

  • 你手机连耳机,如果耳机要求安全连接但你手机不支持,就直接拒绝。
  • 你手机和支付终端连,要求用 P-256 密钥,如果之前是旧版配对,就重新触发安全升级。
  • 多个蓝牙服务(比如耳机音频+电话)同时要求连接,按顺序一个个处理安全性。
btm_sec_execute_procedure
  • 传入参数是一个指向设备安全记录(p_dev_rec)的指针。
  • 返回类型是 tBTM_STATUS,代表操作结果,比如成功、失败、启动中等。

// system/stack/btm/btm_sec.cc

tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
  CHECK(p_dev_rec != nullptr);
  // 把当前设备需要的安全要求、已有的安全状态、以及安全过程状态打日志。
  // 方便调试:比如知道当前是否已经加密、认证了。
  LOG_INFO(
      "security_required:0x%x security_flags:0x%x security_state:%s[%hhu]",
      p_dev_rec->security_required, p_dev_rec->sec_flags,
      security_state_text(static_cast<tSECURITY_STATE>(p_dev_rec->sec_state))
          .c_str(),
      p_dev_rec->sec_state);

  // 1. 如果设备当前正在进行安全流程,不重复发起
  if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) {
    // 如果设备不是空闲状态(比如正在认证或加密中),就直接返回,说明流程已经在跑了。
    LOG_INFO(
        "Security state is idle indicating remote name request is outstanding");
    return (BTM_CMD_STARTED);
  }

  /* 
	  2. 如果设备名字未知,先发起远程名字请求
		  1. 为什么要名字?:很多安全策略需要知道对方设备名字(比如判断是已知设备还是陌生设备)。
		  2. 如果名字没拿到,先请求获取远程设备名字。
  */
  /* If any security is required, get the name first */
  if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) &&
      (p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) {
    LOG_INFO("Security Manager: Start get name");
    if (!btm_sec_start_get_name(p_dev_rec)) {
      LOG_WARN("Unable to start remote name request");
      return (BTM_NO_RESOURCES);
    }
    return (BTM_CMD_STARTED);
  }

  /* If connection is not authenticated and authentication is required */
  /* start authentication and return PENDING to the caller */
  // 3. 检查是否需要认证(配对)
  if (p_dev_rec->hci_handle != HCI_INVALID_HANDLE) {
    // 连接已经建立(hci_handle有效),进入检查阶段。
    bool start_auth = false;

    // Check link status of BR/EDR
    // 3.1 出站 or 入站认证需求判断
	    // 如果还没认证,就根据连接方向(自己发起or对方发起)判断要不要启动认证。
	    // 出站连接看 BTM_SEC_OUT_AUTHENTICATE
	    // 入站连接看 BTM_SEC_IN_AUTHENTICATE
    if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) {
      if (p_dev_rec->IsLocallyInitiated()) {
        if (p_dev_rec->security_required &
            (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) {
          LOG_INFO("Outgoing authentication/encryption Required");
          start_auth = true;
        }
      } else {
        if (p_dev_rec->security_required &
            (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) {
          LOG_INFO("Incoming authentication/encryption Required");
          start_auth = true;
        }
      }
    }

	// 3.2 检查是否需要16位PIN码
    if (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)) {
      /*
       * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
       * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
       * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
       * authenticated connections, hence we cannot distinguish here.
       */
      // 如果没有16位PIN码认证,但要求了 BTM_SEC_IN_MIN_16_DIGIT_PIN,则也要认证,这个通常用于防止弱PIN码攻击。
      if (!p_dev_rec->IsLocallyInitiated()) {
        if (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) {
          LOG_INFO("BTM_SEC_IN_MIN_16_DIGIT_PIN Required");
          start_auth = true;
        }
      }
    }

    // 3.3 如果需要认证,则启动认证流程
    if (start_auth) {
      LOG_INFO("Security Manager: Start authentication");

      /*
       * If we do have a link-key, but we end up here because we need an
       * upgrade, then clear the link-key known and authenticated flag before
       * restarting authentication.
       * WARNING: If the controller has link-key, it is optional and
       * recommended for the controller to send a Link_Key_Request.
       * In case we need an upgrade, the only alternative would be to delete
       * the existing link-key. That could lead to very bad user experience
       * or even IOP issues, if a reconnect causes a new connection that
       * requires an upgrade.
       */
      // 特殊情况:需要升级链接密钥
      if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) &&
          (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) &&
          (!p_dev_rec->IsLocallyInitiated() &&
            (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
            // 如果已经有密钥,但不满足更高安全要求(比如16位PIN),就清除旧的密钥标记,强制重做配对。这是为了安全升级。
        p_dev_rec->sec_flags &=
            ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
              BTM_SEC_AUTHENTICATED);
      }
	  // 真正启动认证
      btm_sec_wait_and_start_authentication(p_dev_rec); // 启动认证(配对)流程
      return (BTM_CMD_STARTED); // 返回正在进行中
    }
  }

  /* If connection is not encrypted and encryption is required */
  /* start encryption and return PENDING to the caller */
  // 4. 检查是否需要加密
  if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) &&
      ((p_dev_rec->IsLocallyInitiated() &&
        (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT)) ||
       (!p_dev_rec->IsLocallyInitiated() &&
        (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT))) &&
      (p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) {
      // 如果还没有加密,且上层要求了加密,则发起加密。
    BTM_TRACE_EVENT("Security Manager: Start encryption");

    btsnd_hcic_set_conn_encrypt(p_dev_rec->hci_handle, true); // 使用 HCI_Set_Connection_Encryption 指令。
    p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING; // 状态设为 ENCRYPTING,返回处理中
    return (BTM_CMD_STARTED);
  } else {
    LOG_INFO("Encryption not required");
  }

  // 5. 检查是否符合 Level 4 安全要求(SC Only)
  if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
      (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
      // 如果要求 Level 4,但连接密钥不是 P-256 生成的(老的密钥),直接失败。
      // 保护:防止旧的不安全链接偷渡。
    BTM_TRACE_EVENT(
        "%s: Security Manager: SC only service, but link key type is 0x%02x -",
        "security failure", __func__, p_dev_rec->link_key_type);
    return (BTM_FAILED_ON_SECURITY);
  }

  // 6. 检查是否是"临时绑定"设备在访问安全服务
  if (access_secure_service_from_temp_bond(p_dev_rec,
                                           p_dev_rec->IsLocallyInitiated(),
                                           p_dev_rec->security_required)) {
    LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting");
    // 如果是临时配对的(没正式保存密钥),而试图访问高安全服务,拒绝!
    return (BTM_FAILED_ON_SECURITY);
  }

  /* All required  security procedures already established */
  // 所有检查通过,清理安全请求标志
  p_dev_rec->security_required &=
      ~(BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
        BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT);

  BTM_TRACE_EVENT("Security Manager: access granted");
  // 安全检查通过,允许访问
  return (BTM_SUCCESS); // 返回成功,可以正式使用连接了。
}

这段 btm_sec_execute_procedure 做了这些事情:

  1. 看状态:是不是空闲?是不是已经有名字?是不是认证了?是不是加密了?

  2. 做必要动作:如果没有名字就拿名字,没认证就认证,没加密就加密。

  3. 符合安全级别要求吗:比如 Level 4,SC Only。

  4. 临时配对限制:临时配对不能访问高安全服务。

  5. 最终决定:可以访问(成功)或安全失败。

它是蓝牙设备连接过程中,真正落地执行安全控制策略的地方!

5. 总结

车机接收到 手机侧的 avdtp 连接请求后:

  1. 通过 l2cu_find_rcb_by_psm 传入 psm, 找到对应的服务。 这里找到了我们之前蓝牙初始化注册进 l2cap 的 avdtp 服务。
  2. 通过 l2cu_allocate_ccb 分配 一个 Channel Control Block ,并且将 该通道控制块的状态设置为 CST_CLOSED。 这是该通道的初始状态。
  3. 通过 l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info), 触发状态机处理 L2CEVT_L2CAP_CONNECT_REQ 事件; p_ccb->chnl_state = CST_TERM_W4_SEC_COMP; 将状态切换到 “等待安全完成”
  4. 本地开始对应的安全检查。
  5. 安全检查通过后,回调 l2c_link_sec_comp 函数。

2. 车机同意连接

1. 日志

1082	2025-04-24 15:56:22.505074	22:22:96:de:b1:39 (leo 8295 chan)	vivoMobi_91:b0:62 (cbx)	L2CAP	21	Sent Connection Response - Success (SCID: 0x0041, DCID: 0x0046)

Frame 1082: 21 bytes on wire (168 bits), 21 bytes captured (168 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 12
    CID: L2CAP Signaling Channel (0x0001)
    Command: Connection Response
        Command Code: Connection Response (0x03)
        Command Identifier: 0x11
        Command Length: 8
        Destination CID: Dynamically Allocated Channel (0x0046)
        Source CID: Dynamically Allocated Channel (0x0041)
        Result: Successful (0x0000)
        Status: No further information available (0x0000)

# 安全模块 检查完毕
04-24 15:56:22.504876  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: Security Manager: access granted

04-24 15:56:22.504883  6130  6190 I bt_btm  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: btm_sec_l2cap_access_req_by_requirement: p_dev_rec=0xb800004b18420208, clearing callback. old p_callback=0x7a3fcaf9cc

# 回调 l2c_link_sec_comp
04-24 15:56:22.504893  6130  6190 I l2c_link: packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc:284 l2c_link_sec_comp2: btm_status=BTM_SUCCESS, BD_ADDR=xx:xx:xx:xx:b0:62, transport=BT_TRANSPORT_BR_EDR
04-24 15:56:22.504901  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_TERM_W4_SEC_COMP [2], event=SECURITY_COMPLETE [7]

我们从 回调 l2c_link_sec_comp 开始梳理。

2. 源码分析

1. l2c_link_sec_comp2

l2c_link_sec_comp2 函数是 L2CAP 层在接收到 Security Manager(安全管理模块) 回调(Security Completion)之后,根据安全认证结果,继续推进连接流程的一个重要处理函数

参数:

  • p_bda:远端设备的蓝牙地址(谁的安全过程完成了)

  • transport:传输类型(BR/EDR 或 LE);这里没用到(标记 UNUSED_ATTR),但是为了接口统一保留

  • p_ref_data:指向发起安全检查请求时附带的指针,这里是指向对应的 L2CAP CCB (Channel Control Block)

  • status:安全检查(如鉴权、加密等)完成后的结果,比如 BTM_SUCCESSBTM_AUTH_FAILURE

// system/stack/l2cap/l2c_link.cc
void l2c_link_sec_comp(const RawAddress* p_bda,
                       UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data,
                       tBTM_STATUS status) {
  l2c_link_sec_comp2(*p_bda, transport, p_ref_data, status);
}

void l2c_link_sec_comp2(const RawAddress& p_bda,
                        UNUSED_ATTR tBT_TRANSPORT transport, void* p_ref_data,
                        tBTM_STATUS status) {
  tL2C_CONN_INFO ci; // 连接信息结构体,用于后续封装事件参数。
  tL2C_LCB* p_lcb; // Link Control Block,连接控制块,代表一条逻辑连接。
  tL2C_CCB* p_ccb; // Channel Control Block,信道控制块,代表一条具体的信道。
  tL2C_CCB* p_next_ccb; // Channel Control Block,信道控制块,代表一条具体的信道。

  // 打印日志,显示安全过程返回的状态(status)、设备地址(p_bda)、传输类型(BR/EDR or LE)。
  LOG_INFO("btm_status=%s, BD_ADDR=%s, transport=%s",
            btm_status_text(status).c_str(), PRIVATE_ADDRESS(p_bda),
            bt_transport_text(transport).c_str());

  // 特殊处理:
  if (status == BTM_SUCCESS_NO_SECURITY) {
    // 如果安全管理器返回 BTM_SUCCESS_NO_SECURITY(即“不需要安全”也算通过),直接将其视为普通的 BTM_SUCCESS
    // 统一后续处理逻辑
    status = BTM_SUCCESS;
  }

  // 把当前设备地址和安全检查结果打包到 ci,准备给后续状态机(l2c_csm_execute)使用
  /* Save the parameters */
  ci.status = status;
  ci.bd_addr = p_bda;

  // 根据设备地址和传输类型,找到对应的 连接控制块(LCB), LCB 代表当前设备和对方设备之间的“链接”
  p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, transport);

  /* If we don't have one, this is an error */
  if (!p_lcb) {
    // 如果找不到对应的 LCB
	    // 说明出现了异常,比如链接已经断了,但安全过程回调还到达了;
    LOG_WARN("L2CAP got sec_comp for unknown BD_ADDR");// 打印警告日志,直接返回,不做任何处理。
    return;
  }

  /* Match p_ccb with p_ref_data returned by sec manager */
  for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) {
    // 遍历当前连接(LCB)上挂着的所有 CCB(信道)。
    // 每一个 CCB 对应一个 L2CAP Channel(如 SDP、RFCOMM、AVCTP、A2DP 等通道)
    
    p_next_ccb = p_ccb->p_next_ccb;// p_next_ccb 保存下一个,防止遍历时链表出错。

    // 找到和回调参数 p_ref_data 匹配的 CCB。
    // 这里要求精确匹配指针,所以安全回调回来时能直接定位到是哪一个信道触发的安全流程。
    if (p_ccb == p_ref_data) {
      switch (status) {
        // 如果安全认证成功:
        case BTM_SUCCESS:
          // 触发 CCB 的状态机,发送 L2CEVT_SEC_COMP 事件,带着连接信息(ci)
          l2c_csm_execute(p_ccb, L2CEVT_SEC_COMP, &ci); // 
          break;

        case BTM_DELAY_CHECK:
          // 意思是要延迟一段时间再确认安全性(SM4 协议相关,旧版蓝牙的一种安全模式)
          /* start a timer - encryption change not received before L2CAP connect
           * req */
          // 启动一个定时器,等超时后重新处理。
          alarm_set_on_mloop(p_ccb->l2c_ccb_timer,
                             L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
                             l2c_ccb_timer_timeout, p_ccb);
          return; // 注意这里直接 return,不继续遍历

        default:
          // 其他情况(比如认证失败、加密失败等)
          // 触发 CCB 状态机,发送 L2CEVT_SEC_COMP_NEG 事件
          // 通常最终导致连接失败或断开
          l2c_csm_execute(p_ccb, L2CEVT_SEC_COMP_NEG, &ci);
          break;
      }
      break; // 处理完对应的 CCB后,直接退出循环,不再继续找其他信道
    }
  }
}
  • L2CAP在安全认证(比如加密或鉴权)完成后,根据认证结果,通知对应的信道状态机继续连接流程或者终止连接
    如果认证成功,就继续发起连接;如果失败,就中断连接。
  • 正常情况下, 会返回 BTM_SUCCESS
    • l2c_csm_execute(p_ccb, L2CEVT_SEC_COMP, &ci)

我们继续分析 l2c_csm_execute 的执行:

  • 此时 p_ccb->chnl_state = CST_TERM_W4_SEC_COMP
  • event = L2CEVT_SEC_COMP
04-24 15:56:22.504901  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_TERM_W4_SEC_COMP [2], event=SECURITY_COMPLETE [7]
void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
  if (p_ccb == nullptr) {
    LOG_WARN("CCB is null for event (%d)", event);
    return;
  }


  LOG_INFO("Entry chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);


  switch (p_ccb->chnl_state) {
  
  
	  case CST_TERM_W4_SEC_COMP:

		l2c_csm_term_w4_sec_comp(p_ccb, event, p_data);

	break;
  
  }

}
2. l2c_csm_term_w4_sec_comp

这段代码是 L2CAP CCB(Channel Control Block)状态机中,在"终止中等待安全认证完成"状态(TERM_W4_SEC_COMP)下处理各种事件的核心逻辑。

  • 函数定义:处理 L2CAP CCB 当前处于 CST_TERM_W4_SEC_COMP 状态时收到的各种事件。
  • p_ccb:对应的 Channel Control Block。
  • event:收到的事件类型(如连接请求、断开指示、安全认证完成等)。
  • p_data:事件附带的参数(类型根据不同事件不同)。

04-24 15:56:22.504907  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:481 l2c_csm_term_w4_sec_comp: LCID: 0x0046  st: TERM_W4_SEC_COMP  evt: SECURITY_COMPLETE

04-24 15:56:22.504913  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:497 l2c_csm_term_w4_sec_comp: Not waiting for info response, sending connect response

04-24 15:56:22.504922  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:503 l2c_csm_term_w4_sec_comp: Not LE connection, sending configure request

static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, tL2CEVT event,
                                     void* p_data) {
  // 打日志:记录当前 Local CID、本状态名、接收到的事件名,便于调试。
  LOG_INFO("LCID: 0x%04x  st: TERM_W4_SEC_COMP  evt: %s", p_ccb->local_cid,
            l2c_csm_get_event_name(event));

  switch (event) {
    case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
      // 链路断开通知(Link Layer)。链路断了,当前还在等待安全认证,就没必要继续了。
      /* Tell security manager to abort */
      btm_sec_abort_access_req(p_ccb->p_lcb->remote_bd_addr); // 通知 Security Manager 中止本次安全请求。
      l2cu_release_ccb(p_ccb); // 释放掉当前的 Channel Control Block(内存、资源等都回收)
      break;

    case L2CEVT_SEC_COMP:
      // 安全认证完成并且成功。
      p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP; // 把 Channel 状态转为 等待上层(L2CA)回应连接。

      /* Wait for the info resp in next state before sending connect ind (if
       * needed) */
      if (!p_ccb->p_lcb->w4_info_rsp) {
        // 如果 不需要等待 Info Response,直接继续连接流程
        // Info Response 是标准 L2CAP连接时用来了解对方特性的一步。
        LOG_INFO("Not waiting for info response, sending connect response");
        /* Don't need to get info from peer or already retrieved so continue */
        alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
                           l2c_ccb_timer_timeout, p_ccb); // 开启连接超时定时器

        if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
          // 如果是经典蓝牙(BR/EDR)连接:
          LOG_INFO("Not LE connection, sending configure request");
          l2c_csm_send_connect_rsp(p_ccb); // 发送 Connect Response
          l2c_csm_send_config_req(p_ccb); // 发送 Configuration Request(即开始配置通道参数)
        } else {
          // 如果是 BLE 连接(Bluetooth Low Energy)
          if (p_ccb->ecoc) { // 是 Enhanced Credit Based Connection (ECoC)
            // 使用 Credit-based 多通道连接(LE ECoC),一次可以连多个 CID
            /* Handle Credit Based Connection */
            LOG_INFO("Calling CreditBasedConnect_Ind_Cb(), num of cids: %d",
                      p_ccb->p_lcb->pending_ecoc_conn_cnt);
            
            std::vector<uint16_t> pending_cids;
            for (int i = 0; i < p_ccb->p_lcb->pending_ecoc_conn_cnt; i++) {
              // 把要建立连接的所有 pending CIDs 收集起来。
              uint16_t cid = p_ccb->p_lcb->pending_ecoc_connection_cids[i];
              if (cid != 0) pending_cids.push_back(cid);
            }

			// 通知上层 Profile,有多个 CID 等待建立。
            (*p_ccb->p_rcb->api.pL2CA_CreditBasedConnectInd_Cb)(
                p_ccb->p_lcb->remote_bd_addr, pending_cids, p_ccb->p_rcb->psm,
                p_ccb->peer_conn_cfg.mtu, p_ccb->remote_id);
          } else {
            // 否则是传统 BLE CoC, 使用传统 BLE CoC(Credit-Based Connection,单一通道)。
            /* Handle BLE CoC */
            LOG_INFO("Calling Connect_Ind_Cb(), CID: 0x%04x",
                      p_ccb->local_cid);
            l2c_csm_send_connect_rsp(p_ccb); // 回复 connect rsp。
            l2c_csm_indicate_connection_open(p_ccb); // 告知上层连接已经建立成功。
          }
        }
      } else { // 如果还在等 Info Response
        // 等待对方的 Info Response,比如设备特性等。
        // 注意到这里讲了蓝牙兼容性问题(Bluesoleil响应慢的问题)。
        /*
        ** L2CAP Connect Response will be sent out by 3 sec timer expiration
        ** because Bluesoleil doesn't respond to L2CAP Information Request.
        ** Bluesoleil seems to disconnect ACL link as failure case, because
        ** it takes too long (4~7secs) to get response.
        ** product version : Bluesoleil 2.1.1.0 EDR Release 060123
        ** stack version   : 05.04.11.20060119
        */

        /* Cancel ccb timer as security complete. waiting for w4_info_rsp
        ** once info rsp received, connection rsp timer will be started
        ** while sending connection ind to profiles
        */
        alarm_cancel(p_ccb->l2c_ccb_timer); // 取消之前的定时器。

        /* Waiting for the info resp, tell the peer to set a longer timer */
        LOG_INFO("Waiting for info response, sending connect pending");
        l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0); // 向对方回复 "连接还在处理中"(PENDING 状态),以防超时。
      }
      break;

    case L2CEVT_SEC_COMP_NEG:
      // 安全认证失败
      if (((tL2C_CONN_INFO*)p_data)->status == BTM_DELAY_CHECK) {
        // 特殊情况 BTM_DELAY_CHECK
        // 如果失败原因是 "需要延迟检查"(通常是SM4安全模式下的一种处理)。
        /* start a timer - encryption change not received before L2CAP connect
         * req */
        alarm_set_on_mloop(p_ccb->l2c_ccb_timer,
                           L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
                           l2c_ccb_timer_timeout, p_ccb); // 启动延迟定时器,后续补发认证。
      } else {// 其他认证失败情况
        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
          l2cu_reject_ble_connection(
              p_ccb, p_ccb->remote_id,
              L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION); // 如果是 BLE,发 BLE 的拒绝连接(错误码:认证失败)。
        else
          l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0); // 如果是 BR/EDR,发送 L2CAP 层的拒绝(SECURITY BLOCK)。
        l2cu_release_ccb(p_ccb); // 最后释放掉这个 CCB。
      }
      break;

    case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
    case L2CEVT_L2CAP_DATA:      /* Peer data packet rcvd    */
      // 有数据写入或收到数据,但当前正在断开中,丢弃数据并释放。
      osi_free(p_data);
      break;

    case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
      // 上层主动要求断开,直接释放通道。
      l2cu_release_ccb(p_ccb);
      break;

    case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
      // 对方发起断开。
      l2cu_send_peer_disc_rsp(p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid,
                              p_ccb->remote_cid); // 回复 disconnect response。

      /* Tell security manager to abort */
      btm_sec_abort_access_req(p_ccb->p_lcb->remote_bd_addr); //通知 Security Manager 取消认证

      l2cu_release_ccb(p_ccb); // 释放通道
      break;

    case L2CEVT_TIMEOUT:
      // 超时,比如认证超时了,主动断 ACL 链路。
      /* SM4 related. */
      acl_disconnect_from_handle(
          p_ccb->p_lcb->Handle(), HCI_ERR_AUTH_FAILURE,
          "stack::l2cap::l2c_csm::l2c_csm_term_w4_sec_comp Event timeout");
      break;

    case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
      // 安全模块通知可以重新发起安全请求,比如密钥刷新之类的。
      btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
                               false, &l2c_link_sec_comp, p_ccb); // 再次请求访问权限。
      break;

    default:
      // 遇到未处理的事件,打印错误日志。
      LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
  }
  LOG_INFO("Exit chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);
}

这段 l2c_csm_term_w4_sec_comp 的本质是:

  • 等待安全认证的时候,处理各种意外情况(断链、认证失败、认证成功、超时等)。
  • 保证:
    • 正常认证成功时,能继续连接流程;
    • 认证失败或断链时,能正确清理资源;
    • 防止泄露或死锁。

目前我们只需要关注 L2CEVT_SEC_COMP认证成功的即可

  • p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP : 把 Channel 状态转为 等待上层(L2CA)回应连接
  • l2c_csm_send_connect_rsp(p_ccb) :发送 Connect Response
  • l2c_csm_send_config_req(p_ccb) : 发送 Configuration Request(即开始配置通道参数)
3. l2c_csm_send_connect_rsp
04-24 15:56:22.504928  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_W4_L2CA_CONNECT_RSP [4], event=UPPER_LAYER_CONNECT_RSP [22]

04-24 15:56:22.504935  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:810 l2c_csm_w4_l2ca_connect_rsp: LCID: 0x0046  st: W4_L2CA_CON_RSP  evt: UPPER_LAYER_CONNECT_RSP

04-24 15:56:22.504941  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:870 l2c_csm_w4_l2ca_connect_rsp: Sending connection ok for BR_EDR
static void l2c_csm_send_connect_rsp(tL2C_CCB* p_ccb) {
  l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL); // 发送 L2CEVT_L2CA_CONNECT_RSP 事件
}

void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
  if (p_ccb == nullptr) {
    LOG_WARN("CCB is null for event (%d)", event);
    return;
  }


  LOG_INFO("Entry chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);


  switch (p_ccb->chnl_state) {
  
  
	  case CST_W4_L2CA_CONNECT_RSP:
      l2c_csm_w4_l2ca_connect_rsp(p_ccb, event, p_data);
      break;

	break;
  
  }

}
4. l2c_csm_w4_l2ca_connect_rsp
  • 专门处理 CCB(Channel Control Block)在等待上层回应连接请求(Connect Response)阶段时发生的各种事件

  • p_ccb:当前信道的控制块(Channel Control Block),管理一个逻辑信道(LCID)。

  • event:本次触发状态机的事件类型(枚举)。

  • p_data:附加数据(根据不同事件类型,结构体不同,比如 tL2C_CONN_INFO 等)。

// system/stack/l2cap/l2c_csm.cc
static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, tL2CEVT event,
                                        void* p_data) {
  tL2C_CONN_INFO* p_ci; // 指向连接信息,后面处理连接响应用。
  tL2C_LCB* p_lcb = p_ccb->p_lcb; // 指向对应的 LCB(Link Control Block,表示物理链接,例如 BR/EDR 或 LE 链路)。
  tL2CA_DISCONNECT_IND_CB* disconnect_ind =
      p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; // 上层注册的断开连接回调函数。
  uint16_t local_cid = p_ccb->local_cid; // 本地的 CID(Channel ID),用于标识逻辑信道

  LOG_INFO("LCID: 0x%04x  st: W4_L2CA_CON_RSP  evt: %s", p_ccb->local_cid,
            l2c_csm_get_event_name(event)); // 日志,打印当前 Local CID、状态(等待上层连接响应 W4_L2CA_CON_RSP)和触发事件名。

  switch (event) {
    // 1. 链路层断开通知
    case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
      // 链路断开了(可能是对端断开或者链路异常中断)。
      LOG_INFO("Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
                p_ccb->local_cid);
      l2cu_release_ccb(p_ccb); // 释放 p_ccb
      (*disconnect_ind)(local_cid, false); // 调用上层回调 disconnect_ind() 通知上层,不需要等待 Disconnect Confirm
      break;

    case L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP: //  CREDIT_BASED 连接回应
      // 收到上层对 Credit-Based 连接请求的响应(通常是 LE 上的信用基连接)。
      p_ci = (tL2C_CONN_INFO*)p_data;
      if ((p_lcb == nullptr) || (p_lcb && p_lcb->transport != BT_TRANSPORT_LE)) {// 检查链路是否存在且是 LE 链路。
        LOG_WARN("LE link doesn't exist");
        return;
      }
      l2cu_send_peer_credit_based_conn_res(p_ccb, p_ci->lcids,
                                           p_ci->l2cap_result); // 回复对端连接结果
      alarm_cancel(p_ccb->l2c_ccb_timer); // 停止 CCB 上的连接超时定时器

      // 遍历 pending_ecoc_connection_cids 数组,设置对应 CCB 的状态:
      for (int i = 0; i < p_lcb->pending_ecoc_conn_cnt; i++) {
        uint16_t cid = p_lcb->pending_ecoc_connection_cids[i];
        if (cid == 0) {
            LOG_WARN("pending_ecoc_connection_cids[%d] is %d", i, cid);
            continue;
        }

        tL2C_CCB* temp_p_ccb = l2cu_find_ccb_by_cid(p_lcb, cid);
        if (temp_p_ccb) {
          auto it = std::find(p_ci->lcids.begin(), p_ci->lcids.end(), cid);
          if (it != p_ci->lcids.end()) {
            // 成功的 CID,状态设为 CST_OPEN(已连接)
            temp_p_ccb->chnl_state = CST_OPEN;
          } else {
            l2cu_release_ccb(temp_p_ccb); // 失败的,释放 CCB。
          }
        }
        else {
            LOG_WARN("temp_p_ccb is NULL, pending_ecoc_connection_cids[%d] is %d", i, cid);
        }
      }
      // 清空 pending_ecoc_connection_cids 相关字段
      p_lcb->pending_ecoc_conn_cnt = 0;
      memset(p_lcb->pending_ecoc_connection_cids, 0,
             L2CAP_CREDIT_BASED_MAX_CIDS);

      break;
    // 经典连接回应
    case L2CEVT_L2CA_CONNECT_RSP:
      // 收到上层对传统连接请求(BR/EDR 或 LE)的响应。
      p_ci = (tL2C_CONN_INFO*)p_data;
      if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
        // LE (信用基连接)
        
        /* Result should be OK or Reject */
        if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK)) {
          // 如果上层同意(l2cap_result == L2CAP_CONN_OK),发送 OK 响应,状态设 CST_OPEN
          l2cble_credit_based_conn_res(p_ccb, L2CAP_CONN_OK);
          p_ccb->chnl_state = CST_OPEN;
          alarm_cancel(p_ccb->l2c_ccb_timer);
        } else {
          // 否则发送拒绝并释放 CCB。
          l2cble_credit_based_conn_res(p_ccb, p_ci->l2cap_result);
          l2cu_release_ccb(p_ccb);
        }
      } else {
        // BR/EDR (传统)
        /* Result should be OK or PENDING */
        if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK)) {
          // 上层同意(l2cap_result == OK),发送 OK,转到 CST_CONFIG(配置阶段),开启配置超时定时器。
          LOG_INFO("Sending connection ok for BR_EDR");
          l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_OK, 0);
          p_ccb->chnl_state = CST_CONFIG;
          alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
                             l2c_ccb_timer_timeout, p_ccb);
        } else {
          // 上层暂时挂起(Pending),发送 PENDING,开启扩展连接超时定时器。
          /* If pending, stay in same state and start extended timer */
          LOG_INFO("Sending connection result %d and status %d",
                    p_ci->l2cap_result, p_ci->l2cap_status);
          l2cu_send_peer_connect_rsp(p_ccb, p_ci->l2cap_result,
                                     p_ci->l2cap_status);
          alarm_set_on_mloop(p_ccb->l2c_ccb_timer,
                             L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
                             l2c_ccb_timer_timeout, p_ccb);
        }
      }
      break;

    case L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP_NEG:
      // 上层拒绝 Credit-Based 连接请求。
      p_ci = (tL2C_CONN_INFO*)p_data;
      alarm_cancel(p_ccb->l2c_ccb_timer); // 停掉定时器。
      if (p_lcb != nullptr) {
        if (p_lcb->transport == BT_TRANSPORT_LE) {
          // 如果链路存在且是 LE,发送拒绝回应
          l2cu_send_peer_credit_based_conn_res(p_ccb, p_ci->lcids,
                                               p_ci->l2cap_result);
        }
        for (int i = 0; i < p_lcb->pending_ecoc_conn_cnt; i++) {
          uint16_t cid = p_lcb->pending_ecoc_connection_cids[i];
          tL2C_CCB* temp_p_ccb = l2cu_find_ccb_by_cid(p_lcb, cid);
          l2cu_release_ccb(temp_p_ccb); // 释放所有 pending CCB。
        }

        p_lcb->pending_ecoc_conn_cnt = 0;
        memset(p_lcb->pending_ecoc_connection_cids, 0,
               L2CAP_CREDIT_BASED_MAX_CIDS);
      }
      break;
      
    case L2CEVT_L2CA_CONNECT_RSP_NEG:
      // 传统连接拒绝
      p_ci = (tL2C_CONN_INFO*)p_data;
      // 根据链路类型(LE or BR/EDR)发送拒绝。
      if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
        l2cble_credit_based_conn_res(p_ccb, p_ci->l2cap_result);
      else
        l2cu_send_peer_connect_rsp(p_ccb, p_ci->l2cap_result,
                                   p_ci->l2cap_status);
      l2cu_release_ccb(p_ccb); // 然后释放 CCB。
      break;

    // 超时事件
    case L2CEVT_TIMEOUT:
      // 在等待上层响应期间超时。
      l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_NO_PSM, 0); // 向对端回复 NO_PSM 错误(表明不支持)。
      LOG_INFO("Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
                p_ccb->local_cid);
      l2cu_release_ccb(p_ccb); // 释放 CCB。
      (*disconnect_ind)(local_cid, false); // 调用上层断开通知(不需要等待确认)
      break;

    // 数据相关事件
    case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
    case L2CEVT_L2CAP_DATA:      /* Peer data packet rcvd    */
      osi_free(p_data); // 在连接未完成阶段,不应该有数据收发,所以这里直接 free 掉。
      break;

    // 上层请求主动断开
    case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
      l2cu_send_peer_disc_req(p_ccb); // 发送 Disconnect Request 给对端, 状态机切换到 CST_W4_L2CAP_DISCONNECT_RSP(等待断开回应)。
      p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 开启断开超时定时器
      break;

    
    case L2CEVT_L2CAP_INFO_RSP: // 收到信息回应
      // 收到 L2CAP 信息响应(比如询问对端的特性)。
      /* We have feature info, so now give the upper layer connect IND */
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 重新开启连接超时定时器。
      LOG_INFO("Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);

      l2c_csm_send_connect_rsp(p_ccb);  // 调用 l2c_csm_send_connect_rsp(p_ccb) 给上层
      l2c_csm_send_config_req(p_ccb); // 调用 l2c_csm_send_config_req(p_ccb) 向对端发配置请求。
      break;
    default:
      // 收到不符合当前状态的事件,打错误日志。
      LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
  }
  LOG_INFO("Exit chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);
}
主要事件主要处理逻辑
链路断开释放 CCB,通知上层。
上层 Credit-based Connect 回复回复对端,调整信道状态。
上层传统 Connect 回复回复对端,切换到配置阶段或超时。
上层拒绝连接回复对端,释放资源。
超时回复对端错误,释放资源,通知上层。
数据写或收丢弃。
上层请求断开发送断开请求,等待响应。
收到信息回应继续完成连接建立。

我们这里只需要关注 L2CEVT_L2CA_CONNECT_RSP 事件的处理:

  • l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_OK, 0);
  • p_ccb->chnl_state = CST_CONFIG;
04-24 15:56:22.504928  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_W4_L2CA_CONNECT_RSP [4], event=UPPER_LAYER_CONNECT_RSP [22]

04-24 15:56:22.504935  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:810 l2c_csm_w4_l2ca_connect_rsp: LCID: 0x0046  st: W4_L2CA_CON_RSP  evt: UPPER_LAYER_CONNECT_RSP

04-24 15:56:22.504941  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:870 l2c_csm_w4_l2ca_connect_rsp: Sending connection ok for BR_EDR

这里就是 本节 车机回复同意连接 ok , 的地方。 我们可以对照 btsnoop 日志看一下。

1082	2025-04-24 15:56:22.505074	22:22:96:de:b1:39 (leo 8295 chan)	vivoMobi_91:b0:62 (cbx)	L2CAP	21	Sent Connection Response - Success (SCID: 0x0041, DCID: 0x0046)

Frame 1082: 21 bytes on wire (168 bits), 21 bytes captured (168 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 12
    CID: L2CAP Signaling Channel (0x0001)
    Command: Connection Response
        Command Code: Connection Response (0x03)
        Command Identifier: 0x11
        Command Length: 8
        Destination CID: Dynamically Allocated Channel (0x0046)
        Source CID: Dynamically Allocated Channel (0x0041)
        Result: Successful (0x0000)
        Status: No further information available (0x0000)

3. 车机发起配置请求

1083	2025-04-24 15:56:22.505308	22:22:96:de:b1:39 (leo 8295 chan)	vivoMobi_91:b0:62 (cbx)	L2CAP	21	Sent Configure Request (DCID: 0x0041)

Frame 1083: 21 bytes on wire (168 bits), 21 bytes captured (168 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 12
    CID: L2CAP Signaling Channel (0x0001)
    Command: Configure Request
        Command Code: Configure Request (0x04)
        Command Identifier: 0x0e
        Command Length: 8
        Destination CID: Dynamically Allocated Channel (0x0041)
        0000 0000 0000 000. = Reserved: 0x0000
        .... .... .... ...0 = Continuation Flag: False
        Option: MTU


在 l2c_csm_term_w4_sec_comp 函数的分析中:

  • p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP : 把 Channel 状态转为 等待上层(L2CA)回应连接
  • l2c_csm_send_connect_rsp(p_ccb) :发送 Connect Response
    • p_ccb->chnl_state = CST_CONFIG;
  • l2c_csm_send_config_req(p_ccb) : 发送 Configuration Request(即开始配置通道参数)

触发了 l2c_csm_send_config_req, 本节就来分析这个。

1. l2c_csm_send_config_req

static void l2c_csm_send_config_req(tL2C_CCB* p_ccb) {
  tL2CAP_CFG_INFO config{};
  config.mtu_present = true;
  config.mtu = p_ccb->p_rcb->my_mtu;
  p_ccb->max_rx_mtu = config.mtu;
  if (p_ccb->p_rcb->ertm_info.preferred_mode != L2CAP_FCR_BASIC_MODE) {
    config.fcr_present = true;
    config.fcr = kDefaultErtmOptions;
  }
  p_ccb->our_cfg = config;
  l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_REQ, &config); // 这里发送了 L2CEVT_L2CA_CONFIG_REQ 消息
}

void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
  if (p_ccb == nullptr) {
    LOG_WARN("CCB is null for event (%d)", event);
    return;
  }


  LOG_INFO("Entry chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);


  switch (p_ccb->chnl_state) {
  
  
	  case CST_CONFIG:
      l2c_csm_config(p_ccb, event, p_data);
      break;

	break;
  
  }

}
04-24 15:56:22.505097  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_CONFIG [5], event=UPPER_LAYER_CONFIG_REQ [24]

04-24 15:56:22.505104  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:975 l2c_csm_config: LCID: 0x0046  st: CONFIG  evt: UPPER_LAYER_CONFIG_REQ


04-24 15:56:22.505267  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:1235 l2c_csm_config: Exit chnl_state=CST_CONFIG [5], event=UPPER_LAYER_CONFIG_REQ [24]

2. l2c_csm_config

  • 信道已经进入"正在配置"阶段(CONFIG状态),不同的事件触发不同的逻辑处理。

static void l2c_csm_config(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
  tL2CAP_CFG_INFO* p_cfg = (tL2CAP_CFG_INFO*)p_data; // 把传进来的 p_data 强制转换成普通L2CAP配置结构体。
  tL2CA_DISCONNECT_IND_CB* disconnect_ind =
      p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; // 保存上层应用注册的“断开指示”回调函数指针,后面如果要通知上层断开连接,就直接用这个回调。
  uint16_t local_cid = p_ccb->local_cid; // 本地通道号保存一份副本,后续打印日志或传递参数方便。
  uint8_t cfg_result; // 用于保存peer配置请求处理后的结果,比如"成功"、"需要断开"、"需要重新配置"。
  tL2C_LCB* p_lcb = p_ccb->p_lcb; // 链接控制块(LCB),描述物理连接(ACL link)状态。
  tL2C_CCB* temp_p_ccb; // 临时的CCB指针,目前还没用到。
  tL2CAP_LE_CFG_INFO* p_le_cfg = (tL2CAP_LE_CFG_INFO*)p_data; // 如果是LE credit-based flow,会用到这个类型(区别于经典的L2CAP)。 处理LE Credit-Based的Reconfig消息

  LOG_INFO("LCID: 0x%04x  st: CONFIG  evt: %s", p_ccb->local_cid,
            l2c_csm_get_event_name(event)); // 打印出当前信道ID、当前状态(CONFIG)、接收到的事件名。

  switch (event) {
    case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
      // 链路层提示说物理链路断开了(ACL link down了)。 比如手机蓝牙突然关闭,车机收到链路断开的通知,就走这里
      LOG_INFO("Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
                p_ccb->local_cid);
      l2cu_release_ccb(p_ccb); // 释放CCB(信道控制块),因为连接没了;
      (*disconnect_ind)(local_cid, false); // 通知上层连接断开,参数 false 表示“不需要上层回复Confirm”。
      break;

    case L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_REQ:
      // 接收到Peer设备发来的LE Credit-Based重配置请求。比如耳机重协商MTU大小时
      /* For ecoc reconfig is handled below in l2c_ble. In case of success
       * let us notify upper layer about the reconfig
       */
      LOG_INFO("Calling LeReconfigCompleted_Cb(), CID: 0x%04x",
                p_ccb->local_cid);
      // 调用上层注册的Reconfig完成回调,告诉上层“Peer发起了重配置,处理结果是成功的”。
      (*p_ccb->p_rcb->api.pL2CA_CreditBasedReconfigCompleted_Cb)(
          p_lcb->remote_bd_addr, p_ccb->local_cid, false, p_le_cfg);
      break;
    case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request   */
      // 对端发来配置请求
      // 调用底层函数解析对端发来的配置请求内容。
      cfg_result = l2cu_process_peer_cfg_req(p_ccb, p_cfg);
      if (cfg_result == L2CAP_PEER_CFG_OK) { // 对端配置没问题。
        LOG_INFO("Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
                  p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
        l2c_csm_send_config_rsp_ok(p_ccb); // 发送Config Response(OK)给对端。
        if (p_ccb->config_done & OB_CFG_DONE) { // 如果自己也已经完成对对方的配置(即 OB_CFG_DONE),检查是否能进入 OPEN 状态
          if (p_ccb->remote_config_rsp_result == L2CAP_CFG_OK) {
            l2c_csm_indicate_connection_open(p_ccb); // 如果对端返回OK,那就打开连接;
          } else { // 否则如果我是发起方,本地上报错误。
            if (p_ccb->connection_initiator == L2CAP_INITIATOR_LOCAL) {
              (*p_ccb->p_rcb->api.pL2CA_Error_Cb)(p_ccb->local_cid,
                                                  L2CAP_CFG_FAILED_NO_REASON);
              bluetooth::shim::CountCounterMetrics(
                  android::bluetooth::CodePathCounterKeyEnum::
                      L2CAP_CONFIG_REQ_FAILURE,
                  1);
            }
          }
        }
      } else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT) { // 配置严重不兼容,需要断开
        /* Disconnect if channels are incompatible */
        LOG_INFO("incompatible configurations disconnect");
        l2cu_disconnect_chnl(p_ccb); //断开连接。
      } else /* Return error to peer so it can renegotiate if possible */
      { // 配置部分不兼容,需要协商:
        LOG_INFO("incompatible configurations trying reconfig");
        l2cu_send_peer_config_rsp(p_ccb, p_cfg); // 发送配置响应,表示部分参数不接受,等对端重新发新的配置。
      }
      break;

    case L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_RSP:
      // 收到 BLE Credit-Based 连接重新配置的响应。

      // 更新状态:配置完成,连接状态改为 OPEN,取消超时定时器。
      p_ccb->config_done |= OB_CFG_DONE;
      p_ccb->config_done |= RECONFIG_FLAG;
      p_ccb->chnl_state = CST_OPEN;
      alarm_cancel(p_ccb->l2c_ccb_timer);

      LOG_INFO("Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid);

      // 通知上层,Credit-Based重配置成功完成(`true` 表示成功)。
      p_ccb->p_rcb->api.pL2CA_CreditBasedReconfigCompleted_Cb(
          p_lcb->remote_bd_addr, p_ccb->local_cid, true, p_le_cfg);

      break;
    case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response  */
      // 对端发来了配置响应
      l2cu_process_peer_cfg_rsp(p_ccb, p_cfg); // 处理对端的配置响应,把对端配置更新到本地控制块 p_ccb->peer_cfg

      /* TBD: When config options grow beyong minimum MTU (48 bytes)
       *      logic needs to be added to handle responses with
       *      continuation bit set in flags field.
       *       1. Send additional config request out until C-bit is cleared in
       * response
       */
      p_ccb->config_done |= OB_CFG_DONE; // 标记自己发出去的配置已经完成了,OB_CFG_DONE(OutBound Config Done)。

      if (p_ccb->config_done & IB_CFG_DONE) { // 如果对端的配置也完成了(InBound Config Done),说明双方配置都搞定了,可以考虑继续后续操作。
        /* Verify two sides are in compatible modes before continuing */
        if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
          // 检查自己和对端的FCR模式(Flow Control and Retransmission mode,比如 Basic/ERTM/Streaming)是否一致。 如果不一致,无法通信,需要断开
          
          l2cu_send_peer_disc_req(p_ccb); // 发送 Disconnect Request 给对方。
          LOG_WARN(
              "Calling Disconnect_Ind_Cb(Incompatible CFG), CID: "
              "0x%04x  No Conf Needed",
              p_ccb->local_cid);
          l2cu_release_ccb(p_ccb); // 释放 CCB 资源,通知上层断开连接(false 表示无须上层回复)。
          (*disconnect_ind)(local_cid, false);
          break;
        }
        // 如果配置兼容:
        p_ccb->config_done |= RECONFIG_FLAG; // 标记为已经重新配置(即配置完成后还可以后续改配)。
        p_ccb->chnl_state = CST_OPEN; // 把信道状态切换为 CST_OPEN,进入数据传输阶段。
        l2c_link_adjust_chnl_allocation(); // 调整物理链路资源分配。
        alarm_cancel(p_ccb->l2c_ccb_timer); // 取消配置超时定时器

        /* If using eRTM and waiting for an ACK, restart the ACK timer */
        if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb); // 如果在用增强模式(eRTM)且在等ACK包,则重启ACK定时器

        /*
         ** check p_ccb->our_cfg.fcr.mon_tout and
         *p_ccb->our_cfg.fcr.rtrans_tout
         ** we may set them to zero when sending config request during
         *renegotiation
         */
        if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) &&
            ((p_ccb->our_cfg.fcr.mon_tout == 0) ||
             (p_ccb->our_cfg.fcr.rtrans_tout))) {
             // 如果使用 eRTM 且 monitor timeout / retransmission timeout 不合理(=0),调整一下参数。
          l2c_fcr_adj_monitor_retran_timeout(p_ccb);
        }

        /* See if we can forward anything on the hold queue */
        if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
          // 检查有没有挂起的待发数据,有的话现在可以发了!
          l2c_link_check_send_pkts(p_ccb->p_lcb, 0, NULL);
        }
      }

      LOG_INFO("Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid); // 打日志,表明调用了配置完成回调
      p_ccb->remote_config_rsp_result = p_cfg->result; // 记录对端回复的配置结果(比如成功/失败码)。
      if (p_ccb->config_done & IB_CFG_DONE) {
        l2c_csm_indicate_connection_open(p_ccb); // 如果对端配置也完成,通知上层连接正式建立
      }
      break;

    case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer config error rsp */
    // 对端配置失败回复
                                      /* Disable the Timer */
      alarm_cancel(p_ccb->l2c_ccb_timer); // 停掉配置超时定时器。

      /* If failure was channel mode try to renegotiate */
      if (!l2c_fcr_renegotiate_chan(p_ccb, p_cfg)) { // 如果不能重新协商频道(比如因为模式不兼容),执行失败处理
        LOG_INFO("Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d",
                  p_ccb->local_cid, p_cfg->result);
        if (p_ccb->connection_initiator == L2CAP_INITIATOR_LOCAL) {
          // 如果是本地发起连接的角色,通知上层出错
          (*p_ccb->p_rcb->api.pL2CA_Error_Cb)(p_ccb->local_cid,
                                              L2CAP_CFG_FAILED_NO_REASON);
          bluetooth::shim::CountCounterMetrics(
              android::bluetooth::CodePathCounterKeyEnum::L2CAP_CONFIG_RSP_NEG,
              1);
        }
      }
      break;

    // 对端主动断开请求
    case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 设置断开流程的超时器
      p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP; // 切换到等待上层应用回复 L2CA_DisconnectRsp 的状态。
      LOG_INFO("Calling Disconnect_Ind_Cb(), CID: 0x%04x  Conf Needed",
                p_ccb->local_cid);
      (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, true); // 通知上层:对端请求断开连接(需要应用层回复)。
      l2c_csm_send_disconnect_rsp(p_ccb); // 同时主动发出 Disconnect Response。
      break;

    case L2CEVT_L2CA_CREDIT_BASED_RECONFIG_REQ:
      // 本地发起credit-based重新配置请求
      l2cu_send_credit_based_reconfig_req(p_ccb, (tL2CAP_LE_CFG_INFO*)p_data); // 发出 Credit Based Channel 的 Reconfiguration Request
      
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 设置 Reconfig 超时定时器。
      break;
    case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req   */
      // 本地应用层发来配置请求


      l2cu_process_our_cfg_req(p_ccb, p_cfg); // 处理自己配置请求内容,发给对端。
      l2cu_send_peer_config_req(p_ccb, p_cfg);
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 设置配置超时定时器。
      break;

    case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp   */
      // 本地应用层收到对端的配置响应
      
      l2cu_process_our_cfg_rsp(p_ccb, p_cfg); // 处理对端返回的响应并标记 IB_CFG_DONE。

      p_ccb->config_done |= IB_CFG_DONE;

      // 后续逻辑跟前面的 CONFIG_RSP 类似,不再赘述。
      if (p_ccb->config_done & OB_CFG_DONE) {
        /* Verify two sides are in compatible modes before continuing */
        if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
          l2cu_send_peer_disc_req(p_ccb);
          LOG_WARN(
              "Calling Disconnect_Ind_Cb(Incompatible CFG), CID: "
              "0x%04x  No Conf Needed",
              p_ccb->local_cid);
          l2cu_release_ccb(p_ccb);
          (*disconnect_ind)(local_cid, false);
          break;
        }

        p_ccb->config_done |= RECONFIG_FLAG;
        p_ccb->chnl_state = CST_OPEN;
        l2c_link_adjust_chnl_allocation();
        alarm_cancel(p_ccb->l2c_ccb_timer);
      }

      l2cu_send_peer_config_rsp(p_ccb, p_cfg);

      /* If using eRTM and waiting for an ACK, restart the ACK timer */
      if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb);

      /* See if we can forward anything on the hold queue */
      if ((p_ccb->chnl_state == CST_OPEN) &&
          (!fixed_queue_is_empty(p_ccb->xmit_hold_q))) {
        l2c_link_check_send_pkts(p_ccb->p_lcb, 0, NULL);
      }
      break;

    case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
      // 上层要求断开连接

	  // 发送 Disconnect Request,切换到等待响应状态。
      l2cu_send_peer_disc_req(p_ccb);
      p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 设置断开超时器。
      break;

    case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd    */
      // 收到对端的数据包
      
      LOG_INFO("Calling DataInd_Cb(), CID: 0x%04x", p_ccb->local_cid);
      // 判断是否是固定信道:
      if (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
          p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL) {
        if (p_ccb->local_cid < L2CAP_BASE_APPL_CID) {
          // 如果是且注册了固定信道的回调,则直接调用。
          if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
                  .pL2CA_FixedData_Cb != nullptr) {
            p_ccb->metrics.rx(static_cast<BT_HDR*>(p_data)->len);
            (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
                  .pL2CA_FixedData_Cb)(p_ccb->local_cid,
                                       p_ccb->p_lcb->remote_bd_addr,
                                       (BT_HDR*)p_data);
          } else {
            if (p_data != nullptr) osi_free_and_reset(&p_data);
          }
          break;
        }
      }
      // 否则调用普通动态信道的回调 pL2CA_DataInd_Cb。
      if (p_data) p_ccb->metrics.rx(static_cast<BT_HDR*>(p_data)->len);
      (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR*)p_data);
      break;

    case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
      // 本地应用层发数据
      if (p_ccb->config_done & OB_CFG_DONE)
        // 如果自己发出去的配置完成了,排入发送队列,否则丢弃数据
        l2c_enqueue_peer_data(p_ccb, (BT_HDR*)p_data);
      else
        osi_free(p_data);
      break;

    case L2CEVT_TIMEOUT: // 配置或连接过程超时
      if (p_ccb->ecoc) {
        // 如果是 Credit Based ECOC 连接,且处于 Reconfig 中,遍历所有 CCB,强制断开。
        for (temp_p_ccb = p_lcb->ccb_queue.p_first_ccb; temp_p_ccb;
             temp_p_ccb = temp_p_ccb->p_next_ccb) {
          if ((temp_p_ccb->in_use) && (temp_p_ccb->reconfig_started)) {
            (*temp_p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(
                temp_p_ccb->local_cid, false);
            l2cu_release_ccb(temp_p_ccb);
          }
        }

        acl_disconnect_from_handle(
            p_ccb->p_lcb->Handle(), HCI_ERR_CONN_CAUSE_LOCAL_HOST,
            "stack::l2cap::l2c_csm::l2c_csm_config timeout");
        return;
      }

	  // 否则发送 Disconnect Request 断开连接。
      l2cu_send_peer_disc_req(p_ccb);
      LOG_INFO("Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
                p_ccb->local_cid);
      l2cu_release_ccb(p_ccb);
      (*disconnect_ind)(local_cid, false);
      break;
    default:
      LOG_ERROR("Handling unexpected event:%s", l2c_csm_get_event_name(event));
  }
  LOG_INFO("Exit chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);
}

目前 这个阶段,我们只需要关注:

    case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req   */
      // 本地应用层发来配置请求


      l2cu_process_our_cfg_req(p_ccb, p_cfg); // 处理自己配置请求内容,发给对端。
      l2cu_send_peer_config_req(p_ccb, p_cfg);
      alarm_set_on_mloop(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
                         l2c_ccb_timer_timeout, p_ccb); // 设置配置超时定时器。
      break;
  • l2cu_send_peer_config_req(p_ccb, p_cfg); 向对端发送 配置请求。
  • 此时并没有切状态

1083	2025-04-24 15:56:22.505308	22:22:96:de:b1:39 (leo 8295 chan)	vivoMobi_91:b0:62 (cbx)	L2CAP	21	Sent Configure Request (DCID: 0x0041)

Frame 1083: 21 bytes on wire (168 bits), 21 bytes captured (168 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 12
    CID: L2CAP Signaling Channel (0x0001)
    Command: Configure Request
        Command Code: Configure Request (0x04)
        Command Identifier: 0x0e
        Command Length: 8
        Destination CID: Dynamically Allocated Channel (0x0041)
        0000 0000 0000 000. = Reserved: 0x0000
        .... .... .... ...0 = Continuation Flag: False
        Option: MTU


04-24 15:56:22.505097  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_CONFIG [5], event=UPPER_LAYER_CONFIG_REQ [24]

04-24 15:56:22.505104  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:975 l2c_csm_config: LCID: 0x0046  st: CONFIG  evt: UPPER_LAYER_CONFIG_REQ


04-24 15:56:22.505267  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:1235 l2c_csm_config: Exit chnl_state=CST_CONFIG [5], event=UPPER_LAYER_CONFIG_REQ [24]

4. 接收到手机的配置请求

1089	2025-04-24 15:56:22.598410	vivoMobi_91:b0:62 (cbx)	22:22:96:de:b1:39 (leo 8295 chan)	L2CAP	21	Rcvd Configure Request (DCID: 0x0046)

Frame 1089: 21 bytes on wire (168 bits), 21 bytes captured (168 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 12
    CID: L2CAP Signaling Channel (0x0001)
    Command: Configure Request
        Command Code: Configure Request (0x04)
        Command Identifier: 0x12
        Command Length: 8
        Destination CID: Dynamically Allocated Channel (0x0046)
        0000 0000 0000 000. = Reserved: 0x0000
        .... .... .... ...0 = Continuation Flag: False
        Option: MTU



04-24 15:56:22.598728  6130  6190 I bt_l2c_main: packages/modules/Bluetooth/system/stack/l2cap/l2c_main.cc:310 process_l2cap_cmd: cmd_code: 4, id:18, cmd_len:8

04-24 15:56:22.598769  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_CONFIG [5], event=PEER_CONFIG_REQ [14]

04-24 15:56:22.598780  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:975 l2c_csm_config: LCID: 0x0046  st: CONFIG  evt: PEER_CONFIG_REQ

04-24 15:56:22.598793  6130  6190 I bt_l2cap: packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: l2c_fcr_process_peer_cfg_req() CFG fcr_present:0 fcr.mode:0 CCB FCR mode:0 preferred: 0

04-24 15:56:22.598803  6130  6190 I bt_l2cap: packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: l2cu_adjust_out_mps use 0   Based on peer_cfg.fcr.mps: 0  packet_size: 1011

04-24 15:56:22.598812  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:999 l2c_csm_config: Calling Config_Req_Cb(), CID: 0x0046, C-bit 0
  • 此时我们收到了手机 对我们发起的 配置请求, 我们看一下该如何处理。
#define L2CAP_CMD_CONFIG_REQ 0x04

// system/stack/l2cap/l2c_main.cc  process_l2cap_cmd 中对于  cmd_code: 4 的处理

      case L2CAP_CMD_CONFIG_REQ: {
        uint8_t* p_cfg_end = p + cmd_len; // 记录配置请求的结尾位置,用于控制循环边界。

        // 标记是否发现不支持或格式错误的配置项,并统计被拒绝的长度(用于稍后构造拒绝响应)。
        bool cfg_rej = false;
        uint16_t cfg_rej_len = 0;

        // 每个配置请求头部需要 4 字节(LCID + FLAGS),数据不够就返回。
        uint16_t lcid;
        if (p + 4 > p_next_cmd) {
          LOG_WARN("Not enough data for L2CAP_CMD_CONFIG_REQ");
          return;
        }
        STREAM_TO_UINT16(lcid, p); // lcid:本地通道号,表示配置哪个通道。
        STREAM_TO_UINT16(cfg_info.flags, p); // 如 Continuation 标志(如果选项太长需要分段发送)。

        uint8_t* p_cfg_start = p; // 记录配置选项的起始位置,用于可能的拒绝响应。

		// 清除所有配置标志位(标记哪些选项被包含)。
        cfg_info.flush_to_present = cfg_info.mtu_present =
            cfg_info.qos_present = cfg_info.fcr_present = cfg_info.fcs_present =
                false;

		// 开始解析每个配置选项
        while (p < p_cfg_end) {
          // 进入配置选项循环,直到处理完所有内容。
          // 每个选项结构:code (1B) + len (1B) + data (len B)
          uint8_t cfg_code, cfg_len;
          if (p + 2 > p_next_cmd) {
            LOG_WARN("Not enough data for L2CAP_CMD_CONFIG_REQ sub_event");
            return;
          }
          STREAM_TO_UINT8(cfg_code, p);
          STREAM_TO_UINT8(cfg_len, p);

		  // 处理每种配置类型
          switch (cfg_code & 0x7F) {
            case L2CAP_CFG_TYPE_MTU: // MTU 设置
              cfg_info.mtu_present = true;
              if (cfg_len != 2) {
                return;
              }
              if (p + cfg_len > p_next_cmd) {
                return;
              }
              STREAM_TO_UINT16(cfg_info.mtu, p);
              break;

            // Flush Timeout 设置
            case L2CAP_CFG_TYPE_FLUSH_TOUT:
              cfg_info.flush_to_present = true;
              if (cfg_len != 2) {
                return;
              }
              if (p + cfg_len > p_next_cmd) {
                return;
              }
              STREAM_TO_UINT16(cfg_info.flush_to, p);
              break;

            // QoS 设置(14 字节)
            case L2CAP_CFG_TYPE_QOS:
              cfg_info.qos_present = true;
              if (cfg_len != 2 + 5 * 4) {
                return;
              }
              if (p + cfg_len > p_next_cmd) {
                return;
              }
              STREAM_TO_UINT8(cfg_info.qos.qos_flags, p);
              STREAM_TO_UINT8(cfg_info.qos.service_type, p);
              STREAM_TO_UINT32(cfg_info.qos.token_rate, p);
              STREAM_TO_UINT32(cfg_info.qos.token_bucket_size, p);
              STREAM_TO_UINT32(cfg_info.qos.peak_bandwidth, p);
              STREAM_TO_UINT32(cfg_info.qos.latency, p);
              STREAM_TO_UINT32(cfg_info.qos.delay_variation, p);
              break;

            // FCR(流控制与重传)设置(9 字节)
            case L2CAP_CFG_TYPE_FCR:
              cfg_info.fcr_present = true;
              if (cfg_len != 3 + 3 * 2) {
                return;
              }
              if (p + cfg_len > p_next_cmd) {
                return;
              }
              STREAM_TO_UINT8(cfg_info.fcr.mode, p);
              STREAM_TO_UINT8(cfg_info.fcr.tx_win_sz, p);
              STREAM_TO_UINT8(cfg_info.fcr.max_transmit, p);
              STREAM_TO_UINT16(cfg_info.fcr.rtrans_tout, p);
              STREAM_TO_UINT16(cfg_info.fcr.mon_tout, p);
              STREAM_TO_UINT16(cfg_info.fcr.mps, p);
              break;

			// FCS 设置(Frame Check Sequence)
            case L2CAP_CFG_TYPE_FCS:
              cfg_info.fcs_present = true;
              if (cfg_len != 1) {
                return;
              }
              if (p + cfg_len > p_next_cmd) {
                return;
              }
              STREAM_TO_UINT8(cfg_info.fcs, p);
              break;

			// 扩展流控设置(EXT FLOW)
            case L2CAP_CFG_TYPE_EXT_FLOW:
              cfg_info.ext_flow_spec_present = true;
              if (cfg_len != 2 + 2 + 3 * 4) {
                return;
              }
              if (p + cfg_len > p_next_cmd) {
                return;
              }
              STREAM_TO_UINT8(cfg_info.ext_flow_spec.id, p);
              STREAM_TO_UINT8(cfg_info.ext_flow_spec.stype, p);
              STREAM_TO_UINT16(cfg_info.ext_flow_spec.max_sdu_size, p);
              STREAM_TO_UINT32(cfg_info.ext_flow_spec.sdu_inter_time, p);
              STREAM_TO_UINT32(cfg_info.ext_flow_spec.access_latency, p);
              STREAM_TO_UINT32(cfg_info.ext_flow_spec.flush_timeout, p);
              break;

			// 处理未知或格式错误的选项
            default:
              /* sanity check option length */
              if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len) {
                if (p + cfg_len > p_next_cmd) return;
                p += cfg_len;
                // 注:cfg_code 第 7 位为 1 表示此选项“不可拒绝”
                if ((cfg_code & 0x80) == 0) { // // “可拒绝”位没设置
                  cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
                  cfg_rej = true;
                }
              }
              /* bad length; force loop exit */
              else {
                p = p_cfg_end;
                cfg_rej = true;
              }
              break;
          }
        }

		// 查找此配置请求对应的通道 CCB.
        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
        if (p_ccb) {
          // 如果 CCB 存在:
          p_ccb->remote_id = id;
          if (cfg_rej) {
            // 若发现不合法配置项,则发送 Config Reject。
            l2cu_send_peer_config_rej(
                p_ccb, p_cfg_start, (uint16_t)(cmd_len - L2CAP_CONFIG_REQ_LEN),
                cfg_rej_len);
          } else {
            // 否则将 cfg_info 交给状态机处理配置请求。
            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info);
          }
        } else {
          // 如果 CCB 不存在:
          // 通道无效,发送 Command Reject(CID 无效)响应。
          /* updated spec says send command reject on invalid cid */
          l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0);
        }
        break;
      }

  • 将 cfg_info 交给状态机处理配置请求。
    l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info);

这里发送了 L2CEVT_L2CAP_CONFIG_REQ 消息给状态机

  L2CEVT_L2CAP_CONFIG_REQ = 14,     /* request */

此时 p_ccb->chnl_state 依然是 CST_CONFIG 状态,


void l2c_csm_execute(tL2C_CCB* p_ccb, tL2CEVT event, void* p_data) {
  if (p_ccb == nullptr) {
    LOG_WARN("CCB is null for event (%d)", event);
    return;
  }


  LOG_INFO("Entry chnl_state=%s [%d], event=%s [%d]",
            channel_state_text(p_ccb->chnl_state).c_str(), p_ccb->chnl_state,
            l2c_csm_get_event_name(event), event);


  switch (p_ccb->chnl_state) {
  
  
	  case CST_CONFIG:
      l2c_csm_config(p_ccb, event, p_data);
      break;

	break;
  
  }

}

// 下面是 l2c_csm_config 函数中对于  L2CEVT_L2CAP_CONFIG_REQ 的处理

    case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request   */
      // 对端发来配置请求
      // 调用底层函数解析对端发来的配置请求内容。
      cfg_result = l2cu_process_peer_cfg_req(p_ccb, p_cfg);
      if (cfg_result == L2CAP_PEER_CFG_OK) { // 对端配置没问题。
        LOG_INFO("Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
                  p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
        l2c_csm_send_config_rsp_ok(p_ccb); // 发送Config Response(OK)给对端。
        if (p_ccb->config_done & OB_CFG_DONE) { // 如果自己也已经完成对对方的配置(即 OB_CFG_DONE),检查是否能进入 OPEN 状态
          if (p_ccb->remote_config_rsp_result == L2CAP_CFG_OK) {
            l2c_csm_indicate_connection_open(p_ccb); // 如果对端返回OK,那就打开连接;
          } else { // 否则如果我是发起方,本地上报错误。
            if (p_ccb->connection_initiator == L2CAP_INITIATOR_LOCAL) {
              (*p_ccb->p_rcb->api.pL2CA_Error_Cb)(p_ccb->local_cid,
                                                  L2CAP_CFG_FAILED_NO_REASON);
              bluetooth::shim::CountCounterMetrics(
                  android::bluetooth::CodePathCounterKeyEnum::
                      L2CAP_CONFIG_REQ_FAILURE,
                  1);
            }
          }
        }
      } else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT) { // 配置严重不兼容,需要断开
        /* Disconnect if channels are incompatible */
        LOG_INFO("incompatible configurations disconnect");
        l2cu_disconnect_chnl(p_ccb); //断开连接。
      } else /* Return error to peer so it can renegotiate if possible */
      { // 配置部分不兼容,需要协商:
        LOG_INFO("incompatible configurations trying reconfig");
        l2cu_send_peer_config_rsp(p_ccb, p_cfg); // 发送配置响应,表示部分参数不接受,等对端重新发新的配置。
      }
      break;
  • l2c_csm_send_config_rsp_ok : 向手机 侧发送了 配置应答, 状态没有变化还是 CST_CONFIG

5. 向手机发送配置应答

1090	2025-04-24 15:56:22.598958	22:22:96:de:b1:39 (leo 8295 chan)	vivoMobi_91:b0:62 (cbx)	L2CAP	19	Sent Configure Response - Success (SCID: 0x0041)

Frame 1090: 19 bytes on wire (152 bits), 19 bytes captured (152 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 10
    CID: L2CAP Signaling Channel (0x0001)
    Command: Configure Response
        Command Code: Configure Response (0x05)
        Command Identifier: 0x12
        Command Length: 6
        Source CID: Dynamically Allocated Channel (0x0041)
        0000 0000 0000 000. = Reserved: 0x0000
        .... .... .... ...0 = Continuation Flag: False
        Result: Success (0x0000)


04-24 15:56:22.598819  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_CONFIG [5], event=UPPER_LAYER_CONFIG_RSP [25]

04-24 15:56:22.598826  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:975 l2c_csm_config: LCID: 0x0046  st: CONFIG  evt: UPPER_LAYER_CONFIG_RSP
  • 调用 l2c_csm_send_config_rsp_ok 来处理 向手机发送配置应答的逻辑。
static void l2c_csm_send_config_rsp_ok(tL2C_CCB* p_ccb) {
  tL2CAP_CFG_INFO config{};
  config.result = L2CAP_CFG_OK;
  l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_RSP, &config);
}
  • 发现这里有触发了 L2CEVT_L2CA_CONFIG_RSP 事件
// 此时状态还是 CST_CONFIG, 所以 l2c_csm_execute 继续调用 l2c_csm_config 函数
// 下面是 l2c_csm_config 函数中对于  L2CEVT_L2CA_CONFIG_RSP 的处理

L2CEVT_L2CA_CONFIG_RSP = 25, /* config response */


    case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp   */
      // 本地应用层收到对端的配置响应
      
      l2cu_process_our_cfg_rsp(p_ccb, p_cfg); // 处理对端返回的响应并标记 IB_CFG_DONE。

      p_ccb->config_done |= IB_CFG_DONE;

      // 后续逻辑跟前面的 CONFIG_RSP 类似,不再赘述。
      if (p_ccb->config_done & OB_CFG_DONE) {
        /* Verify two sides are in compatible modes before continuing */
        if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
          l2cu_send_peer_disc_req(p_ccb);
          LOG_WARN(
              "Calling Disconnect_Ind_Cb(Incompatible CFG), CID: "
              "0x%04x  No Conf Needed",
              p_ccb->local_cid);
          l2cu_release_ccb(p_ccb);
          (*disconnect_ind)(local_cid, false);
          break;
        }

        p_ccb->config_done |= RECONFIG_FLAG;
        p_ccb->chnl_state = CST_OPEN;
        l2c_link_adjust_chnl_allocation();
        alarm_cancel(p_ccb->l2c_ccb_timer);
      }

      l2cu_send_peer_config_rsp(p_ccb, p_cfg); //  这里是向手机 发送配置响应的地方。

      /* If using eRTM and waiting for an ACK, restart the ACK timer */
      if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb);

      /* See if we can forward anything on the hold queue */
      if ((p_ccb->chnl_state == CST_OPEN) &&
          (!fixed_queue_is_empty(p_ccb->xmit_hold_q))) {
        l2c_link_check_send_pkts(p_ccb->p_lcb, 0, NULL);
      }
      break;
  • l2cu_send_peer_config_rsp(p_ccb, p_cfg): 这里是向手机 发送配置响应的地方。

6. 接收到手机的配置应答


1091	2025-04-24 15:56:22.599401	vivoMobi_91:b0:62 (cbx)	22:22:96:de:b1:39 (leo 8295 chan)	L2CAP	19	Rcvd Configure Response - Success (SCID: 0x0046)

Frame 1091: 19 bytes on wire (152 bits), 19 bytes captured (152 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI ACL Packet
Bluetooth L2CAP Protocol
    Length: 10
    CID: L2CAP Signaling Channel (0x0001)
    Command: Configure Response
        Command Code: Configure Response (0x05)
        Command Identifier: 0x0e
        Command Length: 6
        Source CID: Dynamically Allocated Channel (0x0046)
        0000 0000 0000 000. = Reserved: 0x0000
        .... .... .... ...0 = Continuation Flag: False
        Result: Success (0x0000)


04-24 15:56:22.599604  6130  6190 I bt_l2c_main: packages/modules/Bluetooth/system/stack/l2cap/l2c_main.cc:310 process_l2cap_cmd: cmd_code: 5, id:14, cmd_len:6

04-24 15:56:22.599636  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:129 l2c_csm_execute: Entry chnl_state=CST_CONFIG [5], event=PEER_CONFIG_RSP [15]

04-24 15:56:22.599646  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:975 l2c_csm_config: LCID: 0x0046  st: CONFIG  evt: PEER_CONFIG_RSP

04-24 15:56:22.599658  6130  6190 I l2c_link: packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc:739 l2c_link_adjust_chnl_allocation: CID:0x0042 FCR Mode:0 Priority:2 TxDataRate:1 RxDataRate:1 Quota:200

04-24 15:56:22.599667  6130  6190 I l2c_link: packages/modules/Bluetooth/system/stack/l2cap/l2c_link.cc:739 l2c_link_adjust_chnl_allocation: CID:0x0046 FCR Mode:0 Priority:2 TxDataRate:1 RxDataRate:1 Quota:200

04-24 15:56:22.599681  6130  6190 I l2c_csm : packages/modules/Bluetooth/system/stack/l2cap/l2c_csm.cc:1088 l2c_csm_config: Calling Config_Rsp_Cb(), CID: 0x0046
  • 在 2025-04-24 15:56:22.599401 收到了 手机 对车机的配置应答。 我们来看一下是如何响应处理的
  • process_l2cap_cmd: cmd_code: 5

#define L2CAP_CMD_CONFIG_RSP 0x05


static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {


      case L2CAP_CMD_CONFIG_RSP: {
        /*
	    计算当前命令数据的结束地址,用于限制 while (p < p_cfg_end) 的解析范围。
		    p 是当前命令起始指针,cmd_len 是该命令的数据长度。
        */
        uint8_t* p_cfg_end = p + cmd_len; 
        uint16_t lcid; // 本地通道 ID,用于查找连接控制块(CCB)。

		// 确保当前命令数据至少有 6 字节可读:LCID (2) + Flags (2) + Result (2)。
        if (p + 6 > p_next_cmd) {
          // 如果不满足,表示数据不完整,记录警告日志并返回。
          LOG_WARN("Not enough data for L2CAP_CMD_CONFIG_RSP");
          return;
        }

        /*
        从数据流中按顺序解析:
			lcid:本地通道 ID
			cfg_info.flags:配置标志(是否继续配置等)
			cfg_info.result:配置结果,例如 L2CAP_CFG_OK
        */
        STREAM_TO_UINT16(lcid, p);
        STREAM_TO_UINT16(cfg_info.flags, p);
        STREAM_TO_UINT16(cfg_info.result, p);

		/*
		清空所有配置字段的标志位,准备重新填充配置项。
		cfg_info 是一个结构体,保存了本次解析得到的配置信息。
		*/
        cfg_info.flush_to_present = cfg_info.mtu_present =
            cfg_info.qos_present = cfg_info.fcr_present = cfg_info.fcs_present =
                false;

		// 开始循环解析各个配置选项:
        while (p < p_cfg_end) {
          // 遍历整个配置项字段,直到到达当前命令末尾。


          uint8_t cfg_code, cfg_len;
          if (p + 2 > p_next_cmd) {
            LOG_WARN("Not enough data for L2CAP_CMD_CONFIG_RSP sub_event");
            return;
          }
          // 获取当前配置项的类型(如 MTU、FCR 等)和长度。
          STREAM_TO_UINT8(cfg_code, p);
          STREAM_TO_UINT8(cfg_len, p);

          switch (cfg_code & 0x7F) { // cfg_code 高位第 7 位用于“是否是可选项”,低 7 位才是实际类型。
            case L2CAP_CFG_TYPE_MTU: // MTU 大小
              cfg_info.mtu_present = true; // 标记为已解析。
              if (p + 2 > p_next_cmd) {
                LOG_WARN("Not enough data for L2CAP_CFG_TYPE_MTU");
                return;
              }
              STREAM_TO_UINT16(cfg_info.mtu, p); // 读取 2 字节 MTU 数值
              break;

            case L2CAP_CFG_TYPE_FLUSH_TOUT: // Flush Timeout
              cfg_info.flush_to_present = true;
              if (p + 2 > p_next_cmd) {
                LOG_WARN("Not enough data for L2CAP_CFG_TYPE_FLUSH_TOUT");
                return;
              }
              STREAM_TO_UINT16(cfg_info.flush_to, p);
              break;

            case L2CAP_CFG_TYPE_QOS:// 服务质量配置
              cfg_info.qos_present = true;
              if (p + 2 + 5 * 4 > p_next_cmd) { // 一共 22 字节:1 + 1 + 5 * 4
                LOG_WARN("Not enough data for L2CAP_CFG_TYPE_QOS");
                return;
              }
              // 包括 token rate、带宽、延迟等。
              STREAM_TO_UINT8(cfg_info.qos.qos_flags, p);
              STREAM_TO_UINT8(cfg_info.qos.service_type, p);
              STREAM_TO_UINT32(cfg_info.qos.token_rate, p);
              STREAM_TO_UINT32(cfg_info.qos.token_bucket_size, p);
              STREAM_TO_UINT32(cfg_info.qos.peak_bandwidth, p);
              STREAM_TO_UINT32(cfg_info.qos.latency, p);
              STREAM_TO_UINT32(cfg_info.qos.delay_variation, p);
              break;

            case L2CAP_CFG_TYPE_FCR: // 流控/重传配置
              cfg_info.fcr_present = true;
              if (p + 3 + 3 * 2 > p_next_cmd) { // 一共 9 字节:3 + 3 * 2
                LOG_WARN("Not enough data for L2CAP_CFG_TYPE_FCR");
                return;
              }
              // 包括模式、窗口大小、超时值等。
              STREAM_TO_UINT8(cfg_info.fcr.mode, p);
              STREAM_TO_UINT8(cfg_info.fcr.tx_win_sz, p);
              STREAM_TO_UINT8(cfg_info.fcr.max_transmit, p);
              STREAM_TO_UINT16(cfg_info.fcr.rtrans_tout, p);
              STREAM_TO_UINT16(cfg_info.fcr.mon_tout, p);
              STREAM_TO_UINT16(cfg_info.fcr.mps, p);
              break;

            case L2CAP_CFG_TYPE_FCS: // 帧校验
              cfg_info.fcs_present = true;
              if (p + 1 > p_next_cmd) {
                LOG_WARN("Not enough data for L2CAP_CFG_TYPE_FCS");
                return;
              }
              // 读取 1 字节的 fcs 校验类型。
              STREAM_TO_UINT8(cfg_info.fcs, p);
              break;

            case L2CAP_CFG_TYPE_EXT_FLOW:// 扩展流控制
              cfg_info.ext_flow_spec_present = true;
              if (p + 2 + 2 + 3 * 4 > p_next_cmd) {
                LOG_WARN("Not enough data for L2CAP_CFG_TYPE_EXT_FLOW");
                return;
              }
              // 读取 ID、服务类型、SDU 尺寸、延迟等。
              STREAM_TO_UINT8(cfg_info.ext_flow_spec.id, p);
              STREAM_TO_UINT8(cfg_info.ext_flow_spec.stype, p);
              STREAM_TO_UINT16(cfg_info.ext_flow_spec.max_sdu_size, p);
              STREAM_TO_UINT32(cfg_info.ext_flow_spec.sdu_inter_time, p);
              STREAM_TO_UINT32(cfg_info.ext_flow_spec.access_latency, p);
              STREAM_TO_UINT32(cfg_info.ext_flow_spec.flush_timeout, p);
              break;
          }
        }

		// 根据 lcid 查找对应的连接控制块(CCB)。
        tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
        if (p_ccb) {
          if (p_ccb->local_id != id) {
            // 检查这条响应命令的标识符 id 是否与原请求一致,不一致可能是延迟或错误响应。
            LOG_WARN("cfg rsp - bad ID. Exp: %d Got: %d", p_ccb->local_id, id);
            break;
          }
          // 成功响应与否:
          if (cfg_info.result == L2CAP_CFG_OK) { // 表示配置接受
            // 使用状态机将配置结果作为事件投递到对应通道的状态机中处理。
            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info);
          } else {
            // 否则认为配置失败,走 L2CEVT_L2CAP_CONFIG_RSP_NEG
            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_RSP_NEG, &cfg_info);
          }
        } else {
          // 找不到则丢弃
          // 输出日志说明:收到一个对未知通道的配置响应,可能是协议异常或状态不同步。
          LOG_WARN("Rcvd cfg rsp for unknown CID: 0x%04x", lcid);
        }
        break;
      }

}
  • l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info);
  • 最终向 状态机 触发了 L2CEVT_L2CAP_CONFIG_RSP 消息
    • L2CEVT_L2CAP_CONFIG_RSP = 15, /* response */

当前状态机还是 处于 CST_CONFIG

// 此时状态还是 CST_CONFIG, 所以 l2c_csm_execute 继续调用 l2c_csm_config 函数
// 下面是 l2c_csm_config 函数中对于  L2CEVT_L2CAP_CONFIG_RSP 的处理

 L2CEVT_L2CAP_CONFIG_RSP = 15, /* response */


    case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response  */
      // 对端发来了配置响应
      l2cu_process_peer_cfg_rsp(p_ccb, p_cfg); // 处理对端的配置响应,把对端配置更新到本地控制块 p_ccb->peer_cfg

      /* TBD: When config options grow beyong minimum MTU (48 bytes)
       *      logic needs to be added to handle responses with
       *      continuation bit set in flags field.
       *       1. Send additional config request out until C-bit is cleared in
       * response
       */
      p_ccb->config_done |= OB_CFG_DONE; // 标记自己发出去的配置已经完成了,OB_CFG_DONE(OutBound Config Done)。

      if (p_ccb->config_done & IB_CFG_DONE) { // 如果对端的配置也完成了(InBound Config Done),说明双方配置都搞定了,可以考虑继续后续操作。
        /* Verify two sides are in compatible modes before continuing */
        if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
          // 检查自己和对端的FCR模式(Flow Control and Retransmission mode,比如 Basic/ERTM/Streaming)是否一致。 如果不一致,无法通信,需要断开
          
          l2cu_send_peer_disc_req(p_ccb); // 发送 Disconnect Request 给对方。
          LOG_WARN(
              "Calling Disconnect_Ind_Cb(Incompatible CFG), CID: "
              "0x%04x  No Conf Needed",
              p_ccb->local_cid);
          l2cu_release_ccb(p_ccb); // 释放 CCB 资源,通知上层断开连接(false 表示无须上层回复)。
          (*disconnect_ind)(local_cid, false);
          break;
        }
        // 如果配置兼容:
        p_ccb->config_done |= RECONFIG_FLAG; // 标记为已经重新配置(即配置完成后还可以后续改配)。
        p_ccb->chnl_state = CST_OPEN; // 把信道状态切换为 CST_OPEN,进入数据传输阶段。
        l2c_link_adjust_chnl_allocation(); // 调整物理链路资源分配。
        alarm_cancel(p_ccb->l2c_ccb_timer); // 取消配置超时定时器

        /* If using eRTM and waiting for an ACK, restart the ACK timer */
        if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb); // 如果在用增强模式(eRTM)且在等ACK包,则重启ACK定时器

        /*
         ** check p_ccb->our_cfg.fcr.mon_tout and
         *p_ccb->our_cfg.fcr.rtrans_tout
         ** we may set them to zero when sending config request during
         *renegotiation
         */
        if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) &&
            ((p_ccb->our_cfg.fcr.mon_tout == 0) ||
             (p_ccb->our_cfg.fcr.rtrans_tout))) {
             // 如果使用 eRTM 且 monitor timeout / retransmission timeout 不合理(=0),调整一下参数。
          l2c_fcr_adj_monitor_retran_timeout(p_ccb);
        }

        /* See if we can forward anything on the hold queue */
        if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
          // 检查有没有挂起的待发数据,有的话现在可以发了!
          l2c_link_check_send_pkts(p_ccb->p_lcb, 0, NULL);
        }
      }

      LOG_INFO("Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid); // 打日志,表明调用了配置完成回调
      p_ccb->remote_config_rsp_result = p_cfg->result; // 记录对端回复的配置结果(比如成功/失败码)。
      if (p_ccb->config_done & IB_CFG_DONE) {
        l2c_csm_indicate_connection_open(p_ccb); // 如果对端配置也完成,通知上层连接正式建立
      }
      break;
  • 手机发起的配置请求, 我们已经响应了, 所以 p_ccb->config_done & IB_CFG_DONE 条件成立
  • p_ccb->chnl_state = CST_OPEN;
  • 此时会调用 l2c_csm_indicate_connection_open(p_ccb)

7. l2c_csm_indicate_connection_open

我们专门看一下这个函数的实现

// system/stack/l2cap/l2c_csm.cc
static void l2c_csm_indicate_connection_open(tL2C_CCB* p_ccb) {
  if (p_ccb->connection_initiator == L2CAP_INITIATOR_LOCAL) { // 如果是发起方,就会回调如下
    (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(p_ccb->local_cid, L2CAP_CONN_OK);
  } else {
    // 在这个场景中 车机并不是发起者,所以会调用如下
    (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)(
        p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm,
        p_ccb->remote_id);
  }
  if (p_ccb->chnl_state == CST_OPEN && !p_ccb->p_lcb->is_transport_ble()) {
    (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(
        p_ccb->local_cid, p_ccb->connection_initiator, &p_ccb->peer_cfg);
  }
}

// system/stack/include/l2c_api.h
typedef struct {
  tL2CA_CONNECT_IND_CB* pL2CA_ConnectInd_Cb;
  tL2CA_CONNECT_CFM_CB* pL2CA_ConnectCfm_Cb;
  tL2CA_CONFIG_IND_CB* pL2CA_ConfigInd_Cb;
  tL2CA_CONFIG_CFM_CB* pL2CA_ConfigCfm_Cb;
  tL2CA_DISCONNECT_IND_CB* pL2CA_DisconnectInd_Cb;
  tL2CA_DISCONNECT_CFM_CB* pL2CA_DisconnectCfm_Cb;
  tL2CA_DATA_IND_CB* pL2CA_DataInd_Cb;
  tL2CA_CONGESTION_STATUS_CB* pL2CA_CongestionStatus_Cb;
  tL2CA_TX_COMPLETE_CB* pL2CA_TxComplete_Cb;
  tL2CA_ERROR_CB* pL2CA_Error_Cb;
  tL2CA_CREDIT_BASED_CONNECT_IND_CB* pL2CA_CreditBasedConnectInd_Cb;
  tL2CA_CREDIT_BASED_CONNECT_CFM_CB* pL2CA_CreditBasedConnectCfm_Cb;
  tL2CA_CREDIT_BASED_RECONFIG_COMPLETED_CB*
      pL2CA_CreditBasedReconfigCompleted_Cb;
  tL2CA_CREDIT_BASED_COLLISION_IND_CB* pL2CA_CreditBasedCollisionInd_Cb;
} tL2CAP_APPL_INFO;

// system/stack/avdt/avdt_l2c.cc
const tL2CAP_APPL_INFO avdt_l2c_appl = {avdt_l2c_connect_ind_cback,
                                        avdt_l2c_connect_cfm_cback,
                                        avdt_l2c_config_ind_cback,
                                        avdt_l2c_config_cfm_cback,
                                        avdt_l2c_disconnect_ind_cback,
                                        NULL,
                                        avdt_l2c_data_ind_cback,
                                        avdt_l2c_congestion_ind_cback,
                                        NULL,
                                        avdt_on_l2cap_error,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL};
  • 这个函数会 触发 avdtp 对应的 pL2CA_ConnectInd_Cb 和 pL2CA_ConfigCfm_Cb 调用

  • 所以此时会触发 avdt_l2c_connect_ind_cback 和 avdt_l2c_config_cfm_cback

04-24 15:56:22.599692  6130  6190 I bt_avp  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: trace_avdt avdt_l2c_connect_ind_cback 143 ->

04-24 15:56:22.599759  6130  6190 I bt_avp  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: avdt_ccb_alloc_by_channel_index: allocated (index 0) peer=70:8f:47:91:b0:62 p_ccb=0x7a407afc28

04-24 15:56:22.599782  6130  6190 I bt_avp  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:201 LogMsg: avdt_ad_tc_tbl_to_idx: 0

04-24 15:56:22.599793  6130  6190 I bt_avp  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: trace_avdt avdt_l2c_config_cfm_cback 306 ->

04-24 15:56:22.599801  6130  6190 I bt_avp  : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: trace_avdt avdt_l2c_config_ind_cback 339 ->

  • 至于 avdtp 如何初始化, 不再本节的分析之内, 会在 avdtp 章节中,专门分享。

3. 小结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值