蓝牙L2CAP剖析(二)

原创 专注于无线通信的蓬勃 2016-05-10 17:42

关键字:bluetooth 蓝牙协议  HCI剖析 HCI概述 HCI笔记 LMP L2CAP SDP RFCOMM 


作者:zhongjun

本着互相学习的目的,来分享此一系列的文章,欢迎转载,请注明作者,尊重版权,谢谢

文章有不当处请指正,共同学习


此系列目前这样打算:

LMP剖析 + 模拟源码:


HCI剖析 + 模拟源码:




L2CAP剖析 + 模拟源码


SDP剖析 + 模拟源码(未完成)

rfcomm剖析 + 模拟源码(未完成)

另外可以从蓝牙栏目访问我的CSDN:http://blog.csdn.net/XiaoXiaoPengBo/article/category/5998687

------------------------------------------------------------------------------------------------------------------------------------

华丽分割线,进入正题

------------------------------------------------------------------------------------------------------------------------------------


一,部分代码没有完成,只是模拟一个面向连接的从建立到断开的过程,另外,L2CAP的重点状态机和拆包重组没有模拟

bt_l2cap.h

/*
* This file is part of the L2CAP protocal.
* Data  :20160510
* Author: zhongjun
*
*/

#ifndef BT_L2CAP_H_H
#define BT_L2CAP_H_H

#include "bt_cfg.h"

#ifdef DEBUG_BT_L2CAP
#define DEBUG(x) {printf x;}
#define BT_L2CAP_DEBUG(x) DEBUG(x)
#else
#define BT_L2CAP_DEBUG(x) 
#endif
/* L2CAP CHANNEL */
#define L2CAP_SIG_CH 0x0001
#define L2CAP_CONLESS_CH 0x0002

/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU	672
#define L2CAP_DEFAULT_FLUSH_TO	0xFFFF

/* UPPER LAYER PSM */
#define SDP_PSM 0x0001
/* L2CAP command codes */
#define L2CAP_COMMAND_REJ	0x01
#define L2CAP_CONN_REQ		0x02
#define L2CAP_CONN_RSP		0x03
#define L2CAP_CONF_REQ		0x04
#define L2CAP_CONF_RSP		0x05
#define L2CAP_DISCONN_REQ	0x06
#define L2CAP_DISCONN_RSP	0x07
#define L2CAP_ECHO_REQ		0x08
#define L2CAP_ECHO_RSP		0x09
#define L2CAP_INFO_REQ		0x0a
#define L2CAP_INFO_RSP		0x0b

/* connect result */
#define L2CAP_CR_SUCCESS	0x0000
#define L2CAP_CR_PEND		0x0001
#define L2CAP_CR_NOSUP_PSM	0x0002
#define L2CAP_CR_SEC_BLOCK	0x0003
#define L2CAP_CR_NO_RSR		0x0004
/* config result */
#define L2CAP_CONF_SUCCESS	0x0000
#define L2CAP_CONF_UNACCEPT	0x0001
#define L2CAP_CONF_REJECT	0x0002
#define L2CAP_CONF_UNKNOWN	0x0003

/* config option */
#define L2CAP_CONF_MTU		0x01
#define L2CAP_CONF_FLUSH_TO	0x02
#define L2CAP_CONF_QOS		0x03
#define L2CAP_CONF_RFC		0x04
#define L2CAP_CONF_RFC_MODE	0x04

#pragma pack(1)
/* L2CAP structures hdr*/
typedef struct {
	uint16_t	len;
	uint16_t	cid;
}L2CAP_PDU_HDR_Format;

typedef struct {
	L2CAP_PDU_HDR_Format sig_hdr;
	uint8_t		code;
	uint8_t		ident;
	uint16_t	len;
}L2CAP_SIG_HDR_Format;

/* L2CAP structures detail*/
typedef struct {
	L2CAP_SIG_HDR_Format com_hdr;
	uint16_t	psm;
	uint16_t	scid;
}L2CAP_Con_Req;

typedef struct {
	L2CAP_SIG_HDR_Format com_hdr;
	uint16_t	dst_cid;
	uint16_t	src_cid;
	uint16_t	result;
	uint16_t	status;
}L2CAP_Con_Rsp;

typedef struct {
	L2CAP_SIG_HDR_Format com_hdr;
	uint16_t	dst_cid;
	uint16_t	flags;
	uint8_t		data[0];
}L2CAP_Conf_Req;

typedef struct {
	L2CAP_SIG_HDR_Format com_hdr;
	uint16_t	src_cid;
	uint16_t	flags;
	uint16_t	result;
	uint8_t		data[0];
}L2CAP_Conf_Rsp;

