文章目錄
- 前言
- 一、Generic Attribute Profile
- 1.1 UUID and Attributes
- 1.1.1 UUID
- 1.1.2 Attributes
- 1.2 GATT Profile hierarchy
- 1.3 GATT feature and procedure
- 二、Attribute protocol
- 2.1 Attribute PDU Format
- 2.2 Attribute protocol methods
- 三、L2CAP Protocol
- 3.1 L2CAP Overview
- 3.2 L2CAP PDU Format
- 3.2.1 L2CAP PDU format on a signaling channel
- 3.2.2 L2CAP PDU format on Security Manager protocol
- 3.2.3 L2CAP PDU format on Attribute protocol
- 更多文章:
前言
前篇博文Generic Access Profile介紹了藍牙設備之間是如何發現彼此、建立連接、實作配對與系結的,同時描述了設備如何實作無需連接的資料傳輸、如何實作等時同步資料傳輸、如何建立ACL和CIS 連接、如何加密認證通信鏈路等,
本篇文章主要介紹藍牙設備建立連接后,如何提供或回應服務、如何發現或請求服務,這就要靠GATT(Generic Attribute Profile)來定義了,GATT 為藍牙設備定義了Server role 和Client role 兩種角色(角色并不固定在設備上,同一設備不同時刻充當的角色可能不同):
- Server role:接收來自客戶端的服務請求,并向客戶端回傳回應資料,GATT 中的角色與GAP 中的角色相互獨立又相互兼容,GAP 中的Peripheral role 或Central role 都可以充當GATT 中的Server role;
- Client role:向服務器發送服務請求,并接收來自服務器的回應資料,GATT 中的角色與GAP 中的角色相互獨立又相互兼容,GAP 中的Peripheral role 或Central role 都可以充當GATT 中的Client role,

Server 根據設計需求會實作并向外公開一個或多個服務,Client 則根據需要發現Server 公開的部分或全部服務,Client 發現Server 提供的服務后,就可以向其請求相應的服務資料(既可以讀取服務器狀態資訊比如溫度傳感器的值,又可以改變服務器的狀態比如控制LED燈的亮滅),Server 接收到服務請求后會向Client 回應對應的服務資料(Server 可能需要Client 通過認證與授權),
BLE 采用“Server – Client” 架構,Server 專注于定義如何使用一個或多個屬性來實作某種特定的服務(包括可以提供的狀態資訊、可以執行的狀態切換等)以及如何訪問并使用這些服務(比如客戶端請求可讀取/可寫入狀態資訊、服務器可通知狀態更新資訊、訪問服務是否需要加密/認證/授權等);Client 專注于定義如何使用一個或多個服務來滿足某種特定的應用需求(比如可以使用光強感應服務、人體感應服務、照明服務等協同實作智能照明服務),
Server 定義的每個單獨服務十分簡單、而且是原子化的(表示一種服務只執行不可分割的特定操作),可以讓每個服務的行為更簡單明確,同時讓不同服務之間的組合更豐富多樣,Client 使用不同的原子服務組合,可以滿足豐富多樣的場景需求,相同的服務可以在不同應用中復用,滿足高內聚、低耦合的設計原則,
為何說明Client 請求服務、Server 回應服務的作業原理,下面擴展前篇博文談到的用戶場景:
用戶購買的心率帶設備為了安全傳輸心率資料,是可以被發現并連接的,對外公開的主要有心率服務、電池電量服務、設備名服務等,用戶的智能手機通過GAP 規范發現并連接了心率帶設備(可以通過公開的設備名服務從設備串列中選出目標設備),由于用戶需求是獲得心率值,心率帶對外提供該服務,因此心率帶處于Server role,智能手機處于Client role,
Client role 與Server role 建立連接后,Client role 首先需要知道Server role 能提供哪些服務,然后再根據應用規范去使用這些服務,Client role 發現Server role 公開服務的程序主要有四個:Primary Service Discovery(可以發現所有主要服務或者某一特定主要服務)、Relationship Discovery(該服務參考的其它服務)、Characteristic Discovery(可以發現所有特性或者某一特定特性)、Characteristic Descriptor Discovery, 智能手機先發現心率帶公開的心率服務和電池電量服務,再發現心率服務參考的時間服務(Secondary Service),接著發現心率服務包含的HRM Characteristic(Heart Rate Measurement) 和BSL Characteristic(Body Sensor Location),最后發現HRM Characteristic 包含的CCCD(Client Characteristic Configuration Descriptor),Heart Rate Service、Characteristic、Descriptor 之間的關系如下圖示,每一行四個欄位Handle、UUID、Permissions、Value 共同構成一個屬性,Characteristic 與Descriptor 都是由一個或多個屬性構成的,
Client role 已經發現了Server role 公開的所有Primary Service及其相關的Characteristic 和Descriptor,接下來看Client role 如何使用Server role 提供的服務,智能手機可通過特定APP向心率帶發起服務請求讀取心率值,心率帶將當前采集到的心率值回傳給智能手機(也可以配置為允許心率帶主動通知智能手機當前的心率值),如果再為心率帶增加時間服務,智能手機APP 就可以借助心率服務和時間服務為用戶繪制心電圖,并給出心率健康評估結果,Handle 0x0021 屬性是Heart Rate Service 的declaration(宣告服務型別為心率服務),Handle 0x0024 和0x002A 屬性分別是HRM Characteristic 和BSL Characteristic 的declaration(宣告特性性質為只讀,特性數值屬性句柄分別為0x0027和0x002C),Handle 0x0027 和0x002C 屬性分別是HRM Characteristic 和BSL Characteristic 的Value(描述特性數值的表示格式,心率測量值單位bpm – beats per minute,身體測量位置為手指),Handle 0x0028 屬性是HRM Characteristic 的Descriptor(客戶端特性配置為啟用通知,允許服務端主動通知客戶端更新后的心率值),

