Core_v6.2 Vol 3 Part F 学习笔记(二):Protocol Overview——ATT 协议模型

0. 本篇说明

本文继续学习 Bluetooth Core Specification v6.2:

Vol 3, Part F:Attribute Protocol,简称 ATT

本篇对应章节:

2 Protocol overview

上一篇我们已经知道,ATT 是用来发现、读取、写入对端设备 attributes 的协议。
这一篇开始进入 ATT 的协议模型,也就是搞清楚:

  • ATT 有哪些角色;

  • Server 是什么;

  • Client 是什么;

  • Attribute 到底由哪些东西组成;

  • Attribute type、handle、permissions 分别干什么;

  • 为什么一个设备可以同时是 Client 和 Server;

  • 为什么一个设备上只能有一个 ATT Server 实例;

  • ATT bearer 是什么;

  • LE 和 BR/EDR 上 ATT bearer 有什么差异。

一句话概括本篇:

ATT 是一个 Client/Server 模型的属性访问协议,Server 暴露 Attribute Database,Client 通过 ATT bearer 访问这些 attributes。

更接地气一点:

Server 像“货架管理员”,货架上摆着一堆带编号的商品;
Client 像“顾客”,通过商品编号去查、读、写;
ATT bearer 像“柜台窗口”,请求和响应都从这个窗口走。


1. Protocol Overview 原文结构拆解

这一节虽然标题叫 “Protocol overview”,但它其实浓缩了 ATT 后面所有章节的核心思想。

可以拆成 8 个知识点:

编号知识点说明
1ATT 定义两种角色Server role 和 Client role
2Server 暴露 attributesClient 通过 ATT 访问这些 attributes
3Attribute 有三个关联属性type、handle、permissions
4Attribute type 说明属性代表什么通常由 UUID 表示
5Attribute handle 唯一标识 attributeClient 靠 handle 读、写、接收通知
6Permissions 用于限制访问但不能通过 ATT 直接访问 permissions
7设备可以同时是 Client 和 Server同一设备可以双角色并发
8ATT 请求通过 ATT bearer 发送一个 bearer 对应一个 L2CAP channel

后面所有 PDU,本质上都围绕这几个点展开。


2. ATT 定义两种角色:Server 和 Client

2.1 原文含义

Protocol overview 开头说明:

Attribute Protocol 定义两种角色:server role 和 client role。

这里要注意,ATT 的 Client/Server 不是物理设备类型,也不是 Central/Peripheral 的同义词。

2.2 逐行解释

原文含义中文解释工程理解
ATT defines two rolesATT 定义两种角色这是 ATT 自己的逻辑角色
a server roleServer 角色保存 attributes,响应访问
a client roleClient 角色访问对端 attributes
server exposes attributesServer 暴露一组 attributesServer 有 Attribute Database
client accesses attributesClient 通过 ATT 访问这些 attributesClient 发 request / command

2.3 Server 是什么?

ATT Server 是保存 attributes 的一方。

ATT Server

Attribute Database

Attribute 1

Attribute 2

Attribute 3

Server 的典型职责:

职责示例
保存 Attribute DatabaseGATT DB
接收 Client 请求ATT_READ_REQ、ATT_WRITE_REQ
返回响应ATT_READ_RSP、ATT_WRITE_RSP
检查 handle 是否有效无效则返回 Invalid Handle
检查读写权限不允许读写则返回错误
检查安全条件是否加密、认证、授权
主动通知 ClientATT_HANDLE_VALUE_NTF
主动指示 ClientATT_HANDLE_VALUE_IND

2.4 Client 是什么?

ATT Client 是访问 Server attributes 的一方。

Discover

Read

Write

Response

Notification / Indication

ATT Client

ATT Server

Attribute Database

Client 的典型职责:

职责示例
发现 attributesFind Information、Read By Type
读取 attribute valueRead Request
写入 attribute valueWrite Request、Write Command
接收 notificationHandle Value Notification
接收 indicationHandle Value Indication
发送 confirmationHandle Value Confirmation
管理事务状态Request 发出后等待 Response

2.5 Client/Server 与 Central/Peripheral 的区别

很多初学者最容易把这几个角色搅成一锅粥。

概念所属层级说明
CentralGAP / Link 层角色通常发起 BLE 连接
PeripheralGAP / Link 层角色通常广播并被连接
ATT ClientATT 层角色访问对端 attribute
ATT ServerATT 层角色暴露 attribute database
GATT ClientGATT 层角色发起 GATT procedures
GATT ServerGATT 层角色提供 GATT database

它们不是一回事。

典型情况下,手机作为 Central 连接手环,手机通常是 GATT Client / ATT Client,手环通常是 GATT Server / ATT Server。

但这不是强制绑定。

一个设备可以是:

设备Link 层角色ATT 角色
手机CentralATT Client,也可以是 ATT Server
手环PeripheralATT Server,也可以是 ATT Client
双模网关Central / Peripheral 都可能Client / Server 都可能