typedef struct {
	L2CAP_PDU_HDR_Format com_hdr;
	uint8_t		data[0];
}L2CAP_Upper_Layer_data_Format;

typedef struct {
	L2CAP_SIG_HDR_Format com_hdr;
	uint16_t	dcid;
	uint16_t	scid;
}L2CAP_Discon_req;

typedef struct {
	L2CAP_SIG_HDR_Format com_hdr;
	uint16_t	dcid;
	uint16_t	scid;
}L2CAP_Discon_rsp;
#pragma pack()

/* API */
/* send pdu */
int L2CAP_Send_SIG_Con_Req(uint8_t ident,uint16_t psm,uint16_t scid);
int L2CAP_Send_SIG_Conf_Req(uint8_t ident,uint16_t dcid,uint16_t flags,uint8_t *conf_opt,uint8_t opt_len);
int L2CAP_Send_Upper_Layer_data(uint16_t cid,uint8_t *data,uint16_t length);
int L2CAP_Send_SIG_Discon_Req(uint8_t ident,uint16_t dcid,uint16_t scid);
int L2CAP_Send_PDU(uint8_t *PDU,uint32_t length);

/* reve pdu */
int L2CAP_Parse_PDU(uint8_t *PDU,uint32_t length);
int L2CAP_Parse_SIG_Con_Rsp_PDU(uint8_t *PDU,uint32_t length);
int L2CAP_Parse_SIG_Conf_Rsp_PDU(uint8_t *PDU,uint32_t length);
int L2CAP_Parse_SIG_Discon_Rsp_PDU(uint8_t *PDU,uint32_t length);
#endif

bt_l2cap.c

#include "bt_l2cap.h"

int L2CAP_Send_SIG_Con_Req(uint8_t ident,uint16_t psm,uint16_t scid)
{
	L2CAP_Con_Req PDU;
	PDU.com_hdr.sig_hdr.cid = L2CAP_SIG_CH;
	PDU.com_hdr.sig_hdr.len = sizeof(L2CAP_Con_Req) - sizeof(L2CAP_PDU_HDR_Format);

	PDU.com_hdr.code = L2CAP_CONN_REQ;
	PDU.com_hdr.ident = ident;
	PDU.com_hdr.len = sizeof(L2CAP_Con_Req) - sizeof(L2CAP_SIG_HDR_Format);

	PDU.psm = psm;
	PDU.scid = scid;
	L2CAP_Send_PDU((uint8_t *)&PDU,sizeof(L2CAP_Con_Req));
}
int L2CAP_Send_SIG_Conf_Req(uint8_t ident,uint16_t dcid,uint16_t flags,uint8_t *conf_opt,uint8_t opt_len)
{
	L2CAP_Conf_Req *PDU = (L2CAP_Conf_Req *)malloc(sizeof(L2CAP_Conf_Req) + opt_len);
	(PDU->com_hdr).sig_hdr.cid = L2CAP_SIG_CH;
	(PDU->com_hdr).sig_hdr.len = sizeof(L2CAP_Conf_Req) - sizeof(L2CAP_PDU_HDR_Format) + opt_len;
	
	(PDU->com_hdr).code = L2CAP_CONF_REQ;
	(PDU->com_hdr).ident = ident;
	(PDU->com_hdr).len = sizeof(L2CAP_Conf_Req) - sizeof(L2CAP_SIG_HDR_Format) + opt_len;
	
	PDU->dst_cid = dcid;
	PDU->flags = flags;
	memcpy(PDU->data,conf_opt,opt_len);

	L2CAP_Send_PDU(PDU,sizeof(L2CAP_Conf_Req) + opt_len);
}

int L2CAP_Send_Upper_Layer_data(uint16_t cid,uint8_t *data,uint16_t length)
{
	L2CAP_Upper_Layer_data_Format *PDU = (L2CAP_Upper_Layer_data_Format *)malloc(sizeof(L2CAP_Upper_Layer_data_Format) + length);
	(PDU->com_hdr).cid = cid;
	(PDU->com_hdr).len = sizeof(L2CAP_Upper_Layer_data_Format) + length;

	memcpy(PDU->data,data,length);	
	L2CAP_Send_PDU(PDU,sizeof(L2CAP_Upper_Layer_data_Format) + length);
}