一、Generic Attribute Profile
GATT 使用屬性協議定義了服務框架,方便Client 與Server 之間實作基于服務請求/回應的通信,簡化了藍牙設備應用程式的開發,一個服務通常包含多個屬性,GATT 定義了如何使用屬性協議來發現、讀取、寫入這些屬性資料,

最上層的Application 應用層在Server 服務端主要是基于屬性協議定義各種服務的GATT 規范,在Client 客戶端主要是定義如何發現并使用這些服務來滿足某種特定的應用需求或實作某種特定的業務邏輯,本文主要介紹如何定義、發現、使用服務的GATT 規范,Attribute protocol 相當于GATT 的承載層,GATT 定義的服務是由多個屬性組成的,Attribute protocol 定義了屬性的報文格式和支持的操作方法,L2CAP 邏輯鏈路控制適配協議定義了報文的分片重組、重傳流控,上層GATT 或Attribute protocol 層資料封裝為SDU(Service Data Unit),下層Controller 資料封裝為PDU(Protocol Data Unit),
1.1 UUID and Attributes
在繼續介紹GATT Profile 之前,先介紹一個藍牙協議中比較重要的兩個概念UUID(Universally Unique Identifier) 和Attributes,
1.1.1 UUID
UUID(Universally Unique Identifier) 通用唯一識別碼是一個128位(16位元組)的數字,可以保證在所有空間和所有時間都是唯一的,除了藍牙之外,UUID 還用于許多協議和應用中(特別是分布式計算領域),它們的格式、用法在IETF(Internet Engineering Task Force)公布的標準 RFC 4122 中定義(技術上等同于 ITU-T Rec. X.667 | ISO / IEC 9834-8:2005 規范),
完整的UUID 需要占用16位元組,這對于鏈路層27位元組的有效資料載荷長度算是不小的負擔,為了減輕存盤、傳輸128位UUID 的負擔,BLE 規范添加了兩個附加的UUID 格式:16位UUID 和32位UUID,這些16位或32位的UUID 可以看作是基于Bluetooth Base UUID (00000000-0000-1000-8000-00805F9B34FB) 的偏移量,因此只能與Bluetooth 規范中定義的UUID 一起使用,也可以稱為標準Bluetooth UUID,這些標準Bluetooth UUID 可以借助Bluetooth Base UUID 重建為完整的128位UUID,只需要經過如下的運算即可:
128_bit_value = 16_bit_value * 296 + Bluetooth_Base_UUID
128_bit_value = 32_bit_value * 296 + Bluetooth_Base_UUID
16位UUID 可以通過高位補零轉換為32位UUID 格式,當UUID 包含在ATT PDU 中時,所有32位UUID 都應轉換為128位UUID,
16位UUID 雖然已經比較簡短了,為了增加可讀性,通常不直接使用數值,而是起一個名稱并加上書名號來表示,比如用《Include》 來表示數值為0x2802 的UUID,UUID 并沒有定義自身的用法,為了增加人工除錯時的可讀性,BLE 常用的那部分UUID 被分為以下幾組:
- 0x1800 ~ 0x26FF 用作 Service UUIDs
- 0x2700 ~ 0x27FF 用于標識計量單位 Units
- 0x2800 ~ 0x28FF 用于區分 Attribute Types
- 0x2900 ~ 0x29FF 用作 Characteristic Descriptors
- 0x2A00 ~ 0x7FFF 用于區分 Characteristic Types
1.1.2 Attributes
Attribute 是ATT(Attribute protocol)定義的最小資料物體,也是構成GATT 中Service、Characteristic、Descriptor 的基本元素,每個Attribute 都包含有關屬性本身的資訊和實際資料,客戶端與服務器之間進行的服務互動,最終都是對這些屬性的操作訪問,從前文GATT Heart Rate Service 圖示了解到,Attribute 由Handle、UUID、Permissions、Value 四部分構成,其邏輯表示如下:

