【android bluetooth 协议分析 06】【l2cap详解 9】【L2cap通道生命周期】

发布于:2025-05-01 ⋅ 阅读:(20) ⋅ 点赞:(0)

本篇 我们开始对 L2CAP 信道状态机的行为进行梳理,覆盖了 Classic L2CAP 和 Credit-based L2CAP 的连接、配置、数据传输、断开流程,以及 Credit-based Reconfig 场景。


在开始本篇介绍之前, 我们先来认识一下 有限状态机(FSM) 模型。

1. FSM 模型

1. 什么是有限状态机(FSM)?

有限状态机是一种抽象的计算模型,用于描述系统在不同状态之间的切换行为。它广泛应用于嵌入式系统、网络协议、编译器、游戏开发、操作系统等场景。

1. 构成要素

一个 FSM 通常由以下几个核心组成:

要素 含义
状态(State) 系统可能处于的某种情况(例如“待机”、“连接中”)
事件(Event) 触发状态改变的外部或内部动作(例如“连接请求”)
动作(Action) 状态转换时执行的操作(例如“初始化连接参数”)
状态转移(Transition) 根据当前状态和事件,决定下一个状态

2. 状态机示意图(简化)

          [Idle] : 初始状态为 Idle
            |
       Connect Request : 此时来了一个 事件:连接请求
            ↓
       [Connecting]: 此时状态切换为 Connecting
            |
     Connection Success : 此时来了一个事件: 连接成功
            ↓
        [Connected] : 此时状态切换为 Connected


3. 类型分类

类型 特点
Mealy 状态机 输出取决于当前状态和输入(动作发生在边上)
Moore 状态机 输出仅取决于当前状态(动作发生在状态上)

大多数实际系统会使用 混合模型,即部分动作跟随事件触发,部分跟随状态变化。


4. 类比:FSM 就像一个红绿灯控制器

状态 事件 行动 下一个状态
红灯 时间到 变黄灯 黄灯
黄灯 时间到 变绿灯 绿灯
绿灯 时间到 变红灯 红灯

这个系统只有有限几个状态(红、黄、绿),每个状态在某个条件满足(如时间到)后会跳转到另一个状态。这就是一个经典的 FSM。


5. FSM 在系统中的应用示例

例如一个音乐 App:

  • 状态:首页, 播放页, 设置页
  • 事件:点击按钮
  • 动作:更新 UI,切换页面

6. 状态机的优势

优点 说明
结构清晰 每种状态和转移逻辑一目了然
易于维护 修改状态逻辑不影响其他部分
可视化强 状态图可以清楚展示系统流程
适合代码自动生成 如使用工具(UML、statechart)辅助开发

7. 简化代码示例

switch (state) {
  case STATE_CLOSED:
    if (event == CONNECT_REQ) {
      send_connect_rsp();
      state = STATE_CONNECTING;
    }
    break;

  case STATE_CONNECTING:
    if (event == CONNECT_SUCCESS) {
      init_config();
      state = STATE_CONFIG;
    }
    break;
}


8. 小结

内容
FSM 是什么? 用来描述系统在不同状态之间如何根据事件进行转换的模型
有什么用? 描述复杂交互逻辑(如蓝牙连接、协议握手、APP导航等)
好处是? 模块清晰,逻辑明确,易于调试和可视化

2. FSM和l2cap 的关系

在 aosp 中 l2cap 对于信道的的管理就是使用的 FSM 模型。 只有了解了 FSM 是什么,我们才能清晰去剖析 aosp 的 l2cap 源码。

在 Android AOSP 的蓝牙协议栈中,每条 L2CAP 信道(channel)就是一个 FSM:

  • 状态:CLOSED, WAIT_CONNECT_RSP, CONFIG, OPEN, DISCONNECTING 等。
  • 事件:L2CEVT_L2CAP_CONNECT_REQ, L2CEVT_L2CAP_CONFIG_RSP, L2CEVT_LP_DISCONNECT_IND 等。
  • 动作:调用回调通知上层、发送数据包给对端、启动定时器等。
  • 状态转移:配置完成后进入 OPEN,断开请求后进入 DISCONNECTING