int L2CAP_Send_SIG_Discon_Req(uint8_t ident,uint16_t dcid,uint16_t scid)
{
	L2CAP_Discon_req PDU;
	PDU.com_hdr.sig_hdr.cid = L2CAP_SIG_CH;
	PDU.com_hdr.sig_hdr.len = sizeof(L2CAP_Discon_req) - sizeof(L2CAP_PDU_HDR_Format);
	
	PDU.com_hdr.code = L2CAP_DISCONN_REQ;
	PDU.com_hdr.ident = ident;
	PDU.com_hdr.len = sizeof(L2CAP_Con_Req) - sizeof(L2CAP_SIG_HDR_Format);
	
	PDU.dcid = dcid;
	PDU.scid = scid;
	L2CAP_Send_PDU((uint8_t *)&PDU,sizeof(L2CAP_Con_Req));
}
int L2CAP_Send_PDU(uint8_t *PDU,uint32_t length)
{
	int index = 0;
	BT_L2CAP_DEBUG((" >> Send L2CAP REQ PDU:"));
	for(index = 0; index < length; index++)
	{
		BT_L2CAP_DEBUG(("0x%02x ",PDU[index]));
	}
	BT_L2CAP_DEBUG(("\n"));
}


int L2CAP_Parse_PDU(uint8_t *PDU,uint32_t length)
{
	L2CAP_PDU_HDR_Format *TMP_PDU = (L2CAP_PDU_HDR_Format *)PDU;
	if((TMP_PDU->cid) == L2CAP_SIG_CH)
	{
		uint8_t tmp_code;
		L2CAP_SIG_HDR_Format *pdu = (L2CAP_SIG_HDR_Format *)PDU;
		BT_L2CAP_DEBUG(("SIG PDU\n"));		
		tmp_code = pdu->code;
		switch(tmp_code)
		{
			case L2CAP_CONN_RSP:
			{
				BT_L2CAP_DEBUG(("L2CAP_CONN_RSP\n"));
				L2CAP_Parse_SIG_Con_Rsp_PDU(PDU,length);
				break;
			}
			case L2CAP_CONF_RSP:
			{
				BT_L2CAP_DEBUG(("L2CAP_CONF_RSP\n"));
				L2CAP_Parse_SIG_Conf_Rsp_PDU(PDU,length);
				break;
			}
			case L2CAP_DISCONN_RSP:
			{
				BT_L2CAP_DEBUG(("L2CAP_DISCONN_RSP\n"));
				L2CAP_Parse_SIG_Discon_Rsp_PDU(PDU,length);
				break;
			}
			default:
			{
				break;
			}
		}
		
	}
	else
	{
		//TODO
	}
}

int L2CAP_Parse_SIG_Con_Rsp_PDU(uint8_t *PDU,uint32_t length)
{
	L2CAP_Con_Rsp *tmp_pdu = (L2CAP_Con_Rsp *)PDU;
	if(tmp_pdu->result == L2CAP_CR_SUCCESS)
	{
		BT_L2CAP_DEBUG(("connect successful\n"));
	}
	else if(tmp_pdu->result == L2CAP_CR_PEND)
	{
		BT_L2CAP_DEBUG(("connect pending\n"));
	}
}

int L2CAP_Parse_SIG_Conf_Rsp_PDU(uint8_t *PDU,uint32_t length)
{
	L2CAP_Conf_Rsp *tmp_pdu = (L2CAP_Conf_Rsp *)PDU;
	if(tmp_pdu->result == L2CAP_CONF_SUCCESS)
	{
		BT_L2CAP_DEBUG(("config successful\n"));
	}
	else if(tmp_pdu->result == L2CAP_CONF_UNACCEPT)
	{
		BT_L2CAP_DEBUG(("config unaccept\n"));
	}
}

int L2CAP_Parse_SIG_Discon_Rsp_PDU(uint8_t *PDU,uint32_t length)
{
	
}

bt_cfg.h

#ifndef BT_LMP_CFG_H
#define BT_LMP_CFG_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEBUG_BT_L2CAP

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;



typedef  char int8_t;
typedef  short int16_t;
typedef  int int32_t;

#undef NULL 
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif

#endif

main.c

#include <stdio.h>
#include "bt_l2cap.h"