所以不要写死:

Central == Client
Peripheral == Server

这在简单 BLE demo 里可能“看起来对”,但在真实协议栈里会把人坑进沟里。


3. Attribute 是一个 discrete value

3.1 原文含义

Protocol overview 说:

An attribute is a discrete value.

这里的 discrete value 可以理解成“独立的数据项”。

ATT 不关心这个数据项在业务上代表什么。
它只关心这个数据项怎么被标识、怎么被访问、有没有权限限制。

3.2 Attribute 的三个关联属性

规范把 attribute 关联的内容列成三项:

属性中文说明
attribute type属性类型由 UUID 定义
attribute handle属性句柄Server 上唯一标识一个 attribute
permissions权限集合由使用该 attribute 的上层规范定义

可以画成这样:

Attribute

Attribute Type
UUID

Attribute Handle
16-bit

Permissions
Read / Write / Security

注意,这里看起来少了一个东西:value。

因为原文说 attribute 本身是一个 discrete value,同时又有 type、handle、permissions 这些关联属性。
从工程建模上,我们通常会把它整理成:

Attribute = Handle + Type + Value + Permissions

也就是:

Attribute

Handle

Type / UUID

Value

Permissions

3.3 工程中的 Attribute 数据结构

一个最小 ATT/GATT 数据库项,大概会写成这样:

typedef struct {
    uint16_t handle;
    uint8_t  uuid_type;      // 16-bit / 32-bit / 128-bit
    uint8_t  uuid[16];
    uint8_t *value;
    uint16_t value_len;
    uint16_t permissions;
} att_attribute_t;

这个结构不是规范原文规定的 C 结构,只是工程实现中常见的抽象。


4. Attribute Type:说明这个属性“是什么”

4.1 原文含义

Protocol overview 说明:

Attribute type specifies what the attribute represents.

也就是说,Attribute Type 负责说明这个 attribute 代表什么。

4.2 Attribute Type 与 UUID

Attribute Type 由 UUID 定义。

UUID 类型用途
16-bit UUIDBluetooth SIG 分配的常用类型
32-bit UUID可扩展类型,需要映射到 128-bit UUID
128-bit UUID厂商自定义类型常用

例如:

Attribute Type说明
0x2800Primary Service Declaration
0x2803Characteristic Declaration
0x2902Client Characteristic Configuration Descriptor
0x2A00Device Name
0x2A19Battery Level

这里要注意:

UUID 说明 attribute 是什么,handle 说明 attribute 在哪里。

4.3 通俗理解

如果 Attribute Database 是一个小区:

ATT 概念类比
Attribute Handle门牌号
Attribute Type / UUID房屋用途
Attribute Value房子里放的东西
Permissions门禁规则

例如:

HandleUUIDValue
0x00010x2800 Primary ServiceGAP Service UUID
0x00020x2803 Characteristic DeclarationDevice Name 声明
0x00030x2A00 Device Name"MyDevice"

Client 想读 Device Name 时,不是直接说:

我要读 Device Name

而是说:

ATT_READ_REQ(handle = 0x0003)

UUID 帮你发现它,handle 帮你访问它。


5. Bluetooth SIG defined attribute types 与 Non-Bluetooth SIG types

5.1 原文含义

Protocol overview 还提到两类 attribute type:

类型说明
Bluetooth SIG defined attribute types由 Bluetooth SIG 定义,记录在 Assigned Numbers 中
Non-Bluetooth SIG attribute types非 Bluetooth SIG 定义,通常是厂商自定义 UUID

5.2 工程解释

如果你做标准服务,比如 Battery Service,那么会使用 SIG 定义的 UUID:

服务 / 特征值UUID
Battery Service0x180F
Battery Level0x2A19

如果你做私有 OTA 服务,就可能定义 128-bit UUID:

12345678-1234-5678-1234-56789abcdef0

5.3 常见坑

厂商自定义 UUID 最容易出问题的是字节序。

很多抓包工具显示 UUID 的方式和代码数组里的存储方式不一致。
你以为自己写的是:

12345678-1234-5678-1234-56789abcdef0

结果代码里数组小端排布,看起来像被蓝牙规范放进洗衣机甩干了一遍。

工程建议:

  • 统一封装 UUID 比较函数;

  • 不要到处手写 memcmp;

  • 打日志时同时打印 canonical string 和 raw bytes;

  • 抓包和代码里的 UUID 表示方式要做对照表。


6. Attribute Handle:Client 访问 attribute 的关键

6.1 原文含义

Protocol overview 说明:

Attribute handle uniquely identifies an attribute on a server.

也就是说,在同一个 ATT Server 上,handle 唯一标识一个 attribute。

6.2 handle 的作用

handle 用在下面几个场景:

场景例子
Read RequestClient 通过 handle 读取 value
Write RequestClient 通过 handle 写入 value
NotificationServer 告诉 Client 哪个 handle 的 value 变化
IndicationServer 指示 Client 哪个 handle 的 value 变化
Find / DiscoverClient 发现 Server 上有哪些 handle

6.3 handle 和读写操作

普通读:

ATT ServerATT ClientATT ServerATT ClientATT_READ_REQ(handle = 0x0003)ATT_READ_RSP(value)

普通写:

ATT ServerATT ClientATT ServerATT ClientATT_WRITE_REQ(handle = 0x0008, value = 0x0100)ATT_WRITE_RSP

Notification:

ATT ServerATT ClientATT ServerATT ClientATT_HANDLE_VALUE_NTF(handle = 0x0007, value = 87)

6.4 handle 的工程意义

handle 是 ATT 层的核心索引。

ATT Server 收到请求后,第一步通常是查 handle:

att_attribute_t *att_db_find_by_handle(uint16_t handle)
{
    for (int i = 0; i < att_db_count; i++) {
        if (att_db[i].handle == handle) {
            return &att_db[i];
        }
    }

    return NULL;
}

如果找不到,后续就会返回类似:

Invalid Handle

或者在某些 discovery 场景返回:

Attribute Not Found

具体返回什么,要看对应 PDU 的规范要求。


7. Permissions:权限存在,但不能通过 ATT 直接访问

7.1 原文含义

Protocol overview 里有一句非常重要:

permissions are defined by each higher layer specification that utilizes the attribute; these permissions cannot be accessed using the Attribute Protocol.

意思是:

  • Attribute 的 permissions 由使用它的上层规范定义;

  • ATT 本身不能直接读取 permissions。

7.2 逐句解释

原文含义中文解释工程理解
permissions are defined by higher layer specification权限由上层规范定义比如 GATT、Service 规范、Profile 规范
utilizes the attribute使用该 attribute 的规范谁定义这个 attribute,谁规定它怎么访问
cannot be accessed using ATT不能通过 ATT 直接访问 permissionsClient 不能发一个 ATT 命令直接查询权限表

7.3 什么叫不能通过 ATT 访问 permissions?

这点很容易误解。

Client 不能这样问 Server:

请告诉我 handle 0x0003 的权限是什么?

ATT 没有这种通用 PDU。

但 Client 可以通过访问结果间接知道:

操作可能结果
读一个不可读 attribute返回 Read Not Permitted
写一个不可写 attribute返回 Write Not Permitted
未加密读取安全 attribute返回 Insufficient Encryption
未认证访问 MITM 保护 attribute返回 Insufficient Authentication
密钥长度不够返回 Encryption Key Size Too Short

也就是说,权限像门禁规则。
你不能直接问物业“这扇门权限表打印一份给我”,但你刷卡失败时,门禁会告诉你“大概哪里不行”。

7.4 工程中的权限设计

常见权限 bit 可能这样设计:

#define ATT_PERM_READ              0x0001
#define ATT_PERM_WRITE             0x0002
#define ATT_PERM_READ_ENCRYPT      0x0004
#define ATT_PERM_WRITE_ENCRYPT     0x0008
#define ATT_PERM_READ_AUTHEN       0x0010
#define ATT_PERM_WRITE_AUTHEN      0x0020
#define ATT_PERM_AUTHORIZE         0x0040

读请求处理时可能这样:

static uint8_t att_check_read_permission(att_attribute_t *attr,
                                         att_security_t *sec)
{
    if ((attr->permissions & ATT_PERM_READ) == 0) {
        return ATT_ERR_READ_NOT_PERMITTED;
    }

    if ((attr->permissions & ATT_PERM_READ_ENCRYPT) &&
        !sec->encrypted) {
        return ATT_ERR_INSUFFICIENT_ENCRYPTION;
    }

    if ((attr->permissions & ATT_PERM_READ_AUTHEN) &&
        !sec->authenticated) {
        return ATT_ERR_INSUFFICIENT_AUTHENTICATION;
    }

    return ATT_ERR_SUCCESS;
}

7.5 常见坑

权限不在 ATT PDU 里,但 ATT Server 处理每个 PDU 时都要查权限。

这就像餐厅菜单上不一定写“厨房是否允许你进”,但你真往厨房冲,保安一定会拦你。


8. Client 发送 Request,Server 必须响应

8.1 原文含义

Protocol overview 明确说明:

A client may send Attribute Protocol requests to a server, and the server shall respond to all requests that it receives.

这句话里的 shall 很重要。

8.2 逐句解释

原文含义中文解释工程意义
Client may send requestsClient 可以发送 ATT requestsClient 主动访问 Server
Server shall respondServer 必须响应收到 Request 不能装死
all requests it receives所有收到的 requests不支持也要用 Error Response 回

8.3 Request 和 Response 的基本模型