3. 剖析l2cap 源码

铺垫了这么多,我们现在看,如何一步步和我们的 源码对应起来。

在 l2cap相关的源码中,我们会看到 很多 对于 p_ccb->chnl_state 通道 的赋值和判断。容易让人晕。那这些都代码什么呢? 我们该如何快速梳理清楚这些信息呢?

我们在之前 的文章 通俗易懂l2cap 状态机里面其实就已经介绍过。 还记得这张图吗?

在这里插入图片描述

  • 图中每一个 圆圈代表 一个状态。 也就是对 p_ccb->chnl_state 的不同赋值。

在aosp 中 l2cap 的状态 是通过 tL2C_CHNL_STATE 来定义的。

p_ccb->chnl_state

每个 状态 之间的切换, 的触发点都是 我们的事件来触发的。 而aosp 中的事件都是用 tL2CEVT 来描述的。

状态和事件的关系是什么?

l2c_csm.cc 的状态机模型中:

  • 状态(State) 描述的是 当前连接的生命周期阶段(比如正在等待安全认证、正在配置、已经打开等)。

  • 事件(Event)触发状态变化的外部/内部信号(比如收到连接请求、认证成功、配置完成等)。

状态 + 事件 = 动作(Action) + 下一状态(Next State)

这是典型的 有限状态机(FSM) 模型。


举个例子
来自 l2c_csm.cc

