当前位置: 首页 > news >正文

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

本篇 我们开始对 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_CFM0Lower Layer下层→L2CAP连接成功确认(主动发起方收到)Classic & Credit-based
L2CEVT_LP_CONNECT_CFM_NEG1Lower Layer下层→L2CAP连接失败确认Classic & Credit-based
L2CEVT_LP_CONNECT_IND2Lower Layer下层→L2CAP接收到连接请求(被动方)Classic & Credit-based
L2CEVT_LP_DISCONNECT_IND3Lower Layer下层→L2CAP接收到断开连接通知Classic & Credit-based

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

事件名分类Peer → L2CAP说明适用连接类型
L2CEVT_L2CAP_CONNECT_REQ10Peer信令接收到 L2CAP 连接请求Classic
L2CEVT_L2CAP_CONNECT_RSP11Peer信令对连接请求的响应Classic
L2CEVT_L2CAP_CONNECT_RSP_PND12Peer信令延迟连接响应(pending)Classic
L2CEVT_L2CAP_CONNECT_RSP_NEG13Peer信令连接失败响应Classic
L2CEVT_L2CAP_CONFIG_REQ14Peer信令接收到配置请求Classic
L2CEVT_L2CAP_CONFIG_RSP15Peer信令接收到配置响应Classic
L2CEVT_L2CAP_CONFIG_RSP_NEG16Peer信令接收到配置失败响应Classic
L2CEVT_L2CAP_DISCONNECT_REQ17Peer信令对方发起断开Classic
L2CEVT_L2CAP_DISCONNECT_RSP18Peer信令对方响应断开请求Classic
L2CEVT_L2CAP_INFO_RSP19Peer信令Peer 信息响应(Info Response)Classic
L2CEVT_L2CAP_DATA20数据接收到 peer 数据帧Classic & Credit-based

事件名分类应用层→L2CAP说明适用连接类型
L2CEVT_L2CA_CONNECT_REQ21上层应用层发起连接请求Classic
L2CEVT_L2CA_CONNECT_RSP22上层应用层同意连接Classic
L2CEVT_L2CA_CONNECT_RSP_NEG23上层应用层拒绝连接Classic
L2CEVT_L2CA_CONFIG_REQ24上层应用层配置请求Classic
L2CEVT_L2CA_CONFIG_RSP25上层应用层配置响应Classic
L2CEVT_L2CA_DISCONNECT_REQ27上层应用层发起断开Classic
L2CEVT_L2CA_DISCONNECT_RSP28上层应用层响应断开Classic
L2CEVT_L2CA_DATA_READ29上层上层读取到数据Classic & Credit-based
L2CEVT_L2CA_DATA_WRITE30上层上层发送数据Classic & Credit-based

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

2. Credit-based L2CAP 专用事件

事件名分类说明方向适用
L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT35上层本地应用补充 credit应用→L2CAPCredit-based
L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT36Peer接收到对方发送的 creditPeer→L2CAPCredit-based
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_REQ37PeerCredit-based 连接请求Peer→L2CAPCredit-based
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP38PeerCredit-based 连接成功响应Peer→L2CAPCredit-based
L2CEVT_L2CAP_CREDIT_BASED_CONNECT_RSP_NEG39PeerCredit-based 连接失败响应Peer→L2CAPCredit-based
L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_REQ40Peer重新配置请求Peer→L2CAPCredit-based
L2CEVT_L2CAP_CREDIT_BASED_RECONFIG_RSP41Peer重新配置响应Peer→L2CAPCredit-based
L2CEVT_L2CA_CREDIT_BASED_CONNECT_REQ42上层应用层发起 Credit-based 连接应用→L2CAPCredit-based
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP43上层应用层接受连接应用→L2CAPCredit-based
L2CEVT_L2CA_CREDIT_BASED_CONNECT_RSP_NEG44上层应用层拒绝连接应用→L2CAPCredit-based
L2CEVT_L2CA_CREDIT_BASED_RECONFIG_REQ45上层应用发起 reconfig 请求应用→L2CAPCredit-based

3. 单个状态梳理

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

1. Classic L2CAP 状态机分析