- Attribute handle:屬性句柄是特定GATT服務器上每個屬性的唯一16位識別符號,便于區分并尋址某個屬性,有效的句柄范圍是0x0001 ~ 0xFFFF,可以把屬性句柄看作該屬性資源的記憶體地址或者指向該屬性資源的指標;
- Attribute type:使用UUID 區分并標識每種屬性的型別,比如溫度、壓強、體積、距離、功率、時間、充電狀態、開關狀態等可公開資料的型別,屬性協議為每種型別都分配了一個UUID(16位標準Bluetooth UUID 或完整的128位UUID);
- Attribute value:表示設備公開的狀態資訊,可以是固定長度或可變長度的八位位元組陣列,最大長度為512位元組,屬性值欄位不僅可以表示狀態資訊,還對上層的GATT Profile 層級結構的定義有重要作用,比如定義Service 宣告的屬性值為Service UUID、Characteristic 宣告的屬性值為<Characteristic Properties | Characteristic Value Attribute Handle | Characteristic UUID>;
- Attribute permissions:表示每個屬性的訪問限制或許可,屬性限制可分為四個型別:Readable / writable 的訪問權限、Encryption / No encryption required 的加密權限、Authentication / No Authentication required 的認證權限、Authorization / No Authorization required 的授權權限等,也可以使用上述多個型別的組合權限,
下面給出某BLE 設備屬性服務器定義的部分屬性供參考,支持的服務屬性包括:GAP Service、GATT Service、Battery State Service、Thermometer Humidity Service、Weight Service、Position Service、Alert Service、Manufacturer Service和Vendor Specific Service等(下圖用《》括起來的名字是UUID 的另一種表示方式,Attribute Value 中被{ } 括起來的部分表示該屬性值由多個欄位組成,被“ ” 括起來的部分表示字串),

1.2 GATT Profile hierarchy
GATT 中定義了的Profile 由一個或多個Service 組成,每個Service 可以看作是完成特定功能或特性的資料和相關行為的集合,由一個或多個Characteristic 構成,每個Characteristic 一般都包含一個資料或者一個公開行為,以及該資料的單位或者公開行為的單位,GATT Profile 的資料層級結構如下圖示:

- Service:完成特定功能或特性的資料和相關行為的集合,由一個或多個Characteristic 構成,可分為Primary Service 和Secondary Service 兩種型別:Primary Service 是公開此設備主要可用功能的服務(主要服務型別的16位UUID 值0x2800);Secondary Service 是為設備提供額外輔助資訊,但跟設備公開的功能無關的服務,一般被包含在主要服務或另一個輔助服務中(輔助服務型別的16位UUID 值0x2801),Service declaration 屬性訪問權限為只讀且不需要認證授權,屬性值為具體的服務種類,比如Heart Rate Service 的16為UUID 值為0x180D;

- Include Service:將服務器上存在的另一種服務定義參考到要定義的服務中,是一種重用其它服務的方法,當某一個服務被包含到當前服務中,當前服務就可以使用被包含服務定義的資料和行為,但不能更改被包含服務的資料和行為,Include declaration 的屬性值包含三個欄位:被包含服務宣告的屬性句柄、被包含服務屬性組合中的最后一個屬性句柄、被包含服務的UUID,比如前面給出的示例屬性串列中的《Include》屬性值為{0x0500, 0x0504, ?Manufacturer Service?};

