【android bluetooth 协议分析 06】【l2cap详解 6】【L2CA_Register函数解析】
L2CA_Register()
函数的实现,它的作用是:
注册一个 L2CAP 服务(基于 PSM)并设置回调函数、MTU、安全等级、传输模式等信息,供 L2CAP 层用于处理连接、配置、数据、断开等事件。
1. L2CA_Register2/L2CA_Register
参数 | 说明 |
---|---|
psm | Protocol/Service Multiplexer,协议服务标识符(A2DP 信令用 0x0019) |
p_cb_info | 包含各种回调函数的结构体(连接、配置、数据、断开等) |
enable_snoop | 是否开启抓包(snoop log) |
p_ertm_info | 指定可靠传输模式(如 ERTM/FCR)相关配置 |
my_mtu | 本地最大传输单元 |
required_remote_mtu | 期望远端 MTU |
sec_level | 安全等级(认证、加密等) |
// system/stack/l2cap/l2c_api.cc
uint16_t L2CA_Register2(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,uint16_t my_mtu, uint16_t required_remote_mtu,uint16_t sec_level) {auto ret = L2CA_Register(psm, p_cb_info, enable_snoop, p_ertm_info, my_mtu,required_remote_mtu, sec_level);BTM_SetSecurityLevel(false, "", 0, sec_level, psm, 0, 0);return ret;
}uint16_t L2CA_Register(uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info,bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info,uint16_t my_mtu, uint16_t required_remote_mtu,uint16_t sec_level) {// 1. 优先判断是否启用新版 GD L2CAP, 我们暂时没有开启 GD L2cap, 暂时不分析if (bluetooth::shim::is_gd_l2cap_enabled()) {// 判断是否启用了新版 GD L2CAP(Google's new architecture)。// 如果启用:调用新的实现,退出旧逻辑return bluetooth::shim::L2CA_Register(psm, p_cb_info, enable_snoop,p_ertm_info, my_mtu,required_remote_mtu, sec_level);}/* 2. 检查必要的回调函数是否提供必须提供以下回调,否则无法注册服务: 就像你开店前必须配好收银台、接待员、保安,否则不让开业。1. pL2CA_ConfigCfm_Cb2. pL2CA_DataInd_Cb3. pL2CA_DisconnectInd_Cb*/const bool config_cfm_cb = (p_cb_info.pL2CA_ConfigCfm_Cb != nullptr);const bool config_ind_cb = (p_cb_info.pL2CA_ConfigInd_Cb != nullptr);const bool data_ind_cb = (p_cb_info.pL2CA_DataInd_Cb != nullptr);const bool disconnect_ind_cb = (p_cb_info.pL2CA_DisconnectInd_Cb != nullptr);tL2C_RCB* p_rcb;uint16_t vpsm = psm;/* Verify that the required callback info has been filled in** Note: Connection callbacks are required but not checked** for here because it is possible to be only a client** or only a server.*/if (!config_cfm_cb || !data_ind_cb || !disconnect_ind_cb) {LOG_ERROR("L2CAP - no cb registering PSM: 0x%04x cfg_cfm:%u cfg_ind:%u"" data_ind:%u discon_int:%u",psm, config_cfm_cb, config_ind_cb, data_ind_cb, disconnect_ind_cb);return (0);}// 3. 验证 PSM 是否有效, 确保 PSM 合法(不能是保留字段、非法值)。/* Verify PSM is valid */if (L2C_INVALID_PSM(psm)) {LOG_ERROR("L2CAP - invalid PSM value, PSM: 0x%04x", psm);return (0);}// 4. 为客户端注册分配虚拟 PSM(vPSM)/* Check if this is a registration for an outgoing-only connection to *//* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */// 如果没有设置 pL2CA_ConnectInd_Cb(表示不监听入站连接),L2CAP 会分配一个虚拟 PSM。// 原因是:服务端监听必须是静态 PSM,但客户端可以使用动态编号。if ((psm >= 0x1001) && (p_cb_info.pL2CA_ConnectInd_Cb == NULL)) {// // 说明仅用于客户端,不处理 远端主动连接for (vpsm = 0x1002; vpsm < 0x8000; vpsm += 2) {p_rcb = l2cu_find_rcb_by_psm(vpsm);if (p_rcb == NULL) break;}LOG_DEBUG("L2CAP - Real PSM: 0x%04x Virtual PSM: 0x%04x", psm, vpsm);}// 5. 查找或创建 RCB(Registration Control Block)/* If registration block already there, just overwrite it */p_rcb = l2cu_find_rcb_by_psm(vpsm); // 若已存在注册,则复用;否则分配一个新的注册块。if (p_rcb == NULL) {p_rcb = l2cu_allocate_rcb(vpsm);if (p_rcb == NULL) {LOG_WARN("L2CAP - no RCB available, PSM: 0x%04x vPSM: 0x%04x", psm,vpsm);return (0);}}// 6. 填充 RCB 参数, 存储服务所需的参数。LOG_INFO("L2CAP Registered service classic PSM: 0x%04x", psm);p_rcb->log_packets = enable_snoop;p_rcb->api = p_cb_info;p_rcb->real_psm = psm;p_rcb->ertm_info = p_ertm_info == nullptr? tL2CAP_ERTM_INFO{L2CAP_FCR_BASIC_MODE}: *p_ertm_info; // 如果没有提供 p_ertm_info,默认使用 Basic Mode(非可靠传输)。p_rcb->my_mtu = my_mtu;p_rcb->required_remote_mtu =std::max<uint16_t>(required_remote_mtu, L2CAP_MIN_MTU);// 7. 返回注册成功的(虚拟)PSM, 返回注册成功后使用的 PSM,可能是原始的,也可能是自动分配的虚拟 PSM。return (vpsm);
}
tL2CAP_APPL_INFO
// 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;
回调函数指针 | 回调触发时机 | 说明 |
---|---|---|
pL2CA_ConnectInd_Cb | 当远端设备尝试发起 L2CAP 连接请求时 | 被动连接接收回调(如手机发起连接到车机时) |
pL2CA_ConnectCfm_Cb | 本地设备主动发起连接后,远端确认连接完成时 | 主动连接的确认回调 |
pL2CA_ConfigInd_Cb | 收到远端的配置请求(如 MTU、流控参数)时 | 对方提出配置要求,等待本地回应 |
pL2CA_ConfigCfm_Cb | 本地发送配置请求后,收到远端的配置确认时 | 对方接受了本地配置 |
pL2CA_DisconnectInd_Cb | 对端发起断开连接时 | 被动断开通知 |
pL2CA_DisconnectCfm_Cb | 本地请求断开连接后,对端确认断开完成时 | 主动断开完成确认 |
pL2CA_DataInd_Cb | 收到对端通过 L2CAP 发送的数据时 | 接收数据,例如 AVDTP 信令或媒体数据 |
pL2CA_CongestionStatus_Cb | L2CAP 发送队列从阻塞变为可用或反之时 | 通知应用当前通道是否阻塞(拥塞控制) |
pL2CA_TxComplete_Cb | 某个数据包成功发送完毕后 | 数据发送完成(带缓冲机制时常用) |
pL2CA_Error_Cb | L2CAP 层出现错误(如参数非法、状态错误)时 | 用于调试和异常处理 |
pL2CA_CreditBasedConnectInd_Cb | 收到基于 Credit 的连接请求时 | 用于 LE 信道(如 LE CoC 模式) |
pL2CA_CreditBasedConnectCfm_Cb | 本地发起 Credit Based 连接后,收到对端确认 | 与 LE CoC 建立流程对应 |
pL2CA_CreditBasedReconfigCompleted_Cb | Credit Based 信道重新配置完成时 | 支持 MTU 或 MPS 改变 |
pL2CA_CreditBasedCollisionInd_Cb | 发现本地和远端同时发起 LE CoC 信道连接时 | 用于处理冲突连接的场景 |
-
把 L2CAP 通道看作打电话,来理解这些回调调用时机:
-
pL2CA_ConnectInd_Cb
就像别人打电话过来(你接电话)。 -
pL2CA_ConnectCfm_Cb
是你打电话给别人,对方接通了。 -
pL2CA_ConfigInd/Cfm_Cb
是双方通话前确认通话方式(语音、视频、网络质量等)。 -
pL2CA_DataInd_Cb
是你在通话中听到的内容。 -
pL2CA_DisconnectInd/Cfm_Cb
是挂电话的通知。 -
pL2CA_CreditBased...
是另一种“对讲机”式的沟通方式(BLE CoC),双方轮流说话,且有限次数(credit)。
-
相关文章:
【android bluetooth 协议分析 06】【l2cap详解 6】【L2CA_Register函数解析】
L2CA_Register() 函数的实现,它的作用是: 注册一个 L2CAP 服务(基于 PSM)并设置回调函数、MTU、安全等级、传输模式等信息,供 L2CAP 层用于处理连接、配置、数据、断开等事件。 1. L2CA_Register2/L2CA_Register 参数…...