状态:CST_CLOSED
Event说明条件ActionNext 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说明条件ActionNext State
L2CEVT_SEC_COMP安全检查成功——发送 L2CAP connect requestCST_W4_L2CAP_CONNECT_RSP
L2CEVT_SEC_COMP_NEG安全检查失败——通知上层失败CST_CLOSED
状态:CST_TERM_W4_SEC_COMP
Event说明条件ActionNext State
L2CEVT_SEC_COMP安全检查成功——通知上层有连接请求CST_W4_L2CA_CONNECT_RSP
L2CEVT_SEC_COMP_NEG安全检查失败——回复 connect negativeCST_CLOSED
状态:CST_W4_L2CAP_CONNECT_RSP
Event说明条件ActionNext State
L2CEVT_L2CAP_CONNECT_RSP接收到 peer 的 connect response(成功)——发送 config requestCST_CONFIG
L2CEVT_L2CAP_CONNECT_RSP_NEGpeer 拒绝连接——通知上层失败CST_CLOSED
L2CEVT_L2CAP_CONNECT_RSP_PNDpeer 暂时无法接收——等待保持不变
状态:CST_W4_L2CA_CONNECT_RSP
Event说明条件ActionNext State
L2CEVT_L2CA_CONNECT_RSP上层接受连接——发送 connect response + config requestCST_CONFIG
L2CEVT_L2CA_CONNECT_RSP_NEG上层拒绝连接——回复 connect negativeCST_CLOSED
状态:CST_CONFIG
Event说明条件ActionNext State
L2CEVT_L2CAP_CONFIG_REQpeer 配置本地接收参数并记录回复 config rsp根据配置完成情况维持或进入 OPEN
L2CEVT_L2CAP_CONFIG_RSPpeer 回应我方配置——检查是否都完成若都完成 → CST_OPEN,否则保持
L2CEVT_L2CAP_CONFIG_RSP_NEGpeer 拒绝配置——处理失败并通知CST_CLOSED
状态:CST_OPEN
Event说明条件ActionNext State
L2CEVT_L2CAP_DISCONNECT_REQpeer 请求断开——回复 disconnect rspCST_CLOSED
L2CEVT_L2CA_DISCONNECT_REQ上层请求断开——发送 disconnect reqCST_W4_L2CAP_DISCONNECT_RSP
L2CEVT_L2CAP_DATApeer 数据到达——调用上层回调保持
状态:CST_W4_L2CAP_DISCONNECT_RSP
Event说明条件ActionNext State
L2CEVT_L2CAP_DISCONNECT_RSPpeer 回复断开成功——通知上层CST_CLOSED
状态:CST_W4_L2CA_DISCONNECT_RSP
Event说明条件ActionNext State
L2CEVT_L2CA_DISCONNECT_RSP上层确认断开——清理资源CST_CLOSED

2. Credit-based L2CAP 状态机分析

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

3. Credit-based Reconfig 状态

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

4. 小结

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

相关文章:

  • 【MobaXterm】---修改 MobaXterm 终端 默认字体和大小 保真
  • QSPI flash xip模式运行
  • 四、Python编程基础04
  • 《宝可梦明耀之星》正式登陆中国大陆!4月15日起陆续上市!
  • 母婴店商城小程序制作哪家强?告别传统经营,拥抱线上新机遇
  • TypeScript 开发实战:如何安全替换字符串中的关键字
  • 阿里云99机器总是宕机,实测还是磁盘性能差
  • 多路转接epoll原理详解
  • 应用信息1.13.0发布
  • verilog和system verilog常用数据类型以及常量汇总
  • SVN钩子脚本获取日志中文乱码解决办法
  • Android 混合开发实战:统一 View 与 Compose 的浅色/深色主题方案
  • 嵌入模型(Embedding Models)原理详解:从Word2Vec到BERT的技术演进
  • MyBatis操作数据库---从入门到理解
  • 硬件工程师面试常见问题(7)
  • LeetCode-Hot100
  • CentOS 7 磁盘分区详细教程
  • 【框架学习】Spring AI-功能学习与实战(一)
  • SpringBoot | 构建客户树及其关联关系的设计思路和实践Demo
  • 【CAPL实战:以太网】对IPv4报文的Payload部分进行分片并创建分片包
  • 美总统批准海底采矿,外交部:擅自授权开发损害国际社会共同利益
  • 我国首次发布铁线礁、牛轭礁珊瑚礁“体检”报告,菲炮制言论毫无科学和事实依据
  • 影子调查丨掉落的喷淋头:太原一7天酒店加盟店消防设施造假迷局
  • 期待会师!神二十与空间站完成对接
  • 夜读丨修车与“不凑合”
  • 陕西全省公开征集涉企行政执法问题线索,切实减轻企业负担