- Characteristic:包含服務中使用的資料資訊,包括如何訪問該資料的屬性方法、如何表示或顯示該資料的格式資訊等,Characteristic declaration 屬性值也包括三個欄位:特征訪問方法、特征值屬性句柄、特征的UUID,比如本文開頭Heart Rate Service 中的HRM Characteristic declaration 的屬性值為{Notify, 0x0027, 0x2A37},其中0x2A37 是Heart Rate Measurement 的16位UUID;

- Characteristic Properties:包含當前Characteristic 支持的訪問方法資訊,支持的特征訪問方法有Broadcast、Read、Write、Notify、Indicate、Authenticated Signed Writes等,比如本文開頭Heart Rate Service 中的HRM Characteristic Properties 為Notify,BSL Characteristic Properties 為Read;

- Characteristic Value:包含當前Characteristic 定義的資料數值資訊,比如本文開頭Heart Rate Service 中的HRM Characteristic Value declaration 的屬性型別為Heart Rate Measurement 的UUID也即0x2A37,屬性值為實際測得的心率值;

- Characteristic Descriptor:包含當前Characteristic 的描述資訊、配置資訊、表示格式資訊等,比如本文開頭Heart Rate Service 中的HRM Characteristic 包含了一個CCCD(Client Characteristic Configuration Descriptor),該CCCD declaration 的屬性訪問權限為可讀寫,屬性值為0x0001,也即Bit Number 0 位Notification被置 1,表示為HRM Characteristic 啟用通知功能,Server 心率帶測量到的心率值以通知形式主動發送給Client 智能手機;

上述介紹的構成GATT Profile 的Service、Include Service、Characteristic、Characteristic Descriptor 等元素的屬性匯總如下:

1.3 GATT feature and procedure
前面介紹了如何使用Attribute 構成GATT Profile 資料層級結構,這里介紹如何使用Attribute protocol 來完成GATT Profile 定義的各種功能,GATT Profile 主要定義了如下11 個功能(feature),每個功能都映射到程序(procedure)和子程序(sub-procedure),這些程序和子程序描述了如何使用Attribute protocol 來完成相應的功能(下表中的M:Mandatory,O:Optional ),

- Server Configuration:Client 使用Exchange MTU (Maximum Transmission Unit) 程序與Server 交換雙方支持的MTU,僅當Client 或Server 可以處理的MTU 超過默認值23 位元組(LE 鏈路層支持的普通報文payload 為27 位元組,L2CAP Header 占用4 位元組,所以ATT_MTU 默認為23 位元組)時才會使用該程序(該程序對連接雙方都是可選的);

- Primary / Include Service Discovery:Client 使用Discover All Primary Services 或Discover Primary Services By Service UUID 子程序發現Server 公開的主要服務(可以發現所有主要服務或通過UUID 發現某個特定主要服務),待Client 發現主要服務后,可以通過Find Included Services 程序發現該主要服務所包含的其它服務,兩個程序可以讓Client 了解Server 公開的所有主要服務與輔助服務;

- Characteristic / Descriptor Discovery:Client 使用Discover All Characteristic of a Service 或Discover Characteristic by UUID 子程序發現Server 公開的某服務的Characteristic(可以發現某服務包含的所有Characteristic或者通過UUID 發現某個特定的Characteristic,通過UUID 發現某個特征實際上是發現所有特征后丟棄掉與UUID 不匹配的結果),待Client 發現Characteristic 后,可以通過Discover All Characteristic Descriptors 程序發現該Characteristic 包含的所有Descriptors,Characteristic 和Characteristic Descriptors 是構成Service 的基本元素,也是讀寫Server 公開資料或狀態資訊的載體;

- Characteristic Value Read:當Client 知道想要讀取的某個Characteristic 的特征值屬性句柄時,使用Read Characteristic Value 子程序從Server 讀取該特征值,如果Server 回應的特征值長度大于(ATT_MTU - 1)位元組則只能回傳特征值的前半部分,Client 可以使用Read Long Characteristic Values 子程序讀取完整的特征值,當Client 知道想要讀取的一組特征值句柄集時,可以使用Read Multiple Characteristic Values 子程序讀取該組的多個特征值,當Client 只知道想要讀取的特征型別UUID 而不知道特征值句柄時,可以使用Read Using Characteristic UUID 子程序讀取已發現該特征型別的所有特征值;