ATT ServerATT ClientATT ServerATT Clientalt[成功][失败]ATT_XXX_REQATT_XXX_RSPATT_ERROR_RSP

比如读请求:

ATT ServerATT ClientATT ServerATT Clientalt[handle 有效且允许读][handle 无效或权限不满足]ATT_READ_REQ(handle)ATT_READ_RSP(value)ATT_ERROR_RSP

8.4 工程注意

只要是 Request,就必须有结果:

Request 情况Server 应该做什么
支持且成功返回对应 Response
支持但失败返回 ATT_ERROR_RSP
不支持该 Request返回 ATT_ERROR_RSP,错误码一般是 Request Not Supported
PDU 格式非法返回 ATT_ERROR_RSP 或按规范处理
权限不足返回对应权限错误
handle 不存在返回对应 handle/attribute 错误

不能这样:

收到不支持的 request,直接丢弃

这会导致 Client 等超时。
协议栈里最怕这种“沉默是金”的行为,因为调试时你会看到 Client 像等对象回消息一样,越等越焦虑。


9. 一个设备可以同时是 Client 和 Server

9.1 原文含义

Protocol overview 说明:

A device can implement both client and server roles, and both roles can function concurrently in the same device and between the same devices.

意思是:

  • 一个设备可以同时实现 Client 和 Server;

  • 两个角色可以在同一个设备里并发工作;

  • 同一对设备之间,也可以双向同时存在 Client/Server 关系。

9.2 图示

Device BDevice ADevice BDevice AA 作为 Client 访问 B 的 ServerB 也可以作为 Client 访问 A 的 ServerATT_READ_REQATT_READ_RSPATT_WRITE_REQATT_WRITE_RSP

9.3 工程解释

这意味着协议栈不能假设:

我连接对方后,只会作为 Client

或者:

我是 Peripheral,所以我只会作为 Server

真实产品里可能出现:

场景说明
手机读手环电量手机是 Client,手环是 Server
手环读手机时间服务手环是 Client,手机是 Server
两个设备互相同步状态双方都同时是 Client 和 Server
EATT 多 bearer 并发多个 ATT bearer 同时存在事务

9.4 工程设计建议

协议栈内部最好拆分:

ATT Layer

ATT Client Engine

ATT Server Engine

ATT Bearer Manager

Attribute Database

TX Scheduler

Client 和 Server 状态机不要写成互斥。

否则一旦遇到双向 GATT 或 EATT,就会出现各种玄学 bug。


10. 每个 Bluetooth Device 只有一个 Server 实例

10.1 原文含义

Protocol overview 中有一个非常关键的约束:

There shall be only one instance of a server on each Bluetooth device.

也就是说:

每个蓝牙设备上只能有一个 ATT Server 实例。

这个点很重要,尤其是理解多 bearer 和 GATT database 时。

10.2 为什么只能有一个 Server?

因为 handle namespace 必须一致。

规范进一步说明,这意味着:

attribute handles shall be identical for all supported bearers.

也就是说,同一个设备如果有多个 ATT bearer,不管你从哪个 bearer 访问,看到的 handle 应该是一致的。

10.3 图示

Bluetooth Device

One ATT Server Instance

One Attribute Database

ATT Bearer 1

ATT Bearer 2

ATT Bearer 3

错误理解:

Bluetooth Device

ATT Server 1

ATT Server 2

DB 1

DB 2

Bearer 1

Bearer 2

后面这种设计容易导致:

  • 同一个 handle 在不同 bearer 上含义不一样;

  • GATT cache 混乱;

  • EATT 并发访问不一致;

  • BR/EDR bearer 和 LE bearer 看到的数据库不一致;

  • 对端 Client 怀疑人生。

10.4 工程意义

如果一个设备同时支持:

  • LE fixed ATT bearer;

  • LE EATT bearer;

  • BR/EDR ATT bearer;

它们看到的 handle 应该一致。

也就是说:

Bearerhandle 0x0003 应该代表
LE fixed ATT bearerDevice Name
LE EATT bearerDevice Name
BR/EDR ATT bearerDevice Name

不能出现:

Bearerhandle 0x0003
LE fixed ATT bearerDevice Name
EATT bearerBattery Level
BR/EDR bearerFirmware Version

那就不是协议栈,是“平行宇宙”。


11. 对于同一个 Client,Server 有一套 attributes

11.1 原文含义

Protocol overview 还说明:

For a given client, the server shall have one set of attributes, which shall have the same value and properties irrespective of which bearer is used.

这句话可以拆成三层理解:

要点中文解释
For a given client对于某一个特定 Client
one set of attributesServer 有一套 attributes
same value and properties不管用哪个 bearer,value 和 properties 应该一致

11.2 举例说明

假设 Client A 通过两个 ATT bearer 访问 Server:

Client A

ATT Bearer 1

ATT Bearer 2

ATT Server

