蓝牙的建立过程是一个复杂的过程,即使有过相当一段工作和使用经验的人,如果不仔细去了解还是理解不全。
平时我们用蓝牙耳机听音乐,和不同的设备共享文件,打电话等,都有一个配对--连接--传输数据的过程。
配对,其实就是一个认证的过程。
1. 为什么不配对便无法建立连接?
任何无线通信技术都存在被监听和破解的可能,蓝牙SIG为了保证蓝牙通信的安全性,采用认证的方式进行数据交互。同时为了保证使用的方便性,以配对的形式完成两个蓝牙设备之间的首次通讯认证,经配对之后,随后的通讯连接就不必每次都要做确认。所以认证码的产生是从配对开始的,经过配对,设备之间以PIN码建立约定的link key用于产生初始认证码,以用于以后建立的连接。
所以不配对,两个设备之间便无法建立认证关系,无法进行连接及其之后的操作,所以配对在一定程度上保证了蓝牙通信的安全,当然这个安全保证机制是比较容易被破解的,因为现在很多个人设备没有人机接口,所以PIN码都是固定的而且大都设置为通用的0000或者1234之类的,所以很容易被猜到并进而建立配对和连接。
2. 蓝牙的连接过程
现在的蓝牙芯片供应商提供的技术支持能力相当强大,有完整的硬件和软件解决方案。对于应用而言,提供了固件用于实现底层协议栈,提供了profile库及源代码规范了各种应用,开发人员只要专注于应用程序开发就可以了。对于蓝牙底层的一些东西往往不甚了了。以前我也是这样子的,最近在做一个自动搜索以实现自动连接的应用,发现还是需要了解一些底层的机制的。
我们可以很容易的进行操作在一个手机和免提设备之间建立连接,那么这个连接是怎么建立起来的呢?
首先,主设备(master,即发起连接的设备)会寻呼(page)从设备(slave,接收连接的设备),master会已跳频的方式去寻呼slave,slave会固定间隔地去扫描(scan)外部寻呼,即page scan,当scan 到外部page时便会响应response该page,这样两个设备之间便会建立link的连接,即ACL链路的连接。当ACL 链路连接建立后,主设备会发起channel的连接请求,即L2CAP的连接,建立L2CAP的连接之后,主设备采用SDP去查询从设备的免提服务,从中得到rfcomm的通道号,然后主设备会发起rfcomm的连接请求建立rfcomm的连接。然后就建立了应用的连接。
即link establish->channel establish->rfcomm establish->connection
3. 广播数据分析
3.1. 发送广播数据包的叫广播发起者(advertisers),在广播通道接收广播数据包但没意向连接广播发起设备的叫扫描者( scanners), 需要连接到另一个设备的设备叫做 initiators,它监听可连接的广播数据包。如果advertiser正在使用一个可连接的广播事件, initiator在收到连接数据包的物理通道上发起一个连接请求,如果advertiser接受这个连接请求则这个广播事件结束,并且开始一个新的连接事件。一旦连接建立,initiator成为主设备,advertiser成为从设备。连接事件被用于在主从设备之间传输数据包。
连接过程:
广播者:广播包使用ADV_IND PDU标志;
扫描者:发送扫描请求(SCAN_REQ PDU)请求关于广播者的信息一个SCAN_REQ PDU(包含了扫描者的设备地 址), 在同一信道上回复一个SCAN_RSP PDU;
发起者: 发起者发送连接请求(CONNECT_REQ PDU)请求进入连接态,广播者确认即可以连接上。
SCAN_REQ_PDU载荷如下图所示,由ScanA(扫描设备地址)和AdvA组成(广播设备地址),ScanA是扫描设备的公共或随机地址(由TxAdd确定),AdvA是广播设备的公共或随机地址(由RxAdd确定)。
图 - 扫描请求PDU载荷
广播报文的报头中的TxAdd指示了扫描设备使用的是公共地址(Public Address)还是随机地址(Random Address)。
TxAdd = 0:公共地址。
TxAdd = 1:随机地址。
RxAdd指示了广播设备使用的是公共地址(Public Address)还是随机地址(Random Address)。
RxAdd = 0:公共地址。
RxAdd = 1:随机地址。
3.2. 扫描响应
SCAN_RSQ_PDU载荷如下图所示,由AdvA(广播设备地址)和ScanRspData组成(扫描响应数据),AdvA是广播设备的公共或随机地址(由TxAdd确定)。
图 - 扫描响应PDU载荷
广播报文的报头中的TxAdd指示了广播设备使用的是公共地址(Public Address)还是随机地址(Random Address)。
TxAdd = 0:公共地址。
TxAdd = 1:随机地址。
广播报文的长度域指示了载荷的字节数(AdvA和ScanRspData)。
3.3. SCAN_REQ和SCAN_RSP解析
3.3.1. 捕获SCAN_REQ
按照《蓝牙4.0BLE抓包(一)》中的描述进行抓包,下面是我们捕获一个心率计的SCAN_REQ包。
图4:捕获的SCAN_REQ包
3.3.2. 分析SCAN_REQ
为了方便分析,我们先取出这个SCAN_REQ包实际传输的数据,如图3中所示。心率计完整的广播报文如下:
D6 BE 89 8E 83 0C 7F 0F 72 DD DF 68 DA B5 E9 D2 CC F3 BD BF 27
在分析数据之前,再次说明:广播包含扫描请求和扫描响应,所以扫描请求和扫描响应得包格式遵循广播包的格式。
分析报文时,需要注意一下报文各个域的字节序。
3.3.2.1. 接入地址
D6 BE 89 8E:接入地址,对广播来说是固定值。注意一下这里的字节序,接入地址传输时是低字节在前的。
3.3.2.2. PDU
1). 83:广播报文报头。
bit0~bit3是0011,说明广播类型是SCAN_REQ,即扫描请求。
bit7(RxAdd)是1:说明广播设备使用的是随机地址。
bit6(TxAdd)是0:说明扫描设备使用的是公共地址。
2). 0C:长度,表示SCAN_REQ报文的长度是12个字节。
3). 7F 0F 72 DD DF 68:扫描设备的公共地址(报头里的TxAdd指示了这个地址是公共地址)。这里使用的实验设备是[艾克姆科技]的EN-nRF51DK开发板和小米3手机,扫描设备是小米3手机,在图3中可以看到该公共地址对应的是Xiao_mico_72。
4). DA B5 E9 D2 CC F3:广播设备的地址(报头里的RxAdd指示了这个地址是随机地址)。
3.3.2.3. 校验
BD BF 27:24字节CRC校验。
3.3.3. 捕获SCAN_RSP
按照《蓝牙4.0BLE抓包(一)》中的描述进行抓包,捕获一个心率计的SCAN_REQ包。
图 - 捕获的SCAN_RSP包
3.3.4. 分析SCAN_RSP
同样,在这里我们先取出SCAN_REQ包的数据,便于分析。
D6 BE 89 8E 44 06 DA B5 E9 D2 CC F3 61 6A 0F
3.3.4.1 接入地址
D6 BE 89 8E:接入地址,对广播来说是固定值。注意一下这里的字节序,接入地址传输时是低字节在前的。
3.3.4.2 PDU
1). 44:广播报文报头。
bit0~bit3是0100,说明广播类型是SCAN_RSP,即扫描响应。
bit6(TxAdd)是1:说明广播设备使用的是随机地址。
2). 06:长度,表示SCAN_ RSP报文的长度是6个字节。
3). DA B5 E9 D2 CC F3:广播设备的地址(报头里的RxAdd指示了这个地址是随机地址)。
3.3.4.3 校验
61 6A 0F:24字节CRC校验。
3.4.连接请求CONNECT_REQ
在低功耗蓝牙技术建立连接的过程中,设备都是成对出现的:master和slave设备。如果master希望与slave建立连接,master就需要发起连接请求(ConnectionRequest,CONNECT_REQ)因此master可以称之为连接发起者;同时,slave必须是可连接的并且具有解析连接请求CONNECT_REQ的能力,slave可以称之为广播者。图1是连接请求CONNECT_REQ的帧结构。
图1 CONNECT_REQ帧结构
其中,InitA是连接发起者的蓝牙设备地址,长度为6字节;AdvA是广播者的蓝牙设备地址,长度为6字节。除了InitA和AdvA之外,帧格式中最为重要的部分则是LLData,这一部分包含了在连接建立过程中所需要使用的有意义的参数。
为了更好的理解连接请求CONNECT_REQ,我们可以在日常生活中找到类似的一个例子,帮助我们理解它的含义。读者们很多应该都有过工作经验,在开始新的工作之前,都需要和雇主签署一份劳动合同,而CONNECT_REQ就是一份由“雇主”master提供的“劳动合同”,只需经过“雇员”slave确认,这份“合同”就开始生效,低功耗蓝牙技术的连接也就建立了。接下来我们就对“合同”中的各项条款逐条进行分析(如图2所示)。
图2 LLData示意图
(1)接入地址(AA:Access Address)
这份合同的第一条款就是为雇员分配一个公司内部的唯一识别码,类似于工号,雇员可以在公司内部使用这一工号;当雇员离开公司之后,唯一识别码自动失效;即使是这一雇员再次加入到这家公司,他/她的新工号也与旧的工号不同。类似的,在两个低功耗蓝牙技术设备建立连接之前,master设备负责生成接入地址,这一地址类似于一个4字节的随机数,当连接建立之后,master和slave都使用这一接入地址进行通信;当连接断开之后,接入地址自动失效。
(2)CRCInit(CRC初始值)
这份“合同”的第二条款是CRCInit,它就是雇员在公司内部的一个密钥,通过这个密钥,雇员可以访问公司内部的资源。对于低功耗蓝牙技术设备,master和slave使用CRCIinit来验证数据包的完整性。
(3)WinSize和WinOffset
合同的第三条款中规范了雇员首次来公司报到的时间以及今后每次工作的时长。WinSize和WinOffset在低功耗蓝牙技术连接中,也做了类似的定义。WinOffset定义了在CONNECT_REQ命令之后的一个通信窗口的偏移量,如图3所示。在slave设备收到CONNECT_REQ之后,slave设备需要占用一些时间、根据LLData参数进行一些相关的配置,因此,WinOffeset为slave设备进行此种操作提供了时间,transmitWindowOffset= WinOffset×1.25 ms。WinSize定义了设备每次开启收发机的窗口时间,无论是master还是slave,它们都遵循WinSize的定义,窗口时间transmitWindowSize=WinSize×1.25 ms。
因此,在CONNECT_REQ之后,第一个由master发送到slave的数据帧,我们称之为“锚点”(如图3所示),因为之后的所有的连接事件都以这一时刻为基准,呈现周期性变化。从红色框图中我们可以看到,第一个数据帧的时刻不能早于(1.25ms+transmitWindowOffset),同时也不能晚于(1.25 ms + transmitWindowOffset + transmitWindowSize)。
图3 发起连接时序图
(4)Interval, Latency & Timeout
一般情况下,人们的工作时间是朝九晚五,一周工作五天。但是在低功耗蓝牙技术的连接机制当中,我们采用了更加灵活的“弹性工作制”。对于低功耗蓝牙技术连接的弹性工作制,这里有三个参数需要了解,Interval,Lantency和Timeout。
图4 连接事件时序图
在连接建立之后,master和slave之间的数据交互我们可以称之为连接事件,连接事件的发生周期(connInterval)则是由Interval参数来进行设定,connInterval= Interval×1.25 ms, connInterval的取值范围则是在7.5 ms至4 s秒之间。因此,在确定了锚点之后,master和slave将按照connInterval确定的时间间隔进行数据的交互,如图4所示。
但是,对于低功耗蓝牙技术,低功耗的特性是需要特别考虑的,而且在实际的应用当中,不需要在每次connInterval都产生连接事件,因此引入了参数Lantancy,可以有效的减少连接事件的产生,connSlaveLatency= Latency。connSlaveLatency 定义了slave设备可以忽略多少个连续的连接事件,其不需要在这些被忽略的连接事件中侦听来自master的数据包,这也意味着slave设备不需要在每个连接事件产生的时刻都唤醒并打开射频接收机进行侦听,所以可以有效减少slave设备的功耗。这也是低功耗蓝牙技术能够实现其低功耗特性的一个重要的原因。
Timeout参数定义了连接超时的长度,connSupervisionTimeout= Timeout×10 ms,其取值范围在100 ms至32 s之间。不论是master还是slave,在其收到一个数据帧之后,如果等待了connSupervisionTimeout时长都没有下一个数据帧到来,则可以认为连接已经断开。在这里要强调的是,connSupervisionTimeout必须大于(1 + connSlaveLatency) × connInterval × 2,否则,slave设备即使是在Lantency状态,也会被误认为是连接超时,导致连接误断开。
(5)ChM & Hop
我们都知道,蓝牙使用的是跳频技术,当连接建立之后,master和slave设备就需要利用某种机制来在预先设定的信道图谱上、按照预先设定的跳频跨度进行跳频工作,信道图谱就来自ChM参数,每跳的跨度则来自于Hop参数。Hop是一个整数,取值范围在5至16之间。下面的公式提供了跳频的工作方式:
————————————————
版权声明:本文为CSDN博主「偏执灬」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sinat_23338865/article/details/52189538