【MFC】 VS2022打开低版本的MFC,双击.rc文件,DIalog加载失败,页面弹窗fatal error RC***:cannot open*****
打开以前的MFC示例报错,打开VS2019的实例以及更早VS版本的实例都一样,打不开,还报错; 错误 MSB8041 此项目需要 MFC 库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。 GxCameraEvents_VS2015 C:\P…...

Centos9 安装 nginx 及配置
1. 安装nginx 安装依赖软件,安装之前可以看一下是否已经安装过以下软件,dnf list installed | grep zlib dnf install gcc-c dnf install zlib dnf install pcre pcre-devel dnf install openssl openssl-devel下载nginx,这里是下载到opt文…...

使用Handsontable实现动态表格和下载表格
1.效果 2.实现代码 首先要加载Handsontable,在示例中我是cdn的方式引入的,vue的话需要下载插件 let hot null;var exportPlugin null;function showHandsontable(param) {const container document.getElementById("hot-container");// 如果…...

Action:Update your application‘s configuration
在使用Maven项目时,有一个报错信息是:Update your applications configuration 这类问题,就是我们的application.yml文件 或者 application.properties文件 内容哪里写错了 最有可能就是对齐方式有问题...

【计算机网络】IP地址
IPv4 五类地址 1.0.0.0 ~ 126.255.255.255A类子网8位,主机24位128.0.0.0 ~ 191.255.255.255B类子网16位,主机16位192.0.0.0 ~ 223.255.255.255C类子网24位,主机8位224.0.0.0 ~ 239.255.255.255D类不分网络地址和主机地址,作为组播…...

Rundeck 介绍及安装:自动化调度与执行工具
Rundeck介绍 概述:Rundeck 是什么? Rundeck 是一款开源的自动化调度和任务执行工具,专为运维场景设计,帮助工程师通过统一的平台管理和执行跨系统、跨节点的任务。它由 PagerDuty 维护(2016 年收购)&#…...

vue element使用el-table时,切换tab,table表格列项发生错位问题
展示问题 问题描述:使用el-table的fixed"right"属性后,如果切换tab时,回出现最后一列错误的问题 官网提供解决方法:doLayout 需要注意的事项:我这里是通过组件使用的table组件,涉及多层组件封装…...

第十二章 Python语言-大数据分析PySpark(终)
目录 一. PySpark前言介绍 二.基础准备 三.数据输入 四.数据计算 1.数据计算-map方法 2.数据计算-flatMap算子 3.数据计算-reduceByKey方法 4.数据计算-filter方法 5.数据计算-distinct方法 6.数据计算-sortBy方法 五.数据输出 1.输出Python对象 (1&am…...
【RedisLockRegistry】分布式锁
RedisLockRegistry分布式锁 介绍 RedisLockRegistry是Spring框架提供的一种分布式锁机制,它基于Redis来实现对共享资源的保护,防止多个进程同时对同一资源进行修改,从而避免数据不一致或其他问题 基本原理 RedisLockRegistry通过Redi…...
leetcode-排序
排序 面试题 01.01. 判定字符是否唯一 题目 实现一个算法,确定一个字符串 s 的所有字符是否全都不同。 示例 1: 输入: s "leetcode" 输出: false 示例 2: 输入: s "abc" 输出: true限制: 0 < len(s) &…...

AD相同网络的铜皮和导线连接不上
出现这样的情况是不是很烦恼,明明是相同的网络连接不上????? 直接修改铜皮属性(选择所有相同这个选项) 这样就可以连接上了...

keil修改字体无效,修改字体为“微软雅黑”方法
在网上下载了微软雅黑字体,微软雅黑参考下载链接 结果在Edit->Configuration中找不到这个字体 这个时候可以在keil的安装目录中找到UV4/global.prop文件 用记事本打开它进行编辑,把字体名字改成微软雅黑 重新打开keil就发现字体成功修改了。 这个…...

【网络编程】从零开始彻底了解网络编程(三)
本篇博客给大家带来的是网络编程的知识点. 🐎文章专栏: JavaEE初阶 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺便进步 TCP流…...

NVIDIA --- 端到端自动驾驶
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、传统驾驶模型二、NVIDIA的端到端驾驶模型1.基本模型2.自查讯向量3.通用框架 总结 前言 端到端自动驾驶指的是系统接收来自摄像头雷达和激光雷达的原始传感…...
关于在Springboot中设置时间格式问题
目录 1-设置全局时间格式1.Date类型的时间2.JDK8时间3.使Date类和JDK8时间类统统格式化时间 2-关于DateTimeFormat注解 1-设置全局时间格式 1.Date类型的时间 对于老项目来说,springboot中许多类使用的是Date类型的时间,没有用到LocalDateTime等JDK8时…...

CSRF请求伪造
该漏洞主要是关乎于用户,告诫用户不可乱点击链接,提升自我防范,才能不落入Hacker布置的陷阱! 1. cookie与session 简单理解一下两者作用 1.1. 🍪 Cookie:就像超市的会员卡 存储位置:你钱包里…...

(一)单机架构、应用数据分离架构、应用服务集群架构
文章目录 明确为什么要学习架构的演进单机架构什么是单机架构单机架构的模型单机架构的优缺点优点缺点 单机架构的技术案例 应用数据分离架构什么是应用数据分离架构架构模型应用数据分离架构的优缺点优点缺点 技术案例 应用服务集群架构什么是应用服务集群架构架构模型应用服务…...

Python数据分析案例72——基于股吧评论数据的情感分析和主题建模(LDA)
背景 好久没更新了,最近忙其他去了。最近股市波动太大,看了不少新闻的评论。抽空写了个股吧评论数据的LDA建模和情感分析,简单写到博客上来更新一下。 数据来源 上证指数(000001)股吧_上证指数怎么样_分析讨论社区— 数据来源上述网站的东…...
Git分支管理方案
成都众望智慧有限公司Git分支管理方案 采用 轻量级Git Flow 敏捷版本控制策略,在保证稳定性的同时提升开发效率。以下是优化后的方案: 1. 精简分支模型(相比6-8人团队减少分支层级) 分支类型作用生命周期devops生产环境代码&am…...

力扣-160.相交链表
题目描述 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返…...
c语言中float和double 类型的区别
在 C 语言里,float和double都用于表示浮点数,不过二者在多个方面存在差异,下面为你详细介绍: 1. 存储空间大小 在 C 语言中,数据类型所占用的存储空间大小通常与编译器和系统架构有关,但一般来说…...

【C++】特殊类的设计、单例模式以及Cpp类型转换
📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🅒 C 语言 | 🌐 计算机网络 上篇文章: C 智能指针使用,以及shared_ptr编写 下篇文章ÿ…...

050_基于springboot的音乐网站
一、系统架构 前端:vue | element-ui | html | jquery | css | ajax 后端:springboot | mybatis 环境:jdk1.8 | mysql | maven | nodejs | idea 二、代码及数据 三、功能介绍 01. web端-注册 02. web端-登录 03. web…...
全局变量Msg.sender
msg.sender 在 Solidity 中,有一些全局变量可以被所有函数调用。 其中一个就是 msg.sender,它指的是当前调用者(或智能合约)的 address。 注意:在 Solidity 中,功能执行始终需要从外部调用者开始。 一个合…...

【论文阅读】平滑量化:对大型语言模型进行准确高效的训练后量化
论文题目:SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models 论文地址:[2211.10438] SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models 代码地址:http…...

【资料推荐】LVDS Owner’s Manual
一份年代有些久远的技术资料,但是内容全面且经典! 本用户手册提供了很多有用的信息,首先简要概述了三种最常见的高速接口技术:LVDS(包括B-LVDS和M-LVDS)、CML和LVPECL,并对其相应的特性进行了分…...

ARM Cortex-M (STM32)如何调试HardFault
目录 步骤 1: 实现一个有效的 HardFault 处理程序 步骤 2: 复现 HardFault 并使用调试器分析 步骤 3: 解读故障信息 步骤 4: 定位并修复源代码 HardFault 是 ARM Cortex-M 处理器中的一种异常。当处理器遇到无法处理的错误,或者配置为处理特定类型错误ÿ…...

黑马 redis面试篇笔记
redis主从 version: "3.2"services:r1:image: rediscontainer_name: r1network_mode: "host"entrypoint: ["redis-server", "--port", "7001"]r2:image: rediscontainer_name: r2network_mode: "host"entrypoint:…...
Docker端口映射与容器间DNS发现:打通服务通信的任督二脉
Docker端口映射与容器间DNS发现:打通服务通信的任督二脉 一、端口映射深度解析1.1 端口映射核心机制映射规则语法: 1.2 高级映射技巧批量端口映射:查看端口绑定状态: 二、容器间服务发现机制2.1 自定义网络DNS体系DNS解析特性&…...