- Characteristic Value Write:當Client 知道想要寫入的某個Characteristic 的特征值屬性句柄時,使用Write Characteristic Value 子程序向Server 寫入一個特征值,如果要寫入的特征值長度大于 (ATT_MTU – 3) 位元組則應使用Write Long Characteristic Values 子程序向Server 寫入一個比較長的完整特征值,當Client 不需要確認寫入是否成功執行時,可以使用Write Without Response 子程序向Server 寫入特征值,該程序可以即時發送而不受流控約束,若Server 無法處理則靜默丟棄,當Client 需要在單個操作中按順序寫入多個值時,可以使用Characteristic Value Reliable Writes 子程序向Server 傳輸要準備寫入的多個特征值,待Client 驗證服務器回應的資料無誤后,對已傳輸到Server 上且經過檢驗的全部特征值執行寫入操作;

- Characteristic Descriptor Value Read / Write:Client 讀取或寫入Characteristic Descriptor Value 跟前面介紹的讀取或寫入Characteristic Value 類似,當Client 知道想要讀取或寫入的Characteristic Descriptor 屬性句柄時,使用Read Characteristic Descriptors 或Write Characteristic Descriptors 子程序從Server 讀取或向Server 寫入特征描述符,如果特征描述符的長度大于單個請求報文容納的上限,Client 可以使用Read Long Characteristic Descriptors 或Write Long Characteristic Descriptors 子程序從Server 讀取或向Server 寫入比較長的完整特征描述符;

- Characteristic Value Notifications:當Server 被配置為向Client 通知特征值,且不需要確認是否成功接收到通知時,使用Notifications 子程序向Client 通知特定屬性句柄及其對應的特征值,當Server 被配置為向Client 通知多個特征值時,可以使用Multiple Variable Length Notifications 子程序;

- Characteristic Value Indication:當Server 被配置為向Client 指示特征值,并期望屬性協議層確認已成功接收到指示時,使用Indications 子程序向Client 指示特定屬性句柄及其對應的特征值,后續會受到來自Client 的確認資訊,

上述介紹的每個GATT 功能及其子程序到ATT 屬性協議操作指令之間的映射關系匯總如下(屬性協議操作指令將會在下文介紹):

二、Attribute protocol
前面已經介紹了Attribute 的邏輯結構,這里主要介紹Attribute 的報文格式和支持的操作指令或方法,
2.1 Attribute PDU Format
Attribute PDU 包含三個部分:1 位元組長度的指令操作碼、可變長度的屬性引數、可選的12 位元組長度認證簽名資訊,屬性PDU 格式如下:

Attribute PDU 中的Attribute Parameters 欄位通常包含前面介紹的屬性邏輯結構中Attribute Handle、Attribute Type、Attribute Value、Attribute Permissions 四個欄位中的零個或多個,只有Server 與Client 之間需要互動的欄位資訊才會包含在Attribute PDU 中,
2.2 Attribute protocol methods
GATT Profile 的Procedure 描述了如何使用Attribute protocol 來完成相應的Feature,Client 通過Attribute protocol 可以發現并獲取或更改屬性服務器上的屬性,按照Client 與Server 之間的互動方式劃分,Attribute protocol 由以下六種基本操作構成(也即Attribute PDU 有六種基本型別,由后綴區分):

- Request / Response:Client 向Server 發送ATT Request,以要求服務器執行相關操作并回傳ATT Response,Client 一次只能發送一條Request,也即只能在收到上一條請求的Response 后才能繼續發送下一條Request,這降低了構建屬性服務器的復雜度,Server 回傳給Client 的回應可能是與請求直接相關的回應,也可能是說明請求為何失敗的錯誤回應;

- Command:Client 向Server 發送ATT Command,讓服務器執行某種操作,但不需要Server 回傳回應,Client 可以連續向Server 發送多條命令而不受流控約束,當Server 無法回應命令時可直接忽略,Client 不知道Command的執行結果也不會收到錯誤回應,因此ATT Command 的執行是不可靠的;