Attribute Set for Client A

如果 Client A 通过 Bearer 1 读取 handle 0x0007,得到 Battery Level = 87。
那么它通过 Bearer 2 读取同一个 handle,应该看到同一套 attribute 视图。

11.3 “same value” 和 “per-client value” 不矛盾

后面原文还提到:

Server can support multiple clients. Attribute values can be the same or different for each client as defined by GATT or higher layer specification.

也就是说:

  • 对同一个 Client,跨 bearer 视图一致;

  • 对不同 Client,某些 attribute value 可以不同,前提是由 GATT 或上层规范定义。

11.4 举例:CCCD 就是典型 per-client value

CCCD,全称 Client Characteristic Configuration Descriptor。

它通常是每个 Client 独立保存的。

例如:

ClientCCCD value含义
Client A0x0001开启 Notification
Client B0x0000未开启 Notification
Client C0x0002开启 Indication

这时候不同 Client 看到的 CCCD value 可以不同。

但是对于 Client A 自己,不管它通过哪个 ATT bearer 访问,CCCD 视图应该一致。

11.5 工程数据结构建议

可以把 attribute 分成两类:

类型说明
Global Attribute Value所有 Client 共享
Per-client Attribute Value每个 Client 独立

示例:

typedef struct {
    uint16_t conn_id;
    uint16_t handle;
    uint8_t *value;
    uint16_t value_len;
} att_client_value_t;

对于 CCCD 这种 per-client descriptor,建议不要简单存在全局 GATT DB 里,否则多个手机连接同一个设备时,通知配置会互相串台。

串台的后果就是:

A 手机打开通知,B 手机也收到;
B 手机关闭通知,A 手机突然没数据。
这不是蓝牙,是宫斗剧。


12. Server 可以支持多个 Clients

12.1 原文含义

Protocol overview 明确说 Server 可以支持多个 clients。

这意味着一个 ATT Server 可能同时被多个连接访问。

ATT Server

Attribute Database

Client A

Client B

Client C

12.2 工程挑战

多个 Client 带来几个问题:

问题说明
并发访问多个 Client 同时读写 attribute
per-client 状态CCCD、MTU、安全状态可能不同
Notification 目标每个 Client 是否开启通知不同
安全等级不同连接加密/认证状态可能不同
Bearer 管理每个连接可有多个 ATT bearer
资源限制Prepare Queue、TX buffer、回调上下文

12.3 最小连接上下文

协议栈里通常需要维护 per-client / per-connection 上下文:

typedef struct {
    uint16_t conn_handle;
    uint16_t att_mtu;
    bool encrypted;
    bool authenticated;
    uint8_t encryption_key_size;

    /* per-client CCCD or other values */
    att_client_value_t client_values[MAX_CLIENT_VALUES];

    /* request transaction state */
    bool has_pending_req;
    uint8_t pending_opcode;
} att_client_context_t;

注意这里的 client 不是 ATT Client Engine,而是“连接到本 Server 的对端 Client 上下文”。

命名要谨慎,不然代码里会出现:

client->client->server_client->client_role

这种变量名一出来,后来的维护者基本只能烧香。


13. 多个 Services 可以暴露在一个 Server 上

13.1 原文 note 含义

Protocol overview 的 note 说明:

Multiple services may be exposed on a single server by allocating separate ranges of handles for each service.

意思是:

一个 ATT Server 可以暴露多个 services,每个 service 分配不同的 handle range。

13.2 图示

ATT Server

Attribute Database

GAP Service
0x0001 - 0x0005

GATT Service
0x0006 - 0x0009

Battery Service
0x000A - 0x000D

Vendor OTA Service
0x0010 - 0x0018

13.3 示例 Attribute Database

Handle RangeService示例
0x0001–0x0005GAP ServiceDevice Name、Appearance
0x0006–0x0009GATT ServiceService Changed
0x000A–0x000DBattery ServiceBattery Level
0x0010–0x0018Vendor OTA ServiceOTA Control、OTA Data

13.4 Service Discovery 的本质

GATT 服务发现本质上就是:

在 Attribute Database 里找出哪些 handle range 对应哪些 service。

常见 ATT PDU 是:

ATT_READ_BY_GROUP_TYPE_REQ
ATT_READ_BY_GROUP_TYPE_RSP

这个我们后面会在 Read By Group Type 一篇详细讲。


14. Notification 和 Indication:不需要 Client 主动 Read

14.1 原文含义

Protocol overview 说明:

ATT 有 notification 和 indication 能力,可以高效地把 attribute values 发送给 Client,而不需要 Client 主动读取。

这点很关键。

如果没有 Notification/Indication,Client 想知道数据变化,就只能不断 read:

ServerClientServerClientloop[轮询]ATT_READ_REQATT_READ_RSP

这很浪费。

有了 Notification:

