赞
踩
蓝牙工作在全球通用的 2.4GHz ISM(即工业、科学、医学)频段,使用 IEEE802.11 协议
蓝牙 4.0 是迄今为止第一个蓝牙综合协议规范,将三种规格集成在一起。其中最重要的变化就是 BLE(Bluetooth Low Energy)低功耗功能,提出了低功耗蓝牙、传统蓝牙和高速蓝牙三种模式:
”高速蓝牙“主攻数据交换与传输;“传统蓝牙”则以信息沟通、设备连接为重点;”低功耗蓝牙“以不需占用太多带宽的设备连接为主,功耗较老版本降低了 90%。
蓝牙 4.0 的芯片模式分为 Single mode 与 Dual mode。
Single mode 只能与蓝牙 4.0 互相传输无法向下与 3.0/2.1/2.0 版本兼容;
Dual mode 可以向下兼容 3.0/2.1/2.0 版本。
前者应用于使用纽扣电池的传感器设备,例如对功耗要求较高的心率检测器和温度计;后者应用于传统蓝牙设备,同时兼顾低功耗的需求。
此外,蓝牙 4.0 还把蓝牙的传输距离提升到 100 米以上(低功耗模式条件下)。拥有更快的响应速度,最短可在 3 毫秒内完成连接设置并开始传输数据。更安全的技术,使用AES-128 CCM 加密算法进行数据包加密和认证。
蓝牙 5.0 在低功耗模式下具备更快更远的传输能力,传输速率是蓝牙 4.2 的两倍(速度上限为 2Mbps),有效传输距离是蓝牙 4.2 的四倍(理论上可达 300 米),数据包容量是蓝牙 4.2 的八倍。
支持室内定位导航功能,结合 WiFi 可以实现精度小于 1 米的室内定位。
针对 IoT 物联网进行底层优化,力求以更低的功耗和更高的性能为智能家居服务。
随着蓝牙 5 技术的出现和蓝牙 mesh 技术的成熟,大大降低了设备之间的长距离、多设备通讯门槛,为未来的 IoT 带来了更大的想象空间。
BT Controller:此部分指的是蓝牙芯片,包括 BR/EDR 芯片(蓝牙 2.1 芯片),AMP 芯片(蓝牙 3.0 芯片),LE 芯片(蓝牙 4.0 芯片),后续我们把 4.0 以下统称为传统蓝牙,4.0 以上称为低功耗蓝牙,芯片层面会有 2 种模式,包括
单模蓝牙芯片:单一传统蓝牙芯片,单一低功耗蓝牙芯片
双模蓝牙芯片:同时支持传统蓝牙跟低功耗蓝牙的芯片
BT Host:蓝牙协议栈
HW 层:这里就是蓝牙芯片层,包含以下几个部分
TRANSPORT 层:此部分在硬件接口(UART/USB/SDIO)实现 HOST 跟 CONTROLLER 的交互,此部分会分为以下几个协议,在后续章节会对 transport 协议做详细的说明
HOST 层:此部分就是蓝牙协议栈,是我们本书的重点
core 文档 HCI 的架构如下:
2. L2CAP(Logical Link Control and Adaptation Protocol):逻辑链路控制与适配协议,将ACL数据分组交换为便于高层应用的数据分组格式,并提供协议复用和服务质量交换等功能。
通过协议多路复用、分段重组操作和组概念,向高层提供面向连接的和无连接的数据服务,L2CAP还屏蔽了低层传输协议中的很多特性,使得高层协议应用开发人员可以不必了解基层协议而进行开发。架构如下:
3. SDP(SERVICE DISCOVERY PROTOCOL):服务发现协议,服务发现协议(SDP)为应用程序提供了一种方法来发现哪些服务可用,并确定这些可用服务的特征
4. RFCOMM(SerialPortEmulation):串口仿真协议,上层协议蓝牙电话,蓝牙透传SPP等协议都是直接走的RFCOMM
5. OBEX:对象交换协议,蓝牙电话本,蓝牙短信,文件传输等协议都是走的OBEX
6. HFP(Hands-Free):蓝牙免提协议
一共分为两个角色:AG跟HF,蓝牙耳机跟手机连接,那么手机的角色就是AG,蓝牙耳机的角色是HF
7. HSP:蓝牙耳机协议,最开始的蓝牙耳机协议。算是一个简化版的HFP。
8. SPP(SERIAL PORT PROFILE):蓝牙串口协议,架构如下:
9. IAP:苹果的特有协议,分为IAP1/IAP2,一般做Carplay或者iPod功能的人肯定接触过这块
10. PBAP(Phone Book Access):蓝牙电话本访问协议,架构如下:
11. MAP(MESSAGE ACCESS PROFILE):蓝牙短信访问协议,架构如下:
12. OPP(OBJECT PUSH PROFILE):对象推送协议,架构如下:
13. AVCTP(AUDIO/VIDEO CONTROL TRANSPORT PROTOCOL):音视频控制传输协议,是AVRCP的底层,架构如下:
14. AVDTP(AUDIO/VIDEODISTRIBUTIONTRANSPORTPROTOCOL):音视频分布传输协议,是A2DP的底层,架构如下:
15. HID(HUMAN INTERFACE DEVICE):人机接口协议,架构如下:
16. A2DP(Advanced AudioDistribution): 蓝牙音乐协议,架构如下:
17. AVRCP(AUDIO/VIDEO REMOTE CONTROL PROFILE):蓝牙音乐控制协议
18. ATT:蓝牙 BLE 属性协议
ATT,Attribute Protocol,用于发现、读、写对端设备的协议(针对 BLE 设备),ATT允许设备作为服务端提供拥有关联值的属性集 ,让作为客户端的设备来发现、读、写这些属性;同时服务端能主动通知客户端。
说到属性协议,我们就不得不提属性是什么,在 ATT 中属性分为 3 个内容:
1)属性类型(attribute type),用 UUID 的形式来表现
2)属性句柄(attribute handle),用于标识一个属性
3)属性权限(permissions), 控制是否该 Attribute 可读、可写、属性值是否通过加密链路发送!
ATT 分为两个角色:Server/Client
一般蓝牙有几种方式可以debug
1)直接分析debuglog,就是打印log,这是最简单粗暴的方式,一般程序调试都是用这种方式,这种方式对于逻辑错误,执行流程有很大的帮助,但是对于不懂协议栈的人来说,直接打印有的时候很难定位蓝牙具体问题
2)Btsnoop调试蓝牙协议栈,这种通过软件来根据特定的格式来写一个文件,来看蓝牙整个的交互流程,在后续章节有介绍
3)直接录制HCI log,跟2的区别在于2是通过软件来生成文件,而这种方式是通过特定的工具+软件来采集蓝牙芯片端跟协议栈的收发数据,打开效果类似于btsnoop,但是更加有参考意义常用的hci log工具有frontline,ellisys,都是很贵,另外这个是有使用场景或者需求在的!
假设你的MCU没有FileSystem或者Flash不足以保存足够大的btsnoop,那替代btsnoop的方式推荐使用HCIHWsniffer,另外一种场景是上层确定调用uart 收发接口是正常的,但是到了芯片这端就是不响应,或者controller给你一个错误的应答,为了防止跟驱动扯皮,HCI HW sniffer也有应用场景在的!
4)录制airlog,也就是空中包来抓本地芯片跟远端芯片的蓝牙交互流程,也是用特定的工具跟软件来查看,常用的同样是ellisys,frontline,传统蓝牙的一般都比较贵,但是低功耗的蓝牙有更多的选择,而且价格相对于便宜很多,淘宝有<100RMB的。
5)抓芯片log,比如TI有TI logger,csr有spi接口来抓取相应的芯片log
总结下:以上5种方式各有各的好处,也各有各的弊端,针对具体问题采用不同的debug方式!
H4 是 UART 传输中最简的一个 Transport,只是在
HCI raw data 的前面加一个 type 就行,如下 HCI 一共有五种 HCI data:
1)HCI COMMAND:由蓝牙协议栈发送给芯片的命令(HOST->CONTROLLER)
2)HCI EVENT:由蓝牙芯片上报给蓝牙协议栈的事件(HOST<-CONTROLLER)
3)HCI ACL:蓝牙协议栈跟蓝牙芯片双向交互的普通数据(HOST<->CONTROLLER)
4)HCI SCO:蓝牙芯片跟蓝牙协议栈双向交互的通话/语音识别数据(HOST<->CONTROLLER)
5)HCI ISO(这部分是在 core5.2 才添加):BLE audio(HOST<->CONTROLLER)
仅在HCI原始数据之前添加了一个字节,表示type
从 host 到 Controller 的数据流控分为两种:Packet-based Data Flow Control和 Data-Block-Based Data Flow Control。通过 HCI_Write_Flow_Control_Mode 命令来切换,Packet-based data flow control 对于 BR/EDR和LE 芯片来说是默认的,Data-Block-Based Data Flow Control对于AMP controller来说是默认的
协议栈给芯片发送read buffer size command,芯片回复read buffer size event
在初始化的时候我们读到的 acl buffer size 是 10,所以我们发送了一个 acl 数据,此部分变为 9.
蓝牙协议栈收到蓝牙芯片回送的 Num of complete packet event 后,协议栈更新 acl buffer size 数量。
一般不常用,可以分别控制ACL和SCO的流控开关,通过Set Controller To Host Flow Control
command 命令控制,初始化的时候通过 Host Buffer Size command 由蓝牙协议栈发送给芯片
acl,sco packet num,以及 length,协议栈收到 acl 后发送给芯片 Host Number Of Completed Packets command,断开后,芯片自己维护重新计数
除非特别声明,否则所有的数据都采用小端模式。
HCI 命令包用于从协议栈发送给芯片的命令。HCI 命令包的格式如下图所示
每个命令被分配一个2字节的而操作码,分为两个字段:操作码组字段(OGF),操作码命令字段(OCF),OGF占用高6bit位置,OCF占用低10bit位置。代码实现:
HCI event 是蓝牙芯片发送给协议栈的事件。HCI 事件包的格式如下图所示,每个字段的定义如下所示:
以 HCI_Command_Complete 格式为例:
是reset命令的回复event
raw data 分析:
0x04-》是H4 transport的开头type
0x0E -> command complete event code
0x04 -> para len,也就是后面参数的长度
0x01 -> num HCI command pacekets(允许从host发往ctrler的命令数量,一般都是1?)
0x03 0x0c -> HCI reset command opcode
0x00 -> status success
HCI acl 用于从协议栈跟蓝牙芯片双向交互上层协议的数据。HCI acl 的格式如
下图所示,每个字段的定义如下所示:
HCI sco 用于从协议栈跟蓝牙芯片双向交互音频数据,主要用于传统蓝牙。HCI
sco 的格式如下图所示,每个字段的定义如下所示:
此部分是从 core5.2 开始增加,主要是蓝牙协议栈跟蓝牙芯片交互同步数据,主要用来传输 BLE Audio 的数据
HCI iso 的格式如下图所示,每个字段的定义如下所示:
整个流程如下:
1)首先协议栈给蓝牙芯片发送搜索 command
2)芯片收到搜索命令上报协议栈一个 command status 的 event
3)然后芯片上报协议栈搜索结果
4)最终芯片上报协议栈搜索完成
参数:
LAP:分为通用搜索访问代码(GIAC)和受限搜索访问代码(LIAC)
Unlimited inquiry 可以搜索到处于limited inquiry scan 跟 unlimited inquiry scan 状态的设备。
limited inquiry 只能搜索到处于limited inquiry scan 状态的设备。
Inquiry_Length,
Num_Responses,
后两个参数决定停止搜索的时间
异步指令才会触发该事件
参数:status 0x00表示该命令正常处理中,其他表示命令存在问题
Num_HCI_Command_Packets:控制器允许主机发送的命令数量
Command_Opcode:表示该事件是主机下发的哪个命令的响应
一般是每搜到一个设备就会上报一个该事件
参数:Num_Responses:搜索到设备的个数
BD_ADDR:搜到的蓝牙地址
Page_Scan_Repetition_Mode:page scan 重复模式
Reserved:保留参数
Class_of_Device:设备类型
Clock_Offset:时钟偏移
注意此部分普通的搜索不会上来 remote bluetooth name,需要额外去调用
Remote Name Request command 去请求,当然 EIR 除外,后续我们会说明 EIR。
如下是带有 remote bluetooth name的EIR事件,应该是需要先发送Write Extended Inquiry Response命令配置
达到搜索完成的条件之后,会触发该事件
参数:status,0x00表示成功完成了搜索,其他表示出错
流程是,先发送取消搜索的命令,然后收到命令完成的事件
无参数
一般的同步命令完成都会触发该事件上报
参数:
Num_HCI_Command_Packets:控制器允许主机发送的命令数量
Command_Opcode:该事件对应的命令Opcode
Return_Parameters:根据对应的具体命令确定返回的参数
流程如下:
总结步骤:1)蓝牙协议栈向芯片发送连接的 command
2)蓝牙芯片上报蓝牙协议栈 command status with create connection opcode
3)蓝牙芯片上报蓝牙协议栈 connect complete
异步命令
参数:
BD_ADDR:要连接的remote设备的蓝牙地址
Packet_Type:支持的数据封包类型
Page_Scan_Repetition_Mode:page scan 重复模式
Reserved:保留
Clock_Offset:时钟偏移
Allow_Role_Switch:是否允许角色转换
参数:
status:00代表连接成功
Connection_Handle:连接句柄
BD_ADDR:连接的蓝牙地址
Link_Type:连接的类型,SCO或者ACL
Encryption_Enabled:是否允许加密
步骤整理如下:
1)收到芯片上报给协议栈 connect request 的事件
2)协议栈发送给芯片接受连接请求的 command
3)收到 command status with accept connection req 的 opcode
4)收到 connect complete 的 event
参数:
BD_ADDR:蓝牙地址
Class_of_Device: 对方的 cod设备类型(可穿戴设备,智能手机等等)
Link_Type:连线类型:SCO,ACL,eSCO
参数:BD_ADDR:蓝牙地址
Role:当前连接的角色,00作为master,会产生一个role switch行为,01作为slave
每个协议栈使用顺序的会有所不同,并没有一个固定的顺序,一定要哪条指令先发,
举例如下:
Core手册查询方法:
command和event,位于Vol 4,Part E,第7章,1846~2632页之间
另外LE和传统BT的command有部分不同
我司流程:
步骤:
1)接受到 IO Capability Response event(0x32)
2)接受到 IO Capability Request event(0x31)
3)发送 IO Capability Request Reply command(OGF=0x01 OCF=0x2B),并接收到 command complete with opcode
4)接收到 User Confirmation Request event(0x33)
5)发送 User Confirmation Request Reply command(OGF=0x01 OCF=0x2C),并接收到 command complete with opcode
6)接收到 Simple Pairing Complete event(0x36)
应该是需要先建立一个HCI连接,才能进行SSP配对
参数:
BD_ADDR:蓝牙地址
IO_Capability:IO能力(log中为DisplayYesNo)
OOB_Data_Present:是否需要 OOB data(log中为None)
Authentication_Requirements:是否需要 auth(log中为MITM Protection Not Required, No Bonding)
IO能力意思如下:
DisplayOnly 只是需要显示随机数字就好了
DisplayYesNo 让 user 来决定是否要配对或者不配对
KeyBoardonly 让用户通过键盘来输入配对码
NoInputNoOutput 啥也不需要显示。
参数:
BD_ADDR:蓝牙地址
BD_ADDR:蓝牙地址
IO_Capability:IO 能力(log中为No Input/Output)
OOB_Data_Present:是否需要 OOB data(log中为None)
Authentication_Requirements:是否需要 auth(log中为MITM Protection Not Required, General Bonding)
参数:
BD_ADDR:蓝牙地址
Numeric_Value:随机数(十进制0-999999,16进制0-0x000F423F)
参数:
BD_ADDR:蓝牙地址
参数:
status:同上,00表示成功
BD_ADDR:蓝牙地址
搜索分为三种类型:
标准/RSSI/EIR
区别在于:
标准搜索只会附带以下信息:
RSSI就是在此基础上附带RSSI,那么 EIR(EXTENDED INQUIRY RESPONSE)就是在这些基础上会附带额外的一些信息,比如 remote name,对方支持的 UUID 等(前提是对方注册了 EIR),TX power 等
EIR格式说明:
EIR 信息不管是否有效数据是多少 byte,最终都要 240byte
EIR Data Structure 的格式为:1Byte length+nByte type(一般是 1byte)+(len-n) byte EIR raw data
EIR具体信息在文档 CSS_V9/V10 中
要让其他设备可以搜到本设备的EIR信息,需要先进行写入
HCI_Write_Extended_Inquity_response命令用于写入相关信息,local name,uuid(表示支持哪些profile)
要获取其他设备的EIR信息,需要先设置inquiry模式为extended模式,再搜索
参数
Inquiry_mode:标准,rssi,extended
Extended inquiry使用注意点:
L2CAP channel,在两个设备之间的逻辑通道,通过CID区分
SDU, L2CAP跟上层通信使用的数据包,服务数据单元
PDU,L2CAP跟下层通信使用的数据包,协议数据单元
L2CAP有基础模式,增强重传模式,流模式,重传模式,流控模式
基础模式主要用Basic information frame(B-frame);它是PDU的开头,包含长度和CID
Control frame(C-frame);它是包含L2CAP信令信息的PDU,仅用在信令通道上
segmentation和reassembly,SDU的拆包组包,主要用于非基础模式;
fragmentation和recombination,PDU的拆包组包,他们可能会用在所有模式下
• Basic L2CAP Mode((equivalent to L2CAP specification in Bluetooth v1.1) 默认模式,在未选择其他模式的情况下,用此模式。
• Flow Control Mode,此模式下不会进行重传,但是丢失的数据能够被检测到,并报告丢失。
• Retransmission Mode,此模式确保数据包都能成功的传输给对端设备。
• Enhanced Retransmission Mode,此模式和重传模式类似,加入了 Poll-bit 等提高恢复效率。
• Streaming Mode,此模式是为了真实的实时传输,数据包被编号但是不需要 ACK 确认。设定一个超时定时器,一旦定时器超时就将超时数据冲掉。
• LE Credit Based Flow Control Mode,被用于 LE 设备通讯。
• Enhanced Credit BasedFlow Control Mode
Event Code:0x3E
这个事件封装了所有LE controller的特有事件,其参数的第一个字节就是子事件代码。
初始化过程:
LE_SCAN
LE_Scan_Type:分主动扫描跟被动扫描
区别主要有几个
① 被动扫描仅仅接受广播包,不会发起扫描请求
② 主动扫描接受广播包后悔发送扫描请求给处于广播态的设备,来获取额外的广播数据
一般被动扫描用于确定从机不会发送扫描响应,只会发送 31byte 的广播数据
而主动扫描用于不确定从机是否有额外的数据,所以要额外发起扫描请求来接受更多的广播的数据
注意:主动扫描的扫描请求以及扫描响应也是广播封包
BLE 搜索广播 command 以及 event
步骤 1)发送设置事件掩码的 command(set event mask)以及收到commnd complete event
步骤 2)发送设置支持 BLE 的 command(write le host support)收到command complete event
步骤 3)发送设置 BLE scan 参数的 command(LE set scan param)
步骤 4)发送 BLE 搜索使能的 command(LE set scan enable)
步骤 5)收到步骤 3)4)的 command complete
步骤 6)解析 BLE 广播 event 的数据包
步骤 7)发送结束搜索的 command(LE set scan enable)以及收到commnd complete event
ATT,Attribute Protocol,用于发现、读、写对端设备属性的协议(针对 BLE设备),ATT 分为两个角色:Server/Client,ATT 允许设备作为服务端提供拥有关联值的属性集,让作为客户端的设备来发现、读、写这些属性;同时服务端能主动通知客户端。
ATT 有固定的 L2CAP CID,也就是 0x0004
通过 UUID(universally unique identifier)来标识,UUID 一般分为16bit/32bit/128bit 的 UUID,在 ATT 协议中,32bit 的 UUID 必须转换为 128bit的 UUID!
另外,16bit的UUID是通过加一个128 bit的base uuid来转换为128bit的UUID,base UUID 为:00000000-0000-1000-8000-00805F9B34FB,只所以本来 128bit的 UUID,大部分却采用 16 bit 来发送数据,主要是为了提搞传输速率以及减少交互次数!
采用 16bit 的值用于标识一个属性,范围是 0x0000~0xffff,0x0000 是保留数值,0xffff 是最大数值,所以我们一般不用!
Grouping 是一由高层协议定义的一组属性,他们位于其他属性组之前,客户可以请求第一个和最后一个与属性组关联的 Handle
属性值是自定义的字段,可以是任何类型的数据,长度可以是固定的也可以是可变的,可变的情况下,在一个request、response、notification、indication中只能有一个attribute value,固定的情况下,长度在attribute type中定义好了,这时可以传送多个attribute value
Attribute permissions是access permissions、encryption permissions、authentication permissions和authorization permissions的组合。
(1)access permissions用来表示attribute是否允许client进行读写,取值包括:Readable、Writeable、Readable and writable;
(2)encryption permissions用来表示是否加密,取值包括:Encryption required、No encryption required
(3)authentication permissions用来表示当client访问attribute value时是否需要一个已认证的物理链路,同样也表示当server向client发送notification和indication时是否需要一个已认证的物理链路,取值包括:Authentication Required、No Authentication Required
(4)authorization permissions用来表示当client访问attribute value时是否需要授权,取值包括:Authorization Required、No Authorization Required
不可读,但是可写,可通知(Notified)和可指示(Indicated)的属性被称为Control-Point Attribute 高层协议可使用该属性来使能设备特定过程,比如设备上一个给定过程的命令或指示已经完成.
ATT 使用 Protocol Methods 来发现、读、写、通知、指示属性,方法可分为如
下几种 Request/Response/Command/Notification/Indication/Confirmation
命令(Commands)是 ATT client 发送给 server 端的命令数据,并且不要求回复response,以 CMD 结尾.
请求(Requests)是 ATT client 发送给 server 端的请求数据,要求 server 回复response,以 REQ 结尾.
响应(Reponses)是 ATT server 为响应 client 请求,回复的 response 数据,以RSP 结尾.
通知(Notifications)是 ATT server 发送给 client 的通知数据,并且不要求回复 confirmation,以 NRF 结尾.
指示(Indications)是 ATT server 发送给 client 的指示数据,要求 client 发送confirmation 数据,以 IND 结尾.
确认(Confirmations)是 ATT client 为了回复 server 发送的 indications,发送的 indications 数据,以 CFM 结尾
就是用来传输 ATT PDU 的 L2CAP 通道
ATT_MTU 定义了 Client 和 Server 之间数据包的最大值;其默认值由高层协议来定义,Client 和 Server 可通过 Exchange MTU Request and Response PDUs 来交换最大数据包然后均使用交换值中的最小值进行通信,同时作为 Server 和Client 的设备应该使用相同的 Client Rx MTU 和 Server Rx MTU,每个 ATT Bearer(L2CAP等下层协议)均有其 ATT_MTU;当一个设备拥有多个 ATT Bearer 时,不同 ATT Bearer 的 ATT_MTU可能不同
(1)一个数据包最大可以发送的attribute长度是ATT_MTU-1个字节,至少Attribute Opcode要占一个字节,如果attribute value的长度大于ATT_MTU-1个字节,则称为Long Attribute
(2)read长度大于ATT_MTU-1个字节Attribute,需要使用read blob request,使用read request可能读取到前面的ATT_MTU-1个字节
(3)write长度大于ATT_MTU-3个字节Attribute,使用prepare write request和execute write request,使用write request可能写入前面的ATT_MTU-3个字节
(4)在ATT协议中无法确定一个attribute的长度是否可以大于ATT_MTU-3,在上层协议中将声明给定属性的最大长度可以大于(ATT_MTU-3)字节
(5)attribute value最大长度是512个字节
Server 应该将 Client 的每个请求或命令视为不受影像的原子操作,如果一个链路由于某种原因断开,高层协议应当对属性值得修改负责!Long Attribute 不能被单一的原子操作读、写!
对应六种协议方法
整个 ATT PDU 包含 3 个部分:
1)Attribute Opcode
2)Attribyte Parameters
3)Authentication Signature
Attribute Opcode:ATT PDU 的操作码
Attribyte Parameters:ATT PDU 的参数,每个opcode有自己的参数
Authentication Signature Flag 取值如下
Error Response 用来声明一个给定的请求无法完成,并给出原因
备注:ATT_WRITE_CMD 不需要回复这个 PDU
参数:
Attribute Opcode:操作码,在上一小节中有讲,此处 ATT_ERROR_RSP PDU(0x01)
Request Opcode In Error:是回复哪个请求 Opcode
Attribute Handle In Error:发生错误的句柄
Error Code:错误码,可以查表
Client 使用 MTU Exchange Request 来告知对方所支持的最大接收 MTU size,同时请求 Server 回应 Server 所支持的最大接收 MTU size.
在低功耗蓝牙连接中,属性协议默认的 MTU 为 23 字节。一般客户端如果不发起这个请求的,它的默认值就是 23,当双方交换的值不同时,用较小的那个作为最终使用的值。
Find information 包括两组 request/response
ATT_FIND_INFORMATION_REQ 对应 ATT_FIND_INFORMATION_RSP
ATT_FIND_BY_TYPE_VALUE_REQ 对应 ATT_FIND_BY_TYPE_VALUE_RSP
查找信息请求和回复用来查找一系列属性的句柄和类型信息。这是唯一一个能让客户端发现任意属性类型的消息。
查找信息请求包含有两个句柄:起始句柄和结束句柄。它们定义了该请求用到的属性句柄范围。为了找到所有数值的属性,该请求的起始句柄将是 0x0001,结束句柄设为 0xFFFF。但是回复的信息中因为长度限制,并不能包含所有的属性,所以需要再次请求,只是将起始句柄改为查找到的最大句柄的后一个句柄开始。
查找信息的响应格式包括format和information Data
format代表UUID的类型,是16bit还是128bit的
information Data是两字节的Handle(标识属性)还有两字节或16字节的UUID(标识属性类型的)
按类型值查找请求和回复可以根据给定的类型与数值查找相应的属性。该请求包含有两个句柄: 起始句柄和结束句柄,规定查找范围。对于这一范围类的所有属性,如果和请求中所指定的类型和数值一样,那么这个属性就要在响应中返回
Ready attributes 包括 6 组 request/reponse
ATT_READ_BY_TYPE_REQ/ATT_READ_BY_TYPE_RSP
ATT_READ_REQ/ATT_READ_RSP
ATT_READ_BLOB_REQ/ATT_READ_BLOB_RSP
ATT_READ_MULTIPLE_REQ/ATT_READ_MULTIPLE_RSP
ATT_READ_BY_GROUP_TYPE_REQ/ATT_READ_BY_GROUP_TYPE_RSP
ATT_READ_MULTIPLE_VARIABLE_REQ/ATT_READ_MULTIPLE_VARIABLE_RSP
这个命令能在句柄范围内读取某个属性值。当客户端仅知道属性的类型而非句柄时可以使用该请求。请求包含有起始、结束句柄和需要读取的属性的类型。响应将给出符合的句柄和数值。这个请求用于搜索被包含的服务,并通过特性类型来发现服务中的所有的特性。它也被用来读取已知类型的特性值
读取请求是属性协议总最简单的请求。该请求包含一个句柄,响应将返回该句柄对应的属性值。只有在客户端已知属性句柄的情况下,才能使用该请求读取属性值。
有时属性值太长,无法装入一个读取响应,须使用大对象读取请求来获取剩余字节。大对象读取请求不光包含属性句柄,还包含属性值的这个数据中的偏移量。
其响应将从属性偏移量开始,包含尽可能多的属性值。在获得了属性值的前 22 (ATT_MTU-1)节后,假如客户端还想获取后续的属性值,则使用大对象读取请求。下一条响应将返回第 23 个字节到 44 个字节;如此继续,直到客户端读取到完整的属性值。该请求用于读取长特征值与长特征描述符。
用来在一个操作中读取多个属性值。该请求包含一个或多个属性句柄,响应则按顺序返回相应的属性值。然而因为响应中的数值之间没有界限,因此,在请求中除了最后一个属性允许可变的长度,其他属性必须为定长的属性值。也就是说,如果客户端用一个多重读取请求来读取三个属性,前两个属性的长度必须固定,最后一个属性的长度则可以变化。如果客户端请求读取的属性值的长度超过了响应数据包所能承载的最大长度,那么无法放入响应数据包的数值将被丢弃。
它和按类型读取请求类似,也包含有一个句柄范围,读取时将其视为一个属性的类型来处理,只不过属性的类型必须为分组属性。其响应包含所读取的属性句柄、属性分组中最后一个属性以及属性的数值。这意味着,如果分组类型是首要服务,它将返回所有首要服务声明的属性句柄、该首要服务中最后一个属性以及首要服务声明的数值。因此,可以仅凭单个请求来发现设备上的所有首要服务、与之关联的属性句柄的范围以及这些服务的类型。如同其他返回对个句柄-数值对的响应,如果返回的值长度可变,那么只有长度相同的属性值将在第一个响应中被返回。因此,客户端必须再次发起请求,更新起始句柄来发现想要获取的下一个属性
Write attributes 包括 1 组 request/response,两组 command
这个是写特定的 handle 的属性值
写入命令类似于读取请求,区别是写入命令没有响应。写入命令包含要写入的属性的句柄和要写入的数值。当无需响应时,可以使用写入命令。
签名写命令和写命令类似,只是前者包含认证签名。通过这样的机制,发送端可以向服务器发送写入命令时认证自己,而无需加密通信连接。签名写命令适用于以下两种场合:
1)发起加密将显著增加数据连接的延迟
2)发起加密将显著增加简短且无需加密的数据的送达成本
认证签名由签名计数器和消息认证码构成。签名计数器对设备间发送的每一条消息赋予不同的值,不论消息发送的间隙连接中断与否。使用签名计数器可以抵御消息重放攻击,因此,假如签名写入命令的签名计数器值和先前的值相同,该命令会被忽略。消息认证码长度为 64 位,该码位于句柄、数值和签名计数器之后。注意,服务器需要为每一个客户端保存其最后使用的签名计数器。
长属性的写入,需要分为两步,先准备写,再执行写
准备写:ATT_PREPARE_WRITE_REQ 和ATT_PREPARE_WRITE_RSP
准备写过程是,客户端将长属性分段传输给了服务器,服务器先放入缓存队列之中,传完之后再执行写
执行写:ATT_EXECUTE_WRITE_REQ 和ATT_EXECUTE_WRITE_RSP
执行写过程就是将之前收到的属性值写入真正的属性中
Server initiated 包括 1 组 indication/confirms,两组 notification
ATT_HANDLE_VALUE_NTF
ATT_HANDLE_VALUE_IND/ATT_HANDLE_VALUE_CFM
ATT_MULTIPLE_HANDLE_VALUE_NTF
当服务器想要向客户端发送快速的属性状态更新时,可以发送一条句柄值通知。这个是服务器能够发给客户端的两种消息中的一种,并且是不要求响应的那种。
句柄值指示类似于句柄值通知。它有着相同的属性句柄字段和数值,不同的是客户端收到指示以后应回复。服务器一次只能发送一条指示,并且只有收到确认响应后才能发起下一条指示。
句柄值确认不含任何数据,主要用于流控。因为具备了确认机制,指示被视为可靠传输。一旦服务器收到确认信息,它便能确定客户端收到了该信息。
可以发送两个或者两个以上的 notification
GATT(Generic Attribute Profile),描述了一种使用 ATT 的服务框架 ,该框架定义了服务(Server)和服务属性(characteristic)的过程(Procedure)及格式 。Procedure 定义了 characteristic 的发现、读、写、通知(Notifing)、指示(Indicating)及配置 characteristic 的广播。
GATT 可以被 Application 或其他 Profile 使用,其协议栈如下图
PC 就是做 GATT client 用来读取温度计的数据,,温度计 Sensor 做 GATT server 用来把温度数据发送送出去
GATT 指定了数据交互的结构(Structure);这个结构体定义了一些基本元素,如Service、Characteristic ,这些元素存在于 Attribute 中,层级结构如下:
GATT 中最上层是 Profile,Profile 由一个或多个服务(Service)组成 ,服务是由 Characteristics 组成,或是其他服务的引用(Include),Characteristic 包含一个值(Value),可能包含该 Value 的相关信息
一个service是被service definition定义的,service definition可能包含其他services的引用、必须的characteristics和可选的characteristics
有两种类型的 service
1)Primary Service : 拥有基本功能的服务,可被其他服务包含,可以通过Primary Service Discovery 过程来发现
2)Secondary Service : 仅用来被 Primary/Other Secondary Service、高层协议引用的服务.
service definition肯定包含一个service declaration,可能包含include definitions 和characteristic definitions,发现下一个service declaration或者Attribute Handle达到最大值则表示service definition结束了;
Characteristic 由 Characteristic Definition 定义,包含一个特征声明(Characteristic declaration)、特征值声明(Characteristic Value declaration)和可选的特征的描述声明(characteristic descriptor declarations)
特性声明(Characteristic declaration):特性声明本身的 UUID 值是 0x2803,特性声明中需要声明的特性是在属性值中的,属性值包含有 3 个字段:
特性性质、属性句柄和属性类型,且仅为只读。如下:
Characteristic Value declaration包含characteristic的value,Characteristic Value declaration紧跟在characteristic declaration之后,一个characteristic definitions都有一个Characteristic Value
declaration,具体组成如下图所示:
Characteristic descriptors主要包含一些Characteristic Value的相关信息.Characteristic descriptors位于Characteristic Value declaration之后,多个Characteristic descriptors之间没有顺序要求。
支持通知或者指示的特性必须使用客户端配置描述符。它的声明格式如图所示。
该描述符是一个 2byte 的数值,分别用于设置通知与指示,但是不允许同时设置。
使设备广播该特性所属服务的相关数据,格式如下:
Characteristic Presentation Format declaration定义Characteristic Value的格式,如果在characteristic definition中有超过1个Characteristic Presentation Format declarations存在,那么肯定要有一个Characteristic Aggregate Format declaration存在
有些特性值远比单一的数据复杂得多。譬如用标准的符号来表示地球上的某个位置,通常包含经度和纬度值,二者组合在一起便构成一个“坐标值”。为了构造类似的复杂的特性值,特性聚合格式描述符允许引用多个表示格式描述符来解释组合值的每个字段
GATT 一共定义了 11 个特性,如下:
There are 11 features defined in the GATT Profile:
这个功能是client用来设置ATT的MTU,当client的ATT_MTU大于default ATT_MTU时,client就会调用Exchange MTU程序配置ATT_MTU,这个程序只有在连接过程中执行一次(虽然Spec中规定只能使用一次,但是NRF connect中可以无限测试)。
(client和server都会取Client Rx MTU和Server Rx MTU中最小的值作为ATT_MTU)
Client使用这个功能搜索server上的primary services,这个功能分为两个子程序:Discover All Primary Services和Discover Primary Services by Service UUID
举例:
(1)Client使用ATT的Find By Type Value Request,设置Attribute Type为«Primary Service»,Starting Handle=0x0001,Ending Handle=0xFFFF,Attribute Value设置为UUID1;
(2)server回复Find By Type Value Response,Handles Information List为:0x0200,0x0214;最后一个元素的Group End Handle=0x0214,不是0xFFFF所以没有结束。
(3)client继续ATT的Find By Type Value Request,设置Attribute Type为«Primary Service»,Starting Handle=1 + 0x0214=0x0215,Ending Handle=0xFFFF,Attribute Value设置为UUID1;
(4)server回复Error Response,Error Code为«Attribute Not Found»,搜索结束
举例:
(1)Client使用Read By Type Request,Attribute Type为«Include»,Starting Handle为包含这个«Include»的Service的starting handle即0x0200,Ending Handle为包含个«Include»的Service的最后一个handle即0x0214
(2)server回复Read By Type Response,Length=0x08,Attribute Data List为:0x0201,0x0500,0x518,«UUID1»;其中0x08表示Attribute Data List中每个元素的长度,0x0201表示include declaration的handle,0x0500,0x518分别表示被包含的那个service的service declaration、End Group Handle,«UUID1»即被包含的service的16bit的UUID。0x0201!=0x0214,所以没有结束。
(3)client继续发送ATT的Read By Type Request,设置Attribute Type为«Include»,Starting Handle=1 + 0x0201=0x0202,Ending Handle=0x0214
(4)server回复Read By Type Response,Length=0x06,Attribute Data List为:0x0202,0x0550,0x568;其中0x06表示Attribute Data List中每个元素的长度,0x0202表示include declaration的handle,0x0550,0x558分别表示被包含的那个service的service declaration、End Group Handle,没有被包含的那个service的UUID,所以被包含的那个service的UUID应该是128bit的,需要使用Read Request去获取
(5)Client使用Read Request,Attribute Handle参数设置为0x550
(6)Server回复Read Response,参数Attribute Value就是被包含的那个service的128bit的UUID
(7)client继续发送ATT的Read By Type Request,设置Attribute Type为«Include»,Starting Handle=1 + 0x0202=0x0203,Ending Handle=0x0214
(8)server回复Error Response,Error Code为«Attribute Not Found»,搜索结束
举例:
(1)Client使用Read By Type Request,Attribute Type为«Characteristic»,Starting Handle为包含个«Characteristic»的Service的starting handle即0x0200,Ending Handle为包含这个«Characteristic»的Service的最后一个handle即0x0214
(2)server回复Read By Type Response,Length=0x07,Attribute Data List为:0x0203,0x02,0x0204, «UUID1»,0x0210,0x02,0x212,«UUID2»;其中0x07表
示Attribute Data List中每个元素的长度,0x0203,0x02,0x204, «UUID1»是第一个Attribute Handle和Attribute Value对(Attribute Handle=0x0203,Characteristic Properties=0x02,Characteristic Value Handle=0x0204,Characteristic UUID= «UUID1»),0x0210,0x02,0x212,«UUID2»是第二个Attribute Handle和Attribute Value对;0x0210!=0x0214,所以没有结束。
(3)client继续发送ATT的Read By Type Request,设置Attribute Type为«Characteristic»,Starting Handle=1 + 0x0210=0x0211,Ending Handle=0x0214
(4)server回复Error Response,Error Code为«Attribute Not Found»,搜索结束
这个描述符每个characteristic只能有一个
在characteristic properties中,extended properties位是1,那么这个描述符应该存在
只读,无需认证,无需授权
reliable write 只占1bit
允许这个characteristic的value进行可靠写
可靠写过程举例如下:
writable Auxiliaries 只占1bit
允许写这个characteristic 的 characteristic user Descriptor
这个描述符每个characteristic只能有一个
这个就是用户描述这个characteristic的描述符,value就是UTF-8的字符串
这个描述符每个characteristic只能有一个
这个描述符的配置应在跨连接的绑定设备中保持持久(掉电保存)。客户端特征配置描述符值应在每次与非绑定设备连接时设置为默认值。
每个客户端都有自己的客户端特征配置实例。读取客户端特征配置仅显示该客户端的配置,写入仅影响该客户端的配置。服务器可能需要进行身份验证和授权才能写入配置描述符。
属性值长度应为两个八位字节,并应设置为特征描述符值。
notification:占1位,如果这位为1,这个characteristic value变化了,通知订阅了这个值的客户端
Indication:占1位,如果这位为1,这个characteristic value变化了,指示订阅了这个值的客户端
这个描述符每个characteristic只能有一个
这个描述符对所有客户端有效
实际上就是确定这个characteristic value是否要被广播
BLE扩展广播,最多可以广播0x672(1650)字节的data,具体要看controller的支持情况,通过HCI命令可以read到其支持的最大的长度
配对是一个三阶段的过程,阶段2有两种方式:
LE legacy pairing可以生成STK;
LE Secure Connections可以生成LTK;
加密函数说明:
LE legacy pairing用到的加密函数:
LE secure Connections用到的加密函数:
加密函数ah,c1和s1的构建块是安全函数e
加密函数f4,f5,f6,g2,h6和h7的构建块是安全函数AES-CMAC
e用128位的key和128位的plaintextData产生128位的encryptedData
encryptedData = e(key,plaintextData)
随机地址哈希函数ah用来生成用于可解析私有地址的哈希值
它的输入有:k 128bits,r 24bits,padding 104bits
r和padding连接,生成r’,r’用于作为128bit的plaintextData,用作安全函数e的输入参数,例如,r是0x423456,r’是0x00000000000000000000000000423456。
ah(k,r) = e(k,r’) mod 2^24
即,e的输出被截断为24bit作为ah的输出
认证要求由GAP设定,认证要求包括绑定类型和中间人(MITM)保护要求
加密发起设备会指示响应设备,哪一种密钥将被发送给相应设备,需要响应设备返回哪一种密钥;
SM提供的安全属性分为以下几类:
LE安全连接配对使用P-256椭圆曲线
什么叫中间人保护?
输入能力:无输入能力,可以输入yes or no,可以输入数字和yes or no
输出能力:无输出能力,可以至少显示6位数字
如果有对端设备的带外数据,则OOB flag应该置位
LE遗留加密方法下,如果双方都有对端的带外数据,则使用带外认证方法;
LE安全连接配对时,只要有一个设备有对端的带外数据,就可以使用带外认证方法
密钥大小在,7字节-16字节之间,两个设备之间较小的那个密钥大小会用作加密过程中的密钥大小
配对过程肯定是由中心设备发起,但外设也可以请求中心设备发起配对:
具体参数介绍:
IO能力(1字节)主要是分为:
OOB数据(1字节),一般是来自NFC或者USB
在阶段1完成之后,配对设备双方会选择好合适的配对方法:
在哪里确定使用LE遗留配对或者安全连接配对?阶段1的参数中没有体现呀?
其他两种方式,区别只是TK的来源不同
passkey entry中TK是用户输入的;
OOB中,TK是来自带外
首先两个设备在步骤1a和1b中,交换公钥,然后开始各自生成各自的DHKey
如果至少有一个设备有输出能力,数字比较步骤将会进行;如果两个设备都有输出能力,这一步骤将要求显示一个用户确认值,这个值应该一直显示到步骤2结束;如果一个或者两个设备都没有输出能力,还是会使用相同的协议,但是hosts将跳过要求用户确认的步骤
Just works与Numeric Comparison步骤基本一致,唯一的区别就是,Just works步骤中,host不会显示数字给用户
跟在发起设备侧数字比较失败基本一致,只是最后是由响应设备报告配对失败给发起设备
passkey输入步骤用在两种情况下:当一个设备只有数字输入能力并且另一个设备只有输出或者数字输入能力时。
在这个步骤中,一个设备显示一个由另一个设备输入的数字,或者用户在两个设备上输入一个数字。
注意:passkey输入可能会延长配对体验,因为需要通过SMP执行20次的match操作
一旦在20次重复的某一次中,响应设备计算出的确认值与接收到发起设备发送过来的不同,响应设备将中断配对过程,发送配对失败事件
跟在响应设备端确认检查失败流程一致,只是由发起设备给响应设备报告配对失败事件
个人理解,以上步骤都是为了生成DHkey,Just work,passkey entry和OOB三种方式只是获取计算初始值的手段,Just work初始值为0,passkey entry是用户输入,OOB是双方提前约定好;是根据双方设备的能力不同,采用不同的手段获取初始值。
DHkey计算完成之后,会使用DHKey计算LTK。
在LTK计算和认证阶段1完成之后,配对双方将会交换DHkey检查值用于检查DHKey,这个值是由DHKey生成的;如果检查成功,双方设备就可以显示有关该过程的信息,host可以决定是否显示。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。