安卓蓝牙协议数据包格式
安卓蓝牙协议
本文解析蓝牙传输的数据包格式,目的是对蓝牙的各个层次的协议有更深的理解。
bit数据流格式
在讲数据报文之前,必须了解协议中对数据的BIT排序的规定,在协议中规定数据包或者PDU都是以Little Endian format(小端模式)存放,也就是在内存中低地址放低字节,高地址放高字节,并且Least Significant Bit (LSB) 即最低bit位是第一个发送在空中的位。
一般情况下,Ellisys已经将收到的数据报文用两个byte的十六进制来表示,这种数据称为“HCI裸数据”,比如:
02 20 0A 00 06 00 01 00 0A 02 02 00 02 00
其中0A 00是代表HCI数据长度,因为是小端模式,所以低位数据在前,高位数据在后,即数据长度为0x000A,即10bytes。同理,06 00表示L2CAP数据长度,即6bytes。
PHY链路层的数据报文格式(LE通用数据包格式)
参考《Core_V4.2》3.2.2 LE Generic Packet Structure
上图是LE通用数据包格式,简称LE包。除了PDU和软件关系很大,其他三个都是硬件来填充的,所以我们对其他三个只是大概介绍。
1. Preamble前导码
前导码为一个字节,它有两个值分别为:10101010b和01010101b。
它是由硬件实现,也就是由硬件添加到发送包中,接收到包解析也是由硬件检测,4.0协议有说是频率同步和增益控制用,在协议中有这么一段话:
All Link Layer packets have an eight bit preamble. The preamble is used in the receiver to perform frequency synchronization, symbol timing estimation, and Automatic Gain Control (AGC) training.
那么这前导码的两个值怎么使用呢?是根据Access Address(接入地址)的最低位确定的,当接入地址的最低位为0时,那么前导码为0xAA,即10101010b,如果是1时,前导码为01010101b,目的是保证报文的前9个bit都是交替位。这些都是由硬件完成的。
2. AccessAddress接入地址
接入地址是紧跟前导码的32个bit,它分为两种类型:
- 广播接入地址
- 数据接入地址
广播接入地址是在广播数据,或是广播、扫描、发起连接时使用。数据接入地址是在连接建立之后两个设备的使用。
当控制器试图接收一个报文时,它要事先知道待接收报文的接入地址。接收机开启并调谐到正确的频率,就可以收到数据。即使附近没有发生数据的设备,接收机还是会收到背景辐射。考虑接收到纯随机噪声的概率,接收一段噪声与前导序列相符的可能性相对还是比较高的。通常,如果低功耗蓝牙接收机一直开着,每隔几分钟就能收到一个假的前导序列。因此,就需要利用接入地址以减少随机噪声造成伪报文接收的概率。
- Cyclic RedundancyCheck (CRC) 循环冗余码校验
在报文的最后3个字节是CRC校验码。CRC对整个PDU进行计算,不包括前导码和接入地址。
- PDU报文结构
PDU(Packet Data Unit)在链路层报文的位置如下(以GATT协议为例):
由上图可以看到所有的数据都是指向PHY/LL数据帧结构中的PDU(Protocol Data Unit)即协议数据单元。上图显示了广播通道PDU和数据通道PDU(物理层将40个射频通道分为37个自适应自动调频数据通道和3 个固定广播通道)。
PDU可以分为三部分,报头、长度和数据净荷,报头和长度各占一个字节。
- 广播通道的PDU格式
广播通道下的数据PDU的组成如下:
报文类型:是最低4bit,根据蓝牙的不同状态,有7种广播报文类,每种都有不同的净荷格式以及行为:
- ADV_IND——通用广播
- ADV_DIRECT_IND——定向连接广播
- ADV_NONCONN_IND——不可连接广播
- ADV_SCAN_IND——可扫描广播
- SCAN_REQ——主动扫描请求
- SCAN_RSP——主动扫描应答
- CONNECT_REQ——连接请求
发送地址(TXADD)和接收地址(RXADD):两个都是说明设备地址的类型的,当某位为“1”时表示Random Add(随机地址),当为“0”时表示Public Add(公共地址)。然而这个标记指定放在哪的地址是随机地址还是公共地址呢?在报文类型命令中对应的净荷带有6bytes地址,这些地址就紧跟在长度的后面,这些标志位就是标示这些地址类型的,如下图(Payload:有效净荷)。
图 ADV_INDPDU Payload
图 sniffer采样到的ADV_IND报文
实际上广播通道下每一个报文类型的净荷都包含有一个6字节的地址。在上图中用红色框住的内容,可知Advertising Address=0xf8543c59b281,在发送时是低字节先发送。但是CRC=0xfbfeea,CRC在发送时先发送的是高字节,最后发送的是低字节。
净荷长度:这个长度是指在PDU中的数据除去报头和长度之外的有效净荷数据的长度,注意的是这里只用到了6bit的长度,也就是说最大只能有64个字节长度,够了吗?实际上在表2-2中净荷数据上面就标明了净荷的长度最大296bits=37Bytes,也就是说在整个数据包中,在链路层真正的有效数据最大是37个字节,所以需要用也只需要6bits长度。再看图2-9可知ADV_IND的PDU实际的有效数据变为了最多37-6=31字节。
RFU:它的意思是保留将来用(RESERVED FORFUTURE USE)。
注意:在上面数据中依然是采用小端模式和低bit在左边,高bit在右边。也就是在报头中,报文类型的4个bit是在这个字节的低4bit。
- 数据通道的PDU格式
数据通道下的数据PDU的组成如下:
直接引用4.2规范中的图片,解释各字段的意思,如下图:
图 Data channel PDU Header field
在数据报文中有Message Integrity Check (MIC)信息完整性检测。为了保证数据的正确性,它占有32bit即4个字节,这涉及到加密操作,它是用虚线表示的,也就是不一定要有,因为并不是一定要加密才能工作。
注意:这里的有效净荷数据长度最大只有216字节了,也就是27个字节,加上MIC的4个字节,也才31字节,那么对比PDU报文格式还少了6字节,去哪了?实际上协议规范就是这么规定的,在广播通道这6个字节是设备地址(比如上面ADV_IND就是6字节地址+31字节的数据),在数据通道规定最大的净荷包不能超过27个字节,不管有没有MIC净荷只能是最多27字节。
数据通道的PDU有效净荷数据可直接包含L2CAP数据。
3. HCI裸数据和PDU报文、L2CAP数据的关系
如上文件介绍了广播通道的PDU报文和数据通道的PDU报文,其有效数据净荷就是遵循L2CAP等协议的数据。L2CAP数据可来自软件,比如蓝牙Master端的GATT查询属性命令,这些数据要通过RF天线发送到Slave端,需要先打包为PDU报文,这个打包过程主要是蓝牙模块来实现,跟硬件关系很大。Slave端收到GATT命令后,会返回属性值,同样要打包为PDU报文发送、由Master端接收然后经过解PDU报文得到L2CAP数据。
PDU报文因为是通过RF无线传输的数据,这种数据交换机制也叫“空中接口协议”(Air Interface Protocol),俗称空气包。
HCI是MCU(Host)与蓝牙模块(Controller)的通信接口,Host和Controller之间的通信数据就是HCI数据,通常没有经过协议解析的二进制(或十六进制)数据称为“裸数据”:
比如Master端蓝牙数据如下:
HCI的物理介质可以是USB、UART、SDIO、SPI。Host和Controller之间传递HCI数据,不一定含有L2CAP数据,可能是Host与Controller的控制命令(不需要发送到Slave端的数据)。使用工具 Frontline 12.3分析Android btsoop时,得到的就是Host和Controller之间的HCI数据通信:
4. HCI报文格式
主机控制器传输层提供特定于HCI的信息的透明交换。这些传输机制使主机能够向BR/EDR控制器发送HCI命令、ACL数据和同步数据,并向LE控制器或AMP控制器发送HCI命令和ACL数据。这些传输机制还使主机能够接收来自BR/EDR控制器的HCI事件、ACL数据和同步数据,以及来自LE控制器或AMP控制器的HCI事件和ACL数据。由于主机控制器传输层提供特定于HCI的信息的透明交换,HCI规范指定了主机和控制器之间的命令、事件和数据交换的格式,也就是说蓝牙控制器接口的报文分为:指令报文、事件报文、数据报文(ACL数据或SCO数据,如下图,L2CAP用的是ACL数据)。
HCI Command Packet
HCI命令包用于从主机向控制器发送命令,其中HCI策略命令用于本地控制远程LM或LL的行为。控制器和基带、信息和状态命令提供主机对控制器中各种寄存器的访问。
HCI命令包的格式如图5.1所示,下面解释每个字段的定义。
Opcode:每个命令都分配了一个2字节的操作码(Opcode),用于唯一地标识不同类型的命令。操作码参数分为两个字段,称为操作码组字段(OGF)和操作码命令字段(OCF)。OGF占用操作码的上6位,而OCF占用剩余的10位。0x3F的OGF是为特定于供应商的调试命令保留的。
Parameter_Total_Length:数据包中后面所有参数的总长度(以Byte为单位)
Parameter 0 - N:每个命令都定义了特定的参数数量。
HCI各个命令的解释参考:https://blog.csdn.net/huibei_wuhan/article/details/101350819
Host向Controller发送命令后,Controller都要回复一个Command Status的包。
HCI ACL Data Packets
HCI ACL数据包用于在主机和控制器之间交换数据。格式如下:
Handle:总共12bit。Vol 2->Part E->5.3.1:有三种类型的句柄用于标识主机和控制器之间的逻辑通道:Connection Handles, Logical Link Handles, and Physical Link Handles。
- Connection Handles:在主机和主控制器之间传输数据包或数据段。
- Logical Link Handles:在主机和AMP控制器之间传输数据包。
- Physical Link Handles
范围:0x000-0xEFF(0xF00-0xFFF保留供将来使用)
其中Connection Handles是我们关注的重点。
Packet_Boundary_Flag:总共4bit
标志位由包边界标志(PB Flag)和广播标志(BC Flag)组成。PB Flag位于HCI ACL数据包第二个八位字节第4位和第5位,BC Flag位于第6位和第7位。各个bit的组合意义这里不说明。
Data_Total_Length:数据长度(Byte为单位)
HCI Synchronous Data Packets(SCO 数据包)
HCI Event Packet
HCI命令可能需要不同的时间来完成,因此,Controller将命令的结果以事件(Event)的形式报告给主机。例如,对于大多数HCI命令,当命令完成时,控制器将生成Command Complete的事件,此事件包含已完成的HCI命令的返回参数。
Event_Code:每个事件分配一个1字节的事件代码,用于标识不同类型的事件。参考Vol 2->Part E->7.7。
Parameter_Total_Length:数据包中后面所有参数的总长度(以Byte为单位)
Parameter 0 - N:每个事件都定义了特定的参数数量。
关于HCI数据分析的例子,参考https://blog.csdn.net/feelinghappy/article/details/108467402
- L2CAP报文格式
参考《蓝牙L2CAP协议简介及报文格式》
更多推荐
所有评论(0)