ServerClientServerClientClient 配置 CCCD 开启通知ATT_HANDLE_VALUE_NTF(value changed)ATT_HANDLE_VALUE_NTF(value changed)ATT_HANDLE_VALUE_NTF(value changed)

有了 Indication:

ServerClientServerClientATT_HANDLE_VALUE_IND(value changed)ATT_HANDLE_VALUE_CFM

14.2 Notification vs Indication

项NotificationIndication
ATT PDUATT_HANDLE_VALUE_NTFATT_HANDLE_VALUE_IND
是否需要 Client 确认否是
是否适合高频数据是不太适合
是否适合关键状态一般适合
典型用途传感器数据、音频控制状态、日志流关键配置结果、重要状态变化
性能高较低
可靠性语义ATT 层无确认ATT 层有确认

14.3 工程提醒

Notification 不等于“不可靠传输”。
底层链路可能仍然有重传和确认机制。

但从 ATT 层看:

  • Notification 发出去后,不等 ATT_HANDLE_VALUE_CFM;

  • Indication 发出去后,必须等 ATT_HANDLE_VALUE_CFM。

所以 ATT 层语义不同。


15. ATT bearer:ATT PDU 不是凭空飞过去的

15.1 原文含义

Protocol overview 后半部分说明:

All Attribute Protocol requests are sent over an ATT bearer.

也就是说,ATT 请求都要走 ATT bearer。

15.2 ATT bearer 是什么?

ATT bearer 是发送 ATT PDU 的通道。
它底层使用 L2CAP channel。

ATT PDU

ATT Bearer

L2CAP Channel

Physical / Logical Link

15.3 多个 ATT bearer

Protocol overview 说明,两个设备之间可以建立多个 ATT bearers。

每个 ATT bearer:

  • 使用单独的 L2CAP channel;

  • 可以有不同配置;

  • 可以支持不同的并发行为;

  • 是 EATT 能力的基础。

ATT Bearer 1 / L2CAP Channel 1

ATT Bearer 2 / L2CAP Channel 2

ATT Bearer 3 / L2CAP Channel 3

Device A

Device B

15.4 为什么需要多个 bearer?

传统 ATT bearer 上,很多事务是顺序处理的。
一个 request 没完成,后面的 request 不能随便插队。

这就像一个银行窗口:

客户 A 正在办大额转账
后面的人只能排队

EATT / Enhanced ATT bearer 的意义之一,就是增加多个窗口:

窗口 1:读设备名
窗口 2:写 OTA 数据
窗口 3:读电池电量

这样能降低阻塞,提高并发能力。


16. LE 上的 ATT bearer

16.1 原文含义

Protocol overview 说明:

In LE, there is a single ATT bearer that uses a fixed channel that is available as soon as the ACL connection is established.

意思是:

在 LE 中,ACL 连接一建立,就有一个默认可用的 ATT bearer。
这个 bearer 使用固定 L2CAP channel。

16.2 图示

LE Device BLE Device ALE Device BLE Device A默认 ATT bearer 可用LE ACL Connection EstablishedATT_EXCHANGE_MTU_REQATT_EXCHANGE_MTU_RSP

16.3 工程意义

BLE 连接建立后,通常就可以开始:

  • Exchange MTU;

  • Service Discovery;

  • Characteristic Discovery;

  • Read;

  • Write;

  • Configure CCCD;

  • Notification / Indication。

路径如下:

ATT

L2CAP Fixed CID
LE ATT

HCI ACL

LE Link Layer

这也是为什么 BLE GATT 使用起来相对直接:
连接一建立,ATT/GATT 的基础通道就已经在那里了。

像进餐厅,桌子已经摆好了,你可以直接点菜。


17. LE 上的 additional ATT bearers

17.1 原文含义

Protocol overview 还说:

Additional ATT bearers can be established using L2CAP.

也就是说,除了默认 fixed ATT bearer,LE 还可以通过 L2CAP 建立额外 ATT bearers。

这就是 EATT 的基础。

17.2 图示

LE ACL Connection

Fixed ATT Bearer
默认存在

Enhanced ATT Bearer 1
L2CAP Dynamic Channel

Enhanced ATT Bearer 2
L2CAP Dynamic Channel

17.3 工程意义

默认 ATT bearer 像一个窗口。
EATT 像多开几个窗口。

场景默认 ATTEATT
简单读写足够不一定需要
大量并发 GATT 操作容易阻塞更合适
多服务并行操作事务排队可并发
OTA + 控制命令并行可能互相影响更容易优化
多客户端复杂场景状态管理复杂仍复杂,但能力更强

注意:EATT 不是“免费加速器”。
它引入更多 bearer、更多状态机、更多流控、更多资源管理。
想吃多线程红利,就要先交并发 bug 的学费。


18. BR/EDR 上的 ATT bearer

18.1 原文含义

Protocol overview 说明:

In BR/EDR, one or more ATT bearers can be established using L2CAP.