- Indication / Confirmation:Server 向Client 發送ATT Indication,讓客戶端獲知某屬性的數值,Client 需要回傳給Server 一個ATT Confirmation,Server 一次也只能發送一條Indication,也即只能在收到上一條指示的Confirmation 后才能發送下一條Indication;

- Notification:Server 向Client 發送ATT Notification,以告知客戶端某屬性的數值,但不需要Client 回傳確認資訊,Server 也可以連續向Client 發送多條命令而不受流控約束,Client 來不及處理的通知也將直接丟棄,Server 不知道Notification 的執行結果也不會收到錯誤資訊,因此ATT Notification 的執行也是不可靠的,

Attribute protocol 支持的操作指令匯總如下(對照GATT procedure 到ATT protocol opcodes 的映射關系更容易理解):

- Error handling:指令ATT_ERROR_RSP 用于回傳請求執行失敗的原因,回傳的屬性引數包括產生此錯誤的請求的屬性操作碼、產生該錯誤的原始請求中的屬性句柄、表示產生此錯誤的原因的錯誤碼等;
- MTU exchange:在BLE 連接中,屬性協議默認的MTU 長度是23 位元組,如果設備想發送更大的資料包,可以通過ATT_EXCHANGE_MTU_REQ 和ATT_EXCHANGE_MTU_RSP 指令協商一個更長的MTU,一般由Client 發起交換MTU 的請求,協商結果為Client / Server 二者可接收的MTU 長度中的較小值;
- Find information:查找資訊請求有兩種:一種是Client 發送ATT_FIND_INFORMATION_REQ 指令,請求給定屬性句柄集合內的所有屬性資訊,比如前面介紹的Discover All Characteristic Descriptors 程序;另一種是Client 發送ATT_FIND_BY_TYPE_VALUE_REQ 指令,請求符合特性屬性型別UUID 的所有屬性資訊,比如前面介紹的Discover Primary Services By Service UUID 程序;
- Reading attributes:讀取屬性值請求有五種:一、ATT_READ_BY_TYPE_REQ 指令按屬性型別UUID 讀取屬性值;二、ATT_READ_REQ 指令按屬性句柄Handle 讀取屬性值;三、ATT_READ_BLOB_REQ 指令按屬性句柄Handle 配合偏移量Offset 讀取長屬性值;四、ATT_READ_MULTIPLE_REQ 和ATT_READ_MULTIPLE_VARIABLE_REQ 指令按屬性句柄集合Set Of Handles 讀取多個屬性值;五、ATT_READ_BY_GROUP_TYPE_REQ 指令按屬性組型別UUID 讀取一組屬性值;
- Writing attributes:普通的寫入屬性值請求有兩種:一、ATT_WRITE_REQ 指令按屬性句柄Handle 寫入屬性值,需要接收到回應資訊;二、ATT_WRITE_CMD 和ATT_SIGNED_WRITE_CMD 指令也是按屬性句柄Handle 寫入屬性值,但不需要回傳任何回應資訊;
- Queued writes:排隊寫入屬性值請求分為兩個階段:第一階段是準備寫入請求,也即Client 通過ATT_PREPARE_WRITE_REQ 指令將要寫入的一個或多個屬性值發送到Server,并通過ATT_PREPARE_WRITE_RSP 指令確認Server 接收到的屬性值無誤;第二階段是執行寫入請求,也即Client 通過ATT_EXECUTE_WRITE_REQ 指令將之前發送給Server 并經確認無誤的屬性值立即寫入到對應的屬性中,比如前面介紹的Write Long Characteristic Values 或Characteristic Value Reliable Writes 程序;
- Server initiated:服務器啟動更新請求實際上是從Server 向Client 發送屬性資訊的方式,服務器上屬性值有更新時可以及時將更新后的屬性值發送給客戶端,這樣客戶端就不需要定期輪詢屬性值,從而節省了功率和帶寬,服務器啟動更新程序也有兩種方式:一、Server 發送ATT_HANDLE_VALUE_IND 指令,讓Client 獲知特定屬性句柄及其對應的屬性值,且需要客戶端回傳ATT_HANDLE_VALUE_CFM 確認指令;二、Server 發送ATT_HANDLE_VALUE_NTF 指令,讓Client 獲知特定屬性句柄及其對應的屬性值,但不需要客戶端回傳確認資訊,Server 還可以通過發送ATT_MULTIPLE_HANDLE_VALUE_NTF 指令,讓Client 一次性獲知多個屬性句柄的屬性值,
三、L2CAP Protocol
3.1 L2CAP Overview
本文開頭已經介紹了在Attribute protocol 與LE Controller 之間還有一層L2CAP(Logical Link Control and Adaptation Protocol and Adaptation Protocol) 協議層,L2CAP 協議層的功能架構圖如下(可以將L2CAP 協議與TCP 協議對比理解):