int main()
{
	uint8_t con_rsp_pdu[] = {0x0C,0x00,0x01,0x00,0x03,0x79,0x08,0x00,0x06,0x08,0x40,0x00,0x00,0x00,0x00,0x00}; 
	uint8_t conf_option[] = {0x01,0x02,0xF4,0x01,0x02,0x02,0xFF,0xFF};
	uint8_t conf_rsp_pdu[] = {0x0E,0x00,0x01,0x00,0x05,0x7A,0x0A,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0xF4,0x01};
	uint8_t upper_layer_data[] = {0x1,0x1,0x1,0x1,0x1,0x1};
	L2CAP_Send_SIG_Con_Req(0x79,SDP_PSM,0x40);
	L2CAP_Parse_PDU(con_rsp_pdu,sizeof(con_rsp_pdu));

	L2CAP_Send_SIG_Conf_Req(0x79,0x0806,0x0,conf_option,sizeof(conf_option));
	L2CAP_Parse_PDU(conf_rsp_pdu,sizeof(conf_rsp_pdu));

	L2CAP_Send_Upper_Layer_data(0x40,upper_layer_data,sizeof(upper_layer_data));

	L2CAP_Send_SIG_Discon_Req(0x79,0x40,0x0806);
}


专注于无线通信的蓬勃 朝气蓬勃——不积跬步 无以至千里, 不积小流 无以成江海
评论 (0)
  • 在CAN总线分析软件领域,当CANoe不再是唯一选择时,虹科PCAN-Explorer 6软件成为了一个有竞争力的解决方案。在现代工业控制和汽车领域,CAN总线分析软件的重要性不言而喻。随着技术的进步和市场需求的多样化,单一的解决方案已无法满足所有用户的需求。正是在这样的背景下,虹科PCAN-Explorer 6软件以其独特的模块化设计和灵活的功能扩展,为CAN总线分析领域带来了新的选择和可能性。本文将深入探讨虹科PCAN-Explorer 6软件如何以其创新的模块化插件策略,提供定制化的功能选
    虹科汽车智能互联 2025-04-28 16:00 187浏览
  • 随着电子元器件的快速发展,导致各种常见的贴片电阻元器件也越来越小,给我们分辨也就变得越来越难,下面就由smt贴片加工厂_安徽英特丽就来告诉大家如何分辨的SMT贴片元器件。先来看看贴片电感和贴片电容的区分:(1)看颜色(黑色)——一般黑色都是贴片电感。贴片电容只有勇于精密设备中的贴片钽电容才是黑色的,其他普通贴片电容基本都不是黑色的。(2)看型号标码——贴片电感以L开头,贴片电容以C开头。从外形是圆形初步判断应为电感,测量两端电阻为零点几欧,则为电感。(3)检测——贴片电感一般阻值小,更没有“充放
    贴片加工小安 2025-04-29 14:59 228浏览
  • 你是不是也有在公共场合被偷看手机或笔电的经验呢?科技时代下,不少现代人的各式机密数据都在手机、平板或是笔电等可携式的3C产品上处理,若是经常性地需要在公共场合使用,不管是工作上的机密文件,或是重要的个人信息等,民众都有防窃防盗意识,为了避免他人窥探内容,都会选择使用「防窥保护贴片」,以防止数据外泄。现今市面上「防窥保护贴」、「防窥片」、「屏幕防窥膜」等产品就是这种目的下产物 (以下简称防窥片)!防窥片功能与常见问题解析首先,防窥片最主要的功能就是用来防止他人窥视屏幕上的隐私信息,它是利用百叶窗的
    百佳泰测试实验室 2025-04-30 13:28 334浏览
  • 4月22日下午,备受瞩目的飞凌嵌入式「2025嵌入式及边缘AI技术论坛」在深圳深铁皇冠假日酒店盛大举行,此次活动邀请到了200余位嵌入式技术领域的技术专家、企业代表和工程师用户,共享嵌入式及边缘AI技术的盛宴!1、精彩纷呈的展区产品及方案展区是本场活动的第一场重头戏,从硬件产品到软件系统,从企业级应用到高校教学应用,都吸引了现场来宾的驻足观看和交流讨论。全产品矩阵展区展示了飞凌嵌入式丰富的产品线,从嵌入式板卡到工控机,从进口芯片平台到全国产平台,无不体现出飞凌嵌入式在嵌入式主控设备研发设计方面的
    飞凌嵌入式 2025-04-28 14:43 157浏览
  • 文/郭楚妤编辑/cc孙聪颖‍越来越多的企业开始蚕食动力电池市场,行业“去宁王化”态势逐渐明显。随着这种趋势的加强,打开新的市场对于宁德时代而言至关重要。“我们不希望被定义为电池的制造者,而是希望把自己称作新能源产业的开拓者。”4月21日,在宁德时代举行的“超级科技日”发布会上,宁德时代掌门人曾毓群如是说。随着宁德时代核心新品骁遥双核电池的发布,其搭载的“电电增程”技术也走进业界视野。除此之外,经过近3年试水,宁德时代在换电业务上重资加码。曾毓群认为换电是一个重资产、高投入、长周期的产业,涉及的利
    华尔街科技眼 2025-04-28 21:55 171浏览
  • 一、gao效冷却与控温机制‌1、‌冷媒流动设计‌采用低压液氮(或液氦)通过毛细管路导入蒸发器,蒸汽喷射至样品腔实现快速冷却,冷却效率高(室温至80K约20分钟,至4.2K约30分钟)。通过控温仪动态调节蒸发器加热功率,结合温度传感器(如PT100铂电阻或Cernox磁场不敏感传感器),实现±0.01K的高精度温度稳定性。2、‌宽温区覆盖与扩展性‌标准温区为80K-325K,通过降压选件可将下限延伸至65K(液氮模式)或4K(液氦模式)。可选配475K高温模块,满足材料在ji端温度下的性能测试需求
    锦正茂科技 2025-04-30 13:08 262浏览
  • 文/Leon编辑/cc孙聪颖‍2023年,厨电行业在相对平稳的市场环境中迎来温和复苏,看似为行业增长积蓄势能。带着对市场向好的预期,2024 年初,老板电器副董事长兼总经理任富佳为企业定下双位数增长目标。然而现实与预期相悖,过去一年,这家老牌厨电企业不仅未能达成业绩目标,曾提出的“三年再造一个老板电器”愿景,也因市场下行压力面临落空风险。作为“企二代”管理者,任富佳在掌舵企业穿越市场周期的过程中,正面临着前所未有的挑战。4月29日,老板电器(002508.SZ)发布了2024年年度报告及2025
    华尔街科技眼 2025-04-30 12:40 213浏览
  • 贞光科技代理品牌紫光国芯的车规级LPDDR4内存正成为智能驾驶舱的核心选择。在汽车电子国产化浪潮中,其产品以宽温域稳定工作能力、优异电磁兼容性和超长使用寿命赢得市场认可。紫光国芯不仅确保供应链安全可控,还提供专业本地技术支持。面向未来,紫光国芯正研发LPDDR5车规级产品,将以更高带宽、更低功耗支持汽车智能化发展。随着智能网联汽车的迅猛发展,智能驾驶舱作为人机交互的核心载体,对处理器和存储器的性能与可靠性提出了更高要求。在汽车电子国产化浪潮中,贞光科技代理品牌紫光国芯的车规级LPDDR4内存凭借
    贞光科技 2025-04-28 16:52 265浏览
  • 网约车,真的“饱和”了?近日,网约车市场的 “饱和” 话题再度引发热议。多地陆续发布网约车风险预警,提醒从业者谨慎入局,这背后究竟隐藏着怎样的市场现状呢?从数据来看,网约车市场的“过剩”现象已愈发明显。以东莞为例,截至2024年12月底,全市网约车数量超过5.77万辆,考取网约车驾驶员证的人数更是超过13.48万人。随着司机数量的不断攀升,订单量却未能同步增长,导致单车日均接单量和营收双双下降。2024年下半年,东莞网约出租车单车日均订单量约10.5单,而单车日均营收也不容乐
    用户1742991715177 2025-04-29 18:28 227浏览
  • 在智能硬件设备趋向微型化的背景下,语音芯片方案厂商针对小体积设备开发了多款超小型语音芯片方案,其中WTV系列和WT2003H系列凭借其QFN封装设计、高性能与高集成度,成为微型设备语音方案的理想选择。以下从封装特性、功能优势及典型应用场景三个方面进行详细介绍。一、超小体积封装:QFN技术的核心优势WTV系列与WT2003H系列均提供QFN封装(如QFN32,尺寸为4×4mm),这种封装形式具有以下特点:体积紧凑:QFN封装通过减少引脚间距和优化内部结构,显著缩小芯片体积,适用于智能门铃、穿戴设备
    广州唯创电子 2025-04-30 09:02 245浏览
  • 浪潮之上:智能时代的觉醒    近日参加了一场课题的答辩,这是医疗人工智能揭榜挂帅的国家项目的地区考场,参与者众多,围绕着医疗健康的主题,八仙过海各显神通,百花齐放。   中国大地正在发生着激动人心的场景:深圳前海深港人工智能算力中心高速运转的液冷服务器,武汉马路上自动驾驶出租车穿行的智慧道路,机器人参与北京的马拉松竞赛。从中央到地方,人工智能相关政策和消息如雨后春笋般不断出台,数字中国的建设图景正在智能浪潮中徐徐展开,战略布局如同围棋
    广州铁金刚 2025-04-30 15:24 193浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