也就是说,BR/EDR 上没有 LE 那种“ACL 建立后自动可用的 fixed ATT bearer”。
它需要通过 L2CAP 建立一个或多个 ATT bearers。

18.2 图示

BR/EDR Device BBR/EDR Device ABR/EDR Device BBR/EDR Device ABR/EDR ACL ConnectionL2CAP Channel Establishment for ATTL2CAP Channel EstablishedATT PDU over L2CAP Channel

18.3 工程意义

ATT/GATT 不是 BLE 专属。
BR/EDR 也可以承载 ATT/GATT,但承载方式不同。

对比:

项LEBR/EDR
默认 ATT bearerACL 建立后 fixed channel 可用无默认 fixed ATT bearer
额外 bearer通过 L2CAP 建立通过 L2CAP 建立
常见使用BLE GATTGATT over BR/EDR
底层链路LE ACLBR/EDR ACL
典型场景BLE 服务访问双模设备、GATT over BR/EDR

19. ATT bearer 与 Client/Server 的完整关系

把前面的内容合起来:

Device B

Device A

ATT Client

ATT Server

Attribute Database A

ATT Client

ATT Server

Attribute Database B

ATT Bearer 1
L2CAP Channel

ATT Bearer 2
L2CAP Channel

关键点:

  1. 一个设备可以同时有 ATT Client 和 ATT Server。

  2. 一个设备上只有一个 ATT Server 实例。

  3. 两个设备之间可以有多个 ATT bearer。

  4. 每个 ATT bearer 对应独立 L2CAP channel。

  5. PDU 类型决定它应该交给本地 Client 还是 Server 处理。


20. 从抓包角度看 Protocol Overview

ATT 在 HCI 抓包里通常长这样:

HCI ACL Data
  └── L2CAP
      └── ATT
          ├── Opcode
          ├── Parameters
          └── Optional Signature

20.1 LE 默认 ATT bearer 抓包路径

LE ACL Connection
  HCI ACL Data
    L2CAP CID: ATT fixed channel
      ATT_READ_REQ

20.2 BR/EDR ATT bearer 抓包路径

BR/EDR ACL Connection
  L2CAP Dynamic Channel Establishment
  HCI ACL Data
    L2CAP Dynamic CID
      ATT PDU

20.3 抓包判断思路

看到一个 ATT 包,先问 5 个问题:

问题作用
这个 PDU 是什么类型?Request、Response、Command、Notification、Indication、Confirmation
方向是谁到谁?Client → Server 还是 Server → Client
走哪个 L2CAP CID?fixed channel 还是 dynamic channel
操作哪个 handle?访问哪个 attribute
是否需要后续响应?判断事务是否完整

21. Protocol Overview 的工程版状态机

21.1 ATT Server 简化状态机

Receive ATT Request

Check Handle

Handle Valid

Invalid Handle

Permission OK

Permission / Security Error

Idle

ReceiveRequest

CheckHandle

CheckPermission

SendError

ProcessRequest

SendResponse

21.2 ATT Client 简化状态机

Send ATT Request

Receive Response

Receive Error Response

Response Timeout

Idle

SendRequest

WaitResponse

Complete

Error

Timeout

21.3 Notification / Indication 状态机

Send Notification

No Confirmation Needed

Send Indication

Receive Confirmation

Confirmation Timeout

Idle

SendNotification

SendIndication

WaitConfirmation

Timeout


22. 实现一个 ATT Server 时,这一节给出的约束

从 Protocol Overview 可以抽出几个实现约束:

规范要求工程实现
Server 暴露 attributes需要 Attribute Database
Attribute 有 typeDB 中要保存 UUID
Attribute 有 handleDB 中要保存唯一 handle
Attribute 有 permissionsDB 中要保存权限和安全要求
Client 通过 handle 访问Server 要支持 handle lookup
Request 必须响应Server 不能丢 request
一个设备只有一个 Server 实例多 bearer 共享同一 DB
多 bearer handle 一致不同 bearer 看到同一 handle namespace
支持多个 clients需要 per-connection context
不同 client value 可不同CCCD 等要 per-client 存储
ATT 走 bearer需要 bearer manager
LE 有默认 fixed bearerACL 建立后初始化默认 ATT bearer
BR/EDR 通过 L2CAP 建 bearer需要 L2CAP channel establishment

23. 最小 ATT Server 架构

L2CAP RX

ATT Bearer Manager

ATT PDU Parser

Opcode Dispatcher

Attribute Database

Permission Check

Security Context

Response Builder

Notification / Indication Manager

L2CAP TX

23.1 核心结构建议

typedef struct {
    uint16_t cid;
    uint16_t mtu;
    bool enhanced;
} att_bearer_t;

typedef struct {
    uint16_t handle;
    att_uuid_t type;
    uint8_t *value;
    uint16_t value_len;
    uint16_t permissions;
} att_attribute_t;