case CST_ORIG_W4_SEC_COMP:
    switch (event) {
      case L2CEVT_SEC_COMP:
        // 认证成功,下一状态是等待 L2CAP 连接响应
        ...
        p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
        break;

这段逻辑明确说明:

  • 当前状态:CST_ORIG_W4_SEC_COMP
  • 当前事件:L2CEVT_SEC_COMP
  • 新状态:CST_W4_L2CAP_CONNECT_RSP

我们先来梳理一下 l2cap 中所有的状态

1. tL2C_CHNL_STATE 介绍

// system/stack/l2cap/l2c_int.h
typedef enum {
  CST_CLOSED,                  /* Channel is in closed state */
  CST_ORIG_W4_SEC_COMP,        /* Originator waits security clearence */
  CST_TERM_W4_SEC_COMP,        /* Acceptor waits security clearence */
  CST_W4_L2CAP_CONNECT_RSP,    /* Waiting for peer conenct response */
  CST_W4_L2CA_CONNECT_RSP,     /* Waiting for upper layer connect rsp */
  CST_CONFIG,                  /* Negotiating configuration */
  CST_OPEN,                    /* Data transfer state */
  CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */
  CST_W4_L2CA_DISCONNECT_RSP   /* Waiting for upper layer disc rsp */
} tL2C_CHNL_STATE;

每个状态都代表 L2CAP 信道的某个生命周期阶段

状态枚举值 生命周期阶段 状态含义(职责) 典型进入条件 典型离开条件
CST_CLOSED 初始 / 终止阶段 信道未建立或已关闭;表示不活动状态。 - 信道刚分配
- 信道断开完成
- 发起连接请求(主动连接)
- 收到连接请求(被动连接)
CST_ORIG_W4_SEC_COMP 连接准备阶段(主动) 主动连接发起者正在等待安全认证完成。 - 应用层请求连接
- 本地需要安全认证
- 安全验证通过或失败
CST_TERM_W4_SEC_COMP 连接准备阶段(被动) 被动连接接收者正在等待安全认证完成。 - 接收到连接请求
- 本地需要安全认证
- 安全验证通过或失败
CST_W4_L2CAP_CONNECT_RSP 建链阶段(主动) 主动发起连接后,正在等待对端回应 L2CAP_CONNECT_RSP - 安全验证通过后,发送 L2CAP_CONNECT_REQ - 收到 L2CAP_CONNECT_RSP(成功、失败、pending)
CST_W4_L2CA_CONNECT_RSP 建链阶段(被动) 被动收到连接请求后,等待上层回应是否接受连接。 - 收到 L2CAP_CONNECT_REQ
- 安全验证通过
- 上层调用 L2CA_ConnectRsp() 发送 L2CAP_CONNECT_RSP
CST_CONFIG 配置阶段 信道已建立,正在协商配置参数(MTU、QoS等)。 - 双方连接确认无误 - 本地和对端配置完成
CST_OPEN 数据传输阶段 配置成功,信道处于“开放”状态,可进行数据收发。 - 配置阶段完成(收发双方 config req/resp 都完成) - 发起或收到断开请求
CST_W4_L2CAP_DISCONNECT_RSP 断开阶段(主动) 主动发起断开后,等待对端响应 L2CAP_DISCONNECT_RSP - 本地调用 L2CA_DisconnectReq() - 收到对端 L2CAP_DISCONNECT_RSP
CST_W4_L2CA_DISCONNECT_RSP 断开阶段(被动) 对端发起断开请求后,本地等待上层调用 L2CA_DisconnectRsp() 响应断开。 - 收到对端 L2CAP_DISCONNECT_REQ - 本地上层响应断开(调用 L2CA_DisconnectRsp()

1. 生命周期流程简述(配合状态表)

  • 连接前: CST_CLOSED
  • 主动连接发起: CST_ORIG_W4_SEC_COMPCST_W4_L2CAP_CONNECT_RSP
  • 被动连接接收: CST_TERM_W4_SEC_COMPCST_W4_L2CA_CONNECT_RSP
  • 配置阶段: CST_CONFIG
  • 连接建立完成: CST_OPEN
  • 断开过程(主动): CST_W4_L2CAP_DISCONNECT_RSP
  • 断开过程(被动): CST_W4_L2CA_DISCONNECT_RSP
  • 最终状态: CST_CLOSED

2.CST_ORIG_W4_SEC_COMP/CST_TERM_W4_SEC_COMP 介绍

tL2C_CHNL_STATE 枚举中:

  • CST_ORIG_W4_SEC_COMPOriginator waits security clearance
  • CST_TERM_W4_SEC_COMPTerminator (i.e. acceptor) waits security clearance

从命名和注释来看,这两个状态都属于 等待安全认证 的阶段,但它们分别用于 主动连接发起方(Originator)被动连接接收方(Terminator),即:

状态 所属角色 场景说明
CST_ORIG_W4_SEC_COMP 主动发起方 我们调用 L2CA_ConnectReq() 发起连接请求,需要先进行安全认证
CST_TERM_W4_SEC_COMP 被动接收方 对方发起连接请求,我们收到 L2CAP_CONNECT_REQ,需要本地进行安全认证

1. 为什么一个是“主动”,一个是“被动”?

L2CAP 连接建立是一个主被动分工明确的过程,需要配合 SDP、Security Manager(安全认证)等模块完成握手过程。在安全认证阶段,根据发起连接的一方不同:

  • 我们主动发起连接(Originator):我们触发连接流程,也就需要我们等待“本地的安全认证”完成之后再继续(如发送 L2CAP_CONNECT_REQ)。

    • 对应状态:CST_ORIG_W4_SEC_COMP
  • 我们被动接收连接(Terminator):我们收到对方发来的 L2CAP_CONNECT_REQ,但我们需要先验证是否允许连接(通过安全管理器),再回复 L2CAP_CONNECT_RSP

    • 对应状态:CST_TERM_W4_SEC_COMP

2. 状态之间的本质区别
状态名 安全认证触发方 安全认证后动作
CST_ORIG_W4_SEC_COMP 我们主动调用 安全认证成功 → 发送 L2CAP_CONNECT_REQ
CST_TERM_W4_SEC_COMP 我们被动接收 安全认证成功 → 继续处理 CONNECT_REQ 并向上层汇报

3. 举个现实场景类比

你可以把这个过程想象成:

  • 你(车机)打电话给别人(手机):你要通过保安(安全模块)验证你能否联系到别人,验证中你就是 Originator

  • 别人(手机)给你打电话:你收到请求,但也得问一下保安(安全模块)你是否愿意接,验证中你就是 Terminator


上面已经结束了所有的 l2cap 的事件, 接下来介绍, 触发状态切换的 事件都有哪些:

2. tL2CEVT 介绍

// system/stack/l2cap/l2c_int.h
typedef enum : uint16_t {
  /* Lower layer */
  L2CEVT_LP_CONNECT_CFM = 0,     /* connect confirm */
  L2CEVT_LP_CONNECT_CFM_NEG = 1, /* connect confirm (failed) */
  L2CEVT_LP_CONNECT_IND = 2,     /* connect indication */
  L2CEVT_LP_DISCONNECT_IND = 3,  /* disconnect indication */

  /* Security */
  L2CEVT_SEC_COMP = 7,     /* cleared successfully */
  L2CEVT_SEC_COMP_NEG = 8, /* procedure failed */

  /* Peer connection */
  L2CEVT_L2CAP_CONNECT_REQ = 10,     /* request */
  L2CEVT_L2CAP_CONNECT_RSP = 11,     /* response */
  L2CEVT_L2CAP_CONNECT_RSP_PND = 12, /* response pending */
  L2CEVT_L2CAP_CONNECT_RSP_NEG = 13, /* response (failed) */

  /* Peer configuration */
  L2CEVT_L2CAP_CONFIG_REQ = 14,     /* request */
  L2CEVT_L2CAP_CONFIG_RSP = 15,     /* response */
  L2CEVT_L2CAP_CONFIG_RSP_NEG = 16, /* response (failed) */

  L2CEVT_L2CAP_DISCONNECT_REQ = 17, /* Peer disconnect request */
  L2CEVT_L2CAP_DISCONNECT_RSP = 18, /* Peer disconnect response */
  L2CEVT_L2CAP_INFO_RSP = 19,       /* Peer information response */
  L2CEVT_L2CAP_DATA = 20,           /* Peer data */

  /* Upper layer */
  L2CEVT_L2CA_CONNECT_REQ = 21,     /* connect request */
  L2CEVT_L2CA_CONNECT_RSP = 22,     /* connect response */
  L2CEVT_L2CA_CONNECT_RSP_NEG = 23, /* connect response (failed)*/
  L2CEVT_L2CA_CONFIG_REQ = 24,      /* config request */
  L2CEVT_L2CA_CONFIG_RSP = 25,      /* config response */
  L2CEVT_L2CA_DISCONNECT_REQ = 27,  /* disconnect request */
  L2CEVT_L2CA_DISCONNECT_RSP = 28,  /* disconnect response */
  L2CEVT_L2CA_DATA_READ = 29,       /* data read */
  L2CEVT_L2CA_DATA_WRITE = 30,      /* data write */

  L2CEVT_TIMEOUT = 32,         /* Timeout */
  L2CEVT_SEC_RE_SEND_CMD = 33, /* btm_sec has enough info to proceed */

  L2CEVT_ACK_TIMEOUT = 34, /* RR delay timeout */

  L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT = 35, /* Upper layer credit packet \
                                              */
  /* Peer credit based connection */
  L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT = 36, /* credit packet */
  L2CEVT_L2CAP_CREDIT_BASED_CONNECT_REQ =
      37, /* credit based connection request */
  L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP =
      38, /* accepted credit based connection */
  L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP_NEG =
      39, /* rejected credit based connection */
  L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_REQ =
      40, /* credit based reconfig request*/
  L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_RSP =
      41, /* credit based reconfig response */

  /* Upper layer credit based connection */
  L2CEVT_L2CA_CREDIT_BASED_CONNECT_REQ = 42,     /* connect request */
  L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP = 43,     /* connect response */
  L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP_NEG = 44, /* connect response (failed)*/
  L2CEVT_L2CA_CREDIT_BASED_RECONFIG_REQ = 45,    /* reconfig request */
} tL2CEVT;

1. L2CAP 事件对照表

事件名 分类 方向 说明 适用连接类型
L2CEVT_LP_CONNECT_CFM 0 Lower Layer 下层→L2CAP 连接成功确认(主动发起方收到) Classic & Credit-based
L2CEVT_LP_CONNECT_CFM_NEG 1 Lower Layer 下层→L2CAP 连接失败确认 Classic & Credit-based
L2CEVT_LP_CONNECT_IND 2 Lower Layer 下层→L2CAP 接收到连接请求(被动方) Classic & Credit-based
L2CEVT_LP_DISCONNECT_IND 3 Lower Layer 下层→L2CAP 接收到断开连接通知 Classic & Credit-based

事件名 分类 方向 说明 适用连接类型
L2CEVT_SEC_COMP 7 安全 安全层→L2CAP 安全认证完成 Classic & Credit-based
L2CEVT_SEC_COMP_NEG 8 安全 安全层→L2CAP 安全认证失败 Classic & Credit-based

事件名 分类 Peer → L2CAP 说明 适用连接类型
L2CEVT_L2CAP_CONNECT_REQ 10 Peer信令 接收到 L2CAP 连接请求 Classic
L2CEVT_L2CAP_CONNECT_RSP 11 Peer信令 对连接请求的响应 Classic
L2CEVT_L2CAP_CONNECT_RSP_PND 12 Peer信令 延迟连接响应(pending) Classic
L2CEVT_L2CAP_CONNECT_RSP_NEG 13 Peer信令 连接失败响应 Classic
L2CEVT_L2CAP_CONFIG_REQ 14 Peer信令 接收到配置请求 Classic
L2CEVT_L2CAP_CONFIG_RSP 15 Peer信令 接收到配置响应 Classic
L2CEVT_L2CAP_CONFIG_RSP_NEG 16 Peer信令 接收到配置失败响应 Classic
L2CEVT_L2CAP_DISCONNECT_REQ 17 Peer信令 对方发起断开 Classic
L2CEVT_L2CAP_DISCONNECT_RSP 18 Peer信令 对方响应断开请求 Classic
L2CEVT_L2CAP_INFO_RSP 19 Peer信令 Peer 信息响应(Info Response) Classic
L2CEVT_L2CAP_DATA 20 数据 接收到 peer 数据帧 Classic & Credit-based

事件名 分类 应用层→L2CAP 说明 适用连接类型
L2CEVT_L2CA_CONNECT_REQ 21 上层 应用层发起连接请求 Classic
L2CEVT_L2CA_CONNECT_RSP 22 上层 应用层同意连接 Classic
L2CEVT_L2CA_CONNECT_RSP_NEG 23 上层 应用层拒绝连接 Classic
L2CEVT_L2CA_CONFIG_REQ 24 上层 应用层配置请求 Classic
L2CEVT_L2CA_CONFIG_RSP 25 上层 应用层配置响应 Classic
L2CEVT_L2CA_DISCONNECT_REQ 27 上层 应用层发起断开 Classic
L2CEVT_L2CA_DISCONNECT_RSP 28 上层 应用层响应断开 Classic
L2CEVT_L2CA_DATA_READ 29 上层 上层读取到数据 Classic & Credit-based
L2CEVT_L2CA_DATA_WRITE 30 上层 上层发送数据 Classic & Credit-based

事件名 分类 系统 说明 适用连接类型
L2CEVT_TIMEOUT 32 定时器 超时事件 Classic & Credit-based
L2CEVT_SEC_RE_SEND_CMD 33 安全 安全层 安全认证完成,可重新发送命令 Classic & Credit-based
L2CEVT_ACK_TIMEOUT 34 定时器 等待 ACK 超时 Classic

2. Credit-based L2CAP 专用事件

事件名 分类 说明 方向 适用
L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT 35 上层 本地应用补充 credit 应用→L2CAP Credit-based
L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT 36 Peer 接收到对方发送的 credit Peer→L2CAP Credit-based
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_REQ 37 Peer Credit-based 连接请求 Peer→L2CAP Credit-based
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP 38 Peer Credit-based 连接成功响应 Peer→L2CAP Credit-based
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP_NEG 39 Peer Credit-based 连接失败响应 Peer→L2CAP Credit-based
L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_REQ 40 Peer 重新配置请求 Peer→L2CAP Credit-based
L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_RSP 41 Peer 重新配置响应 Peer→L2CAP Credit-based
L2CEVT_L2CA_CREDIT_BASED_CONNECT_REQ 42 上层 应用层发起 Credit-based 连接 应用→L2CAP Credit-based
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP 43 上层 应用层接受连接 应用→L2CAP Credit-based
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP_NEG 44 上层 应用层拒绝连接 应用→L2CAP Credit-based
L2CEVT_L2CA_CREDIT_BASED_RECONFIG_REQ 45 上层 应用发起 reconfig 请求 应用→L2CAP Credit-based

3. 单个状态梳理

上面我已经帮大家梳理出了 状态和事件。 但是还是不够清晰。 接下来,我将 按照 某一个状态, 接收那些事件(信号) , 需要 执行那些 操作(action), 操作执行完毕后,应该切换到 那个状态。在梳理一次。

1. Classic L2CAP 状态机分析

状态:CST_CLOSED
Event 说明 条件 Action Next State
L2CEVT_L2CA_CONNECT_REQ 上层发起 Classic L2CAP 连接请求 需要分配 local CID 和 peer CID 启动物理连接(l2cu_create_conn) CST_ORIG_W4_SEC_COMP
L2CEVT_LP_CONNECT_IND 接收到物理连接建立请求 —— 回复 L2CAP connect indication,启动安全验证 CST_TERM_W4_SEC_COMP
状态:CST_ORIG_W4_SEC_COMP
Event 说明 条件 Action Next State
L2CEVT_SEC_COMP 安全检查成功 —— 发送 L2CAP connect request CST_W4_L2CAP_CONNECT_RSP
L2CEVT_SEC_COMP_NEG 安全检查失败 —— 通知上层失败 CST_CLOSED
状态:CST_TERM_W4_SEC_COMP
Event 说明 条件 Action Next State
L2CEVT_SEC_COMP 安全检查成功 —— 通知上层有连接请求 CST_W4_L2CA_CONNECT_RSP
L2CEVT_SEC_COMP_NEG 安全检查失败 —— 回复 connect negative CST_CLOSED
状态:CST_W4_L2CAP_CONNECT_RSP
Event 说明 条件 Action Next State
L2CEVT_L2CAP_CONNECT_RSP 接收到 peer 的 connect response(成功) —— 发送 config request CST_CONFIG
L2CEVT_L2CAP_CONNECT_RSP_NEG peer 拒绝连接 —— 通知上层失败 CST_CLOSED
L2CEVT_L2CAP_CONNECT_RSP_PND peer 暂时无法接收 —— 等待 保持不变
状态:CST_W4_L2CA_CONNECT_RSP
Event 说明 条件 Action Next State
L2CEVT_L2CA_CONNECT_RSP 上层接受连接 —— 发送 connect response + config request CST_CONFIG
L2CEVT_L2CA_CONNECT_RSP_NEG 上层拒绝连接 —— 回复 connect negative CST_CLOSED
状态:CST_CONFIG
Event 说明 条件 Action Next State
L2CEVT_L2CAP_CONFIG_REQ peer 配置本地 接收参数并记录 回复 config rsp 根据配置完成情况维持或进入 OPEN
L2CEVT_L2CAP_CONFIG_RSP peer 回应我方配置 —— 检查是否都完成 若都完成 → CST_OPEN,否则保持
L2CEVT_L2CAP_CONFIG_RSP_NEG peer 拒绝配置 —— 处理失败并通知 CST_CLOSED
状态:CST_OPEN
Event 说明 条件 Action Next State
L2CEVT_L2CAP_DISCONNECT_REQ peer 请求断开 —— 回复 disconnect rsp CST_CLOSED
L2CEVT_L2CA_DISCONNECT_REQ 上层请求断开 —— 发送 disconnect req CST_W4_L2CAP_DISCONNECT_RSP
L2CEVT_L2CAP_DATA peer 数据到达 —— 调用上层回调 保持
状态:CST_W4_L2CAP_DISCONNECT_RSP
Event 说明 条件 Action Next State
L2CEVT_L2CAP_DISCONNECT_RSP peer 回复断开成功 —— 通知上层 CST_CLOSED
状态:CST_W4_L2CA_DISCONNECT_RSP
Event 说明 条件 Action Next State
L2CEVT_L2CA_DISCONNECT_RSP 上层确认断开 —— 清理资源 CST_CLOSED

2. Credit-based L2CAP 状态机分析

状态:CST_CLOSED
Event 说明 条件 Action Next State
L2CEVT_L2CA_CREDIT_BASED_CONNECT_REQ 上层请求 credit-based 连接 分配 local CID,初始化 FCR 模式 发送 connect req,启动物理连接 CST_ORIG_W4_SEC_COMP
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_REQ peer 请求 credit-based 连接 检查服务 UUID 是否支持 启动安全验证流程 CST_TERM_W4_SEC_COMP
状态:CST_ORIG_W4_SEC_COMP
Event 说明 条件 Action Next State
L2CEVT_SEC_COMP 安全验证成功 —— 发送 CB connect 请求 CST_W4_L2CAP_CONNECT_RSP
L2CEVT_SEC_COMP_NEG 安全验证失败 —— 通知上层失败 CST_CLOSED
状态:CST_TERM_W4_SEC_COMP
Event 说明 条件 Action Next State
L2CEVT_SEC_COMP 安全验证成功 —— 通知上层(connect indication) CST_W4_L2CA_CONNECT_RSP
L2CEVT_SEC_COMP_NEG 安全验证失败 —— 回复 connect negative CST_CLOSED
状态:CST_W4_L2CAP_CONNECT_RSP
Event 说明 条件 Action Next State
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP peer 同意连接 —— 通知上层成功 CST_OPEN
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP_NEG peer 拒绝连接 —— 通知上层失败 CST_CLOSED
状态:CST_W4_L2CA_CONNECT_RSP
Event 说明 条件 Action Next State
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP 上层接受连接 —— 回复 connect rsp CST_OPEN
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP_NEG 上层拒绝连接 —— 回复 connect negative CST_CLOSED
状态:CST_OPEN
Event 说明 条件 Action Next State
L2CEVT_L2CA_DISCONNECT_REQ 上层请求断开 —— 发送 disconnect req CST_W4_L2CAP_DISCONNECT_RSP
L2CEVT_L2CAP_DISCONNECT_REQ peer 请求断开 —— 回复 disconnect rsp CST_CLOSED
L2CEVT_L2CAP_DATA peer 数据 —— 通知上层 保持
L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT 接收信用额度 —— 更新 flow control 保持
L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT 上层发出信用 —— 发送 credit 保持

3. Credit-based Reconfig 状态

状态:CST_OPEN
Event 说明 条件 Action Next State
L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_REQ peer 请求 Reconfig —— 回复 reconfig rsp 保持
L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_RSP peer 回应我方 Reconfig 请求 —— 更新配置 保持
L2CEVT_L2CA_CREDIT_BASED_RECONFIG_REQ 上层请求 Reconfig —— 发送 reconfig 请求 保持

4. 小结

本篇开篇介绍了 FSM模型,详细介绍了 tL2C_CHNL_STATE 和 tL2CEVT 。 单个状态下,在接收到事件后,如何切换到下一个状态。也帮助大家梳理了一遍。 大家应该对 l2cap 有一个大体了了解了。 我详细有了这些梳理。 我们在对照代码来看, 应该不是特别吃力了。