- Protocol/channel multiplexing:L2CAP 上層不止承載一個協議,比如ATT 屬性協議、SMP 安全管理協議等報文都需要經L2CAP 路由到LE Controller,這里L2CAP 起到協議多路復用器的作用,L2CAP 為上層每個協議分配一個邏輯信道,多個邏輯信道可以復用下層LE Controller 的同一個物理信道,來傳輸不同的協議報文;
- Segmentation and reassembly:L2CAP 上層的應用資料包或服務資料包SDU(Service Data Unit) 通常比較大(最大可達到64 KB),下層LE Controller 可接受的報文PDU(Protocol Data Unit)容量較小(有效負載最大為27 Bytes,擴展報文最大為 251 Bytes),中間的L2CAP 可以起到資料包分段重組的作用,將上層Application 較大的SDU 分段為較小的PDU 后發送給LE Controller,或將從LE Controller 接收到的多個PDU 重組為完整的SDU 再遞交給上層Application 處理;
- Flow control per L2CAP channel:為了避免空中傳輸鏈路堵塞,導致資料傳輸錯誤或丟失,L2CAP 協議為每個L2CAP channel 提供了基于視窗的流量控制機制;
- Error control and retransmissions:空中傳輸鏈路容易受到干擾,導致資料傳輸錯誤或丟失,L2CAP 協議為傳輸的資料提供錯誤校驗和重新傳輸機制,當發現傳輸的資料包錯誤時,請求對方重新傳輸錯誤的資料包,跟流量控制機制一起保證藍牙無線傳輸的可靠;
- Support for Streaming:藍牙音頻服務是一個很重要的應用場景,像音頻這類資料流傳輸對時延比較敏感,對偶爾出現的少量錯誤是可以容忍的,L2CAP 協議為Streaming 流資料傳輸提供了相應的L2CAP channel,而且不對其使用流量控制和錯誤重傳機制,盡可能保證流資料傳輸的及時同步,
3.2 L2CAP PDU Format
L2CAP 既然起到多協議復用器的作用,可以將多個邏輯信道映射到同一個物理信道,為了便于區分不同的邏輯信道,L2CAP 報文需要包含Channel ID 欄位,下面給出L2CAP 的基本報文格式如下(為了實作更多上述功能,L2CAP 還有更復雜的報文格式):

BLE 協議堆疊中L2CAP 支持的CID (Channel ID) 型別如下:

上述CID 主要分為兩類:一類是固定信道,比如為Attribute protocol 分配的CID 是0x0004、為L2CAP LE Signaling channel 分配的CID 是0x0005、為Security Manager protocol 分配的CID 是0x0006;另一類是使用程序中動態分配的可變信道,下文將分別對BLE 支持的三個L2CAP 固定信道報文及指令做簡單介紹,
前面介紹的只是Basic L2CAP Mode下的報文格式,L2CAP 為Flow Control Mode、(Enhanced) Retransmission Mode、Streaming Mode、LE (Enhanced) Credit Based Flow Control Mode 提供了更復雜的報文結構如下(本文不展開介紹了,可以參考Core_v5.2 手冊的[Vol 3] Part A, Section 3 ):

3.2.1 L2CAP PDU format on a signaling channel
從L2CAP architectural blocks 圖中可以看到兩種資料流:紅色的Controls frame 和黑色的Data/packet flow,其中Controls frame 用于L2CAP 信道管理,傳輸Controls frame 信道為signaling channel,在signaling channel 上傳輸的Controls frame(C-frame) 格式如下:

對于BLE 協議,在signaling channel 上傳輸的Controls frame 的CID 為0x0005(對于BR/EDR 協議,C-frame 的CID 為0x0001),Controls frame 的Information payload 部分是signaling command format,包括信令操作碼Code、信令識別符號Identifier、資料長度Length、資料資訊data 四個部分,這里只列出BLE 協議常用的信令操作碼及其描述如下(這里刪去了BR/EDR支持而BLE不支持的信令操作碼):

- Command Reject:當設備收到了不支持或不理解的命令時,或者接收到的命令超過MTU 而溢位時,可以回傳L2CAP_COMMAND_REJECT_RSP 報文告知對方拒絕執行命令的原因;
- Create an L2CAP channel:通過發送L2CAP_LE_CREDIT_BASED_CONNECTION_REQ 或L2CAP_CREDIT_BASED_CONNECTION_REQ 命令,在兩個設備之間創建并配置L2CAP Channel;
- Connection Parameters Update:在BLE 連接中,如果Slave 希望修改當前的連接引數可以使用L2CAP_CONNECTION_PARAMETER_UPDATE_REQ 命令向Master 發起連接引數更新請求,Master 可以接受或者拒絕Slave 請求的連接引數,并通過相應的回應報文告知Slave 結果;
- Reconfigure MTU or MPS:當設備支持的MTU(Maximum Transmission Unit) 或MPS(Maximum PDU Payload Size) 值變化時,可以發送L2CAP_CREDIT_BASED_RECONFIGURE_REQ 命令重新配置MTU 或MPS 的值;
- Flow Control:當設備還能接收Credit-based frame (K-frame)時,通過發送L2CAP_FLOW_CONTROL_CREDIT_IND 告知對方可以繼續發送的K-frame 數量,用于流量控制;
- Terminating an L2CAP channel:設備可以發送L2CAP_DISCONNECTION_REQ 命令來終止特定的L2CAP Channel,
3.2.2 L2CAP PDU format on Security Manager protocol
前篇博文介紹了Security Manager protocol 的配對程序,兩個設備之間要完成配對也需要雙方互動相關的指令或報文,SMP 配對和安全管理相關的指令或報文格式如下:

L2CAP 為Security Manager protocol 分配的Channel ID 為0x0006,SMP command Information payload 包含指令操作碼Code 和資料Data 兩部分,這里列出BLE 支持的SMP 指令操作碼如下:

下面依然按照BLE 配對程序的三個階段簡單介紹SMP 指令:
- Phase 1(Pairing Feature Exchange):Master 使用Pairing Request 報文開始配對功能交換程序,Slave 也可以使用Security Request 命令請求Master 開始配對程序,如果配對程序中出現問題(包括下面兩個階段中出現的問題),則通過Pairing Failed 報文告知對方配對失敗的原因;

- Phase 2(Long Term Key Generation):雙方成功完成配對功能交換后,通過Pairing Public Key 報文交換本設備的Public Key(如果Slave 有鍵盤輸入能力,可通過Keypress Notification 報文通知Master 輸入的配對碼),通過Pairing Confirm 和Pairing Random 報文交換Confirm value 和Random value, 然后開始計算并生成LTK,LTK 計算完成后,雙方通過Pairing DHKey Check 報文生成并相互驗證DHKey value,如果驗證成功則表示生成LTK 的程序沒有問題;

- Phase 3(Transport Specific Key Distribution):雙方建立加密連接后,開始生成并分發一些專用的密鑰,比如使用Encryption Information 報文分發LTK(用于加密會話資訊),使用Master Identification 分發EDIV(Encrypted Diversifier) 和Rand(用于計算并生成LTK),使用Identity Information 報文分發IRK(Identity Resolving Key,用于生成或決議設備的resolvable private address),使用Identity Address Information 報文分發設備的public device address 或static random address,使用Signing Information 報文分發CSRK(Connection Signature Resolving Key,用于對資料進行簽名或驗證接收資料的簽名資訊),

3.2.3 L2CAP PDU format on Attribute protocol
Attribute protocol 的報文格式前面已經介紹過了,在L2CAP 層加上一個L2CAP Header,其中Channel ID 為0x0004,報文格式如下:

Attribute protocol 支持的操作指令前面已經介紹過了,這里不再贅述,
更多文章:
- 《BLE 技術(五)— Generic Access Profile + Security Manager(Core_v5.2)》
- 《GATT (Services and Characteristics)》
- 《Bluetooth Core Specification_v5.2》
- 《BLE技術揭秘》
- 《藍牙協議分析》
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/135241.html
標籤:其他