typedef struct {
    uint16_t conn_handle;
    bool encrypted;
    bool authenticated;
    uint8_t key_size;
} att_security_context_t;

typedef struct {
    uint16_t conn_handle;
    att_bearer_t bearers[MAX_ATT_BEARERS];
    att_security_context_t security;
} att_connection_t;

23.2 Request 处理框架

void att_server_handle_request(att_connection_t *conn,
                               att_bearer_t *bearer,
                               const uint8_t *pdu,
                               uint16_t len)
{
    uint8_t opcode = pdu[0];

    switch (opcode) {
    case ATT_READ_REQ:
        att_handle_read_req(conn, bearer, pdu, len);
        break;

    case ATT_WRITE_REQ:
        att_handle_write_req(conn, bearer, pdu, len);
        break;

    case ATT_FIND_INFORMATION_REQ:
        att_handle_find_information_req(conn, bearer, pdu, len);
        break;

    default:
        att_send_error_rsp(bearer,
                           opcode,
                           0x0000,
                           ATT_ERR_REQUEST_NOT_SUPPORTED);
        break;
    }
}

24. 本篇重点术语表

术语中文工程理解
Server role服务端角色暴露 Attribute Database
Client role客户端角色访问 Server 的 attributes
Attribute属性ATT 数据访问基本单位
Attribute Type属性类型UUID,说明 attribute 是什么
Attribute Handle属性句柄Server 内唯一编号
Permissions权限由上层定义,ATT 不能直接读取
ATT bearerATT 承载发送 ATT PDU 的 L2CAP channel
Fixed channel固定信道LE 默认 ATT bearer 使用
Dynamic channel动态信道L2CAP 建立的额外 bearer
Notification通知Server 主动发,不要确认
Indication指示Server 主动发,需要确认
Confirmation确认Client 对 indication 的确认

25. 常见误区

25.1 误区一:Client 一定是 Central

不一定。

Central/Peripheral 是连接角色。
Client/Server 是 ATT/GATT 访问角色。

25.2 误区二:一个 bearer 对应一套 DB

不对。

同一个设备只有一个 ATT Server 实例。
多个 bearer 应该共享一致的 handle namespace 和 attribute 视图。

25.3 误区三:不同 Client 的所有 value 必须完全一样

不一定。

某些 value 可以按 Client 不同而不同,例如 CCCD。
但这必须由 GATT 或上层规范定义。

25.4 误区四:权限可以通过 ATT 查询

不能。

ATT 没有一个“读取权限表”的通用 PDU。
Client 只能通过访问结果和错误码间接知道权限约束。

25.5 误区五:Notification 和 Indication 都是 Server 主动发,所以差不多

不一样。

Notification 不需要 Confirmation。
Indication 需要 Client 回 Confirmation。


26. 本篇小结

本篇学习了 Vol 3 Part F 的 2 Protocol overview,核心结论如下:

  1. ATT 定义两种角色:Client 和 Server。

  2. Server 暴露 attributes,Client 访问 attributes。

  3. Attribute 是独立数据项,关联 type、handle、permissions。

  4. Attribute Type 由 UUID 定义,用来说明 attribute 代表什么。

  5. Attribute Handle 在 Server 上唯一标识一个 attribute。

  6. Permissions 由上层规范定义,不能通过 ATT 直接访问。

  7. Client 可以发送 requests,Server 必须响应收到的 requests。

  8. 一个设备可以同时实现 Client 和 Server。

  9. 一个 Bluetooth Device 上只能有一个 ATT Server 实例。

  10. 多个 ATT bearers 应该看到一致的 attribute handle namespace。

  11. Server 可以支持多个 clients。

  12. 某些 attribute value 可以按 Client 不同而不同,例如 CCCD。

  13. 多个 services 可以通过不同 handle range 暴露在同一个 Server 上。

  14. Notification 和 Indication 允许 Server 主动向 Client 发送 attribute value。

  15. 所有 ATT 请求都通过 ATT bearer 发送。

  16. 一个 ATT bearer 使用一个 L2CAP channel。

  17. LE 中默认有一个 fixed ATT bearer,ACL 连接建立后即可使用。

  18. LE 可以通过 L2CAP 建立额外 ATT bearers。

  19. BR/EDR 中可以通过 L2CAP 建立一个或多个 ATT bearers。

这一节是 ATT 的“协议地图”。
后面进入 Protocol requirements 时,就会开始详细拆 Attribute type、handle、value、permissions、MTU、bearer 等基础概念。

下一篇继续学习:

第 3 篇:Protocol Requirements 总览——ATT 规范里的强制要求

下一篇重点:

  • 3 Protocol requirements;

  • 3.1 Introduction;

  • Attribute 的基本访问规则;

  • shall、may、shall not 的工程含义;

  • 为什么 ATT 的很多权限和语义都由上层规范决定。

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