Core_v6.2 Vol 3 Part F 学习笔记(三):Protocol Requirements 总览——ATT 规范里的强制要求

0. 本篇说明

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

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

本篇对应章节:

3 Protocol requirements
3.1 Introduction

上一篇我们学习了 2 Protocol overview,知道 ATT 是一个 Client/Server 模型:

  • Server 暴露 attributes;

  • Client 访问 attributes;

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

  • ATT PDU 通过 ATT bearer 发送;

  • LE 默认有 fixed ATT bearer;

  • BR/EDR 可以通过 L2CAP 建立 ATT bearer。

这一篇开始进入 Protocol requirements,也就是 ATT 的“硬规则区”。

如果说前两篇是在看蓝牙小区地图,那么这一篇开始就像进了物业办公室,看门牌、产权、门禁、钥匙、保安规则。

ATT 里最核心的几个对象是:

Attribute Type
Attribute Handle
Attribute Value
Attribute Permissions

它们之间的关系可以先画成这样:

Attribute

Attribute Type
UUID

Attribute Handle
访问索引

Attribute Value
真实数据

Attribute Permissions
读写/安全权限

一句话先总结:

Attribute Type 告诉 Client:“这是什么”;Attribute Handle 告诉 Client:“它在哪里”;Attribute Value 是“里面的数据”;Permissions 决定“你有没有资格读写”。


1. 3 Protocol requirements 是什么?

1.1 章节定位

Protocol requirements 这一章不是在讲某一个具体 PDU,而是在定义 ATT 协议的基础规则。

后面的所有 PDU,比如:

  • ATT_READ_REQ

  • ATT_WRITE_REQ

  • ATT_FIND_INFORMATION_REQ

  • ATT_READ_BY_TYPE_REQ

  • ATT_HANDLE_VALUE_NTF

都要基于这些规则工作。

可以这样理解:

3 Protocol requirements
基础规则

3.2 Basic concepts
基础概念

3.3 Attribute PDU
PDU 类型

3.4 Attribute Protocol PDUs
具体方法

1.2 这一章后续会展开什么?

后续章节会逐个讲:

小节 内容 作用
3.1 Introduction 总体介绍 说明 Attribute 的 type、handle、value、permissions
3.2.1 Attribute type 属性类型 用 UUID 标识 attribute 是什么
3.2.2 Attribute handle 属性句柄 用 16-bit handle 访问 attribute
3.2.3 Attribute handle grouping handle 分组 用于服务、分组属性
3.2.4 Attribute value 属性值 一串 octet 数据
3.2.5 Attribute permissions 属性权限 控制读写、安全要求
3.2.6 Control-point attributes 控制点属性 常见于写控制命令
3.2.7 Protocol methods 协议方法 Request、Command、Notification 等
3.2.8 Exchanging MTU size MTU 交换 决定 ATT PDU 最大长度
3.2.9 Long attribute values 长属性值 超过一个 PDU 的 value
3.2.10 Atomic operations 原子操作 多 bearer 并发时的访问一致性
3.2.11 ATT bearers ATT 承载 ATT PDU 走哪个 L2CAP channel

这一篇先讲 3.1,不急着把所有细节一口吞下。
蓝牙规范这东西不能当火锅丸子,一口塞多了容易噎住。


2. 3.1 Introduction 总览

3.1 Introduction 主要说了五件事:

编号 主题 核心意思
1 Attribute type 每个 attribute 都有 type,用 UUID 表示它是什么
2 Attribute handle 每个 attribute 都有 handle,用来访问它
3 Attribute value 每个 attribute 都有 value,也就是实际数据
4 Handle discovery Client 通过 ATT PDU 发现 handles
5 Permissions Attribute 有权限,控制是否可读、可写、是否需要加密

如果画成图:

ATT Server

Attribute Database

Attribute A

Attribute B

Attribute C

Attribute Type
UUID

Attribute Handle
16-bit

Attribute Value

Permissions

ATT Client

ATT PDUs
Discover / Read / Write

这一节可以看作 ATT 的“身份证 + 门牌号 + 房间内容 + 门禁规则”说明书。


3. 第一组原文要点:每个 Attribute 都有 Attribute Type

3.1 规范意思

规范说:

每个 attribute 都有一个 attribute type,这个 type 通过 UUID 标识 attribute 代表什么,让 Client 能理解 Server 暴露出来的 attributes。

3.2 逐行翻译

原文要点 中文翻译 工程解释
Each attribute has an attribute type 每个 attribute 都有一个 attribute type 每个属性都必须有“类型”
that identifies what the attribute represents 用来标识这个 attribute 表示什么 告诉 Client 这个属性是设备名、电池电量,还是服务声明
by means of a UUID 通过 UUID 来标识 UUID 是 attribute type 的身份标识
so that a client can understand the attributes exposed by a server 这样 Client 才能理解 Server 暴露的 attributes Client 通过 UUID 判断这个 handle 对应什么数据

3.3 通俗解释

Attribute Type 就像“商品类别”。

比如一个超市货架上有很多商品:

商品编号 商品类别 商品内容
001 饮料 可乐
002 水果 苹果
003 零食 薯片

在 ATT 里也类似:

Handle Attribute Type Attribute Value
0x0001 Primary Service GAP Service UUID
0x0002 Characteristic Declaration Device Name 声明
0x0003 Device Name "MyDevice"
0x0004 Appearance 0x0000

其中 Attribute Type 告诉你:

这个 attribute 是什么类型。

没有 type,Client 就只能看到一堆 handle 和 value,像在仓库里看到一堆无标签纸箱:
箱子倒是很多,但不知道哪个是键盘,哪个是榴莲,哪个是老板画的大饼。

3.4 UUID 是什么?

UUID,全称:

Universally Unique Identifier

中文通常叫:

通用唯一标识符。

在 ATT 中,UUID 用于标识 attribute type。

常见 UUID:

UUID 含义
0x2800 Primary Service Declaration
0x2801 Secondary Service Declaration
0x2802 Include Declaration
0x2803 Characteristic Declaration
0x2902 Client Characteristic Configuration Descriptor
0x2A00 Device Name
0x2A19 Battery Level

所以,如果你看到一个 attribute 的 type 是 0x2A19,就知道它大概率是 Battery Level。


4. 第二组原文要点:每个 Attribute 都有 Attribute Handle

4.1 规范意思

规范说:

每个 attribute 都有一个 attribute handle,用于在 server 上访问这个 attribute。

4.2 逐行翻译

原文要点 中文翻译 工程解释
Each attribute has an attribute handle 每个 attribute 都有一个 attribute handle 每个属性都有一个 handle
that is used for accessing the attribute on a server 这个 handle 用于访问 server 上的 attribute Client 读写时靠 handle 找到目标
as well as an attribute value 同时 attribute 还有 attribute value handle 是地址,value 是数据

4.3 Handle 是什么?

Handle 是 ATT 世界里的“门牌号”。

ATT_READ_REQ handle=0x0003

ATT Client

Attribute Handle
0x0003

ATT Server

Attribute Value
MyDevice

Client 想读某个 attribute,不是直接说:

我要读 Device Name

而是发:

ATT_READ_REQ(handle = 0x0003)

Server 收到后查自己的 Attribute Database:

handle 0x0003 -> Device Name -> "MyDevice"

然后返回:

ATT_READ_RSP(value = "MyDevice")

4.4 Handle 与 UUID 的区别

这两个概念非常容易混。

对比项 Attribute Handle Attribute Type / UUID
作用 表示 attribute 在 Server 上的位置 表示 attribute 是什么
类比 门牌号 房屋用途
是否唯一 同一个 Server 上唯一 同一种 UUID 可以出现多次
用于读写 是,Read/Write 通常靠 handle 通常用于发现和识别
示例 0x0003 0x2A00 Device Name

一句话:

UUID 告诉你“这是什么”,Handle 告诉你“去哪找它”。

4.5 举例:同一个 UUID 可以有多个 handle

规范后面还提到,同一种 attribute type 可以在一个 server 上出现多次。

比如一个设备有两个温度传感器:

Handle UUID Value
0x0010 Temperature Measurement 25.1°C
0x0020 Temperature Measurement 28.7°C

UUID 一样,但 handle 不一样。

这说明:

UUID != 唯一实例
Handle = Server 内访问实例的索引

这就像一栋楼里有很多“会议室”,会议室类型一样,但门牌号不同。
你不能只说“我要去会议室”,你得说“我要去 3 楼 301 会议室”。


5. 第三组原文要点:每个 Attribute 都有 Attribute Value

5.1 规范意思

规范说:

每个 attribute 除了 type 和 handle,还有 attribute value。

5.2 逐行翻译

原文要点 中文翻译 工程解释
Each attribute has an attribute value 每个 attribute 都有一个 value 这是真正被读写的数据
An attribute value is accessed using its attribute handle attribute value 通过 attribute handle 访问 Client 不能直接“凭空读 value”,要指定 handle
The value can be discovered/read/written through ATT PDUs value 可通过 ATT PDU 间接操作 具体看 PDU 类型和权限

5.3 Attribute Value 是什么?

Attribute Value 是一串 octets。

也就是说,对 ATT 来说,它只是字节数组:

0x01
0x57
"MyDevice"
0x01 0x00
0x12 0x34 0x56 0x78

ATT 不理解业务含义。

比如:

Attribute Type Value ATT 是否理解业务含义
Device Name "MyDevice" 不理解字符串含义,只搬运字节
Battery Level 0x57 不知道这是 87%,只是一个 octet
CCCD 0x01 0x00 不直接解释业务,但 GATT 会解释
Vendor OTA Data 一段固件数据 完全看上层定义

ATT 就像快递员:
它知道包裹地址、包裹大小、是否能送、是否要签收;
但它不负责拆开包裹研究里面是不是电饭煲。

5.4 Attribute Value 与 GATT 的关系

GATT 会定义 value 的语义。

例如 Battery Level:

层级 看到的内容
ATT handle + value bytes
GATT Battery Level Characteristic
Battery Service 规范 这个 value 表示电量百分比
应用层 显示电量 87%

所以从抓包上看:

ATT_READ_RSP: 57

ATT 只知道返回了 0x57
GATT/Service/Application 才知道这是:

Battery Level = 87%

6. 第四组原文要点:Client 通过 ATT PDU 发现 Handles

6.1 规范意思

规范说:

Attribute handles are discovered by a client using Attribute Protocol PDUs.

也就是说,Client 一开始通常不知道 Server 上有哪些 handles,需要通过 ATT PDU 发现。

6.2 逐行翻译

原文要点 中文翻译 工程解释
The attribute handles are discovered attribute handles 是被发现出来的 Client 通常不能预设对端 handle
by a client 由 Client 发现 Client 发起 discovery
using Attribute Protocol PDUs 使用 ATT PDUs 例如 Find Information、Read By Type、Read By Group Type

6.3 为什么不能直接写死 handle?

在简单 demo 里,你可能知道:

Battery Level handle = 0x0007

于是直接读:

ATT_READ_REQ(0x0007)

但是在真实产品里,这样很危险。

原因:

原因 说明
不同设备 GATT DB 不一样 handle 分配不同
固件升级可能改变 GATT DB handle 可能变化
服务数量不同 handle range 不同
有些服务可选 是否存在不确定
GATT cache 可能失效 需要重新发现

所以 Client 正常流程应该是:

ATT Server ATT Client ATT Server ATT Client Discover Primary Services Service handle ranges Discover Characteristics Characteristic handles Discover Descriptors Descriptor handles Read / Write by discovered handle

6.4 常见 discovery PDU

发现目标 常见 ATT PDU
发现 handle 与 UUID 映射 ATT_FIND_INFORMATION_REQ / RSP
按 type + value 查找范围 ATT_FIND_BY_TYPE_VALUE_REQ / RSP
按 type 读取 attribute ATT_READ_BY_TYPE_REQ / RSP
发现分组属性,比如 Primary Service ATT_READ_BY_GROUP_TYPE_REQ / RSP

GATT 服务发现其实就是基于这些 ATT PDU 组合出来的。

GATT 是导演,ATT 是演员。
导演说“来一段服务发现”,演员实际演的是 READ_BY_GROUP_TYPE


7. 第五组原文要点:同一种 Attribute Type 可以出现多次

7.1 规范意思

规范说:

Attributes that have the same attribute type may exist more than once in a server.

也就是说,一个 Server 里可以有多个相同 type 的 attributes。

7.2 逐行翻译

原文要点 中文翻译 工程解释
Attributes that have the same attribute type 具有相同 attribute type 的 attributes UUID 相同
may exist more than once 可以出现多次 不是全局唯一
in a server 在同一个 Server 上 同一个 ATT Server DB 内也可以重复

7.3 举例:多个 Characteristic Declaration

一个 GATT Server 里会有很多 Characteristic Declaration,它们的 attribute type 都是:

0x2803

但是 handle 不同:

Handle Attribute Type Value
0x0002 0x2803 Characteristic Declaration Device Name 声明
0x0006 0x2803 Characteristic Declaration Battery Level 声明
0x0011 0x2803 Characteristic Declaration OTA Control 声明
0x0014 0x2803 Characteristic Declaration OTA Data 声明

所以:

同一个 UUID 可以对应多个 handle。

7.4 再举例:多个相同业务类型

假设一个设备有多个相同类型传感器:

Handle Type Value
0x0101 Temperature 左侧温度
0x0111 Temperature 右侧温度
0x0121 Temperature 环境温度

Client 不能只根据 UUID 就认为“只有一个”。
它要根据 handle range 和 discovery 结果来判断。

7.5 工程注意

实现 discovery 时,不能写成:

return first_attribute_with_uuid(uuid);

而应该支持查找多个:

int att_find_all_by_type(uint16_t start,
                         uint16_t end,
                         const att_uuid_t *uuid,
                         att_attribute_t **out,
                         int max_count);

否则 Client 会发现一半服务,然后以为对端“少了半边脑子”。


8. 第六组原文要点:Attributes 有 Permissions

8.1 规范意思

规范说:

Attributes have a set of permissions that controls whether they can be read or written, or whether the attribute value shall be sent over an encrypted link.

也就是说,每个 attribute 可以有一组权限,用于控制:

  • 是否可读;

  • 是否可写;

  • 是否必须通过加密链路传输;

  • 是否需要认证;

  • 是否需要授权;

  • 是否有密钥长度要求。

8.2 逐行翻译

原文要点 中文翻译 工程解释
Attributes also have a set of permissions attributes 还有一组 permissions 每个 attribute 有访问控制规则
controls whether they can be read 控制是否可以读 不可读则返回 Read Not Permitted
or written 控制是否可以写 不可写则返回 Write Not Permitted
whether the attribute value shall be sent over an encrypted link 控制 value 是否必须通过加密链路发送 如果没加密,访问会失败
Security aspects are defined in Section 4 安全相关内容在第 4 节定义 后面 Security considerations 会详细讲

8.3 Permissions 是 Server 本地规则

Permissions 通常不会直接暴露给 Client。

Client 不能发一个 PDU:

请告诉我 handle 0x0007 的权限表。

ATT 没有这种通用查询权限表的 PDU。

Client 只能通过访问结果间接知道:

Client 操作 Server 可能返回
读不可读属性 Read Not Permitted
写不可写属性 Write Not Permitted
未加密访问加密属性 Insufficient Encryption
未认证访问认证属性 Insufficient Authentication
密钥长度不足 Encryption Key Size Too Short
未授权 Insufficient Authorization

8.4 权限像门禁

Attribute Database 可以类比成一栋楼:

ATT 概念 类比
Attribute Handle 房间门牌号
Attribute Type 房间用途
Attribute Value 房间里的东西
Permissions 门禁规则
Encryption 保安通道
Authentication 人脸识别
Authorization 领导批准

你知道房间号,不代表你能进。
你能进,不代表你能搬东西。
你能看,不代表你能改。
蓝牙权限也是这个逻辑。


9. 3.1 Introduction 的完整逻辑图

把 3.1 的内容串起来:

Discover handles

Read / Write by handle

Attribute

Attribute Type
UUID
说明它是什么

Attribute Handle
访问它的索引

Attribute Value
实际数据

Permissions
控制读写和安全

ATT Client

ATT Server

ATT PDUs

可以再抽象成一句工程语言:

Client 先通过 ATT PDU 发现 Server 上有哪些 handle,
再通过 handle 访问 attribute value;
Server 根据 attribute permissions 决定是否允许访问。

10. 3.1 对 ATT Server 实现的要求

从这一小节可以推导出 ATT Server 至少要维护这些信息:

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

10.1 Attribute Database 基本要求

字段 必要性 原因
handle 必须 Client 通过 handle 访问
type / UUID 必须 Client 通过 UUID 理解 attribute
value 必须 真实被读写的数据
permissions 必须 控制读写和安全
value length 必须 生成 ATT response 时需要长度
callback 常见需要 动态 value 或控制点处理
per-client storage 某些 attribute 需要 CCCD 等 per-client value

10.2 Server 收到 Read Request 的基本逻辑

No

Yes

No

Yes

No

Yes

Receive ATT_READ_REQ

Parse handle

Find attribute by handle

Found?

Readable?

Security OK?

Send ATT_READ_RSP

Send ATT_ERROR_RSP

伪代码:

void att_handle_read_req(att_connection_t *conn,
                         att_bearer_t *bearer,
                         const uint8_t *pdu,
                         uint16_t len)
{
    uint16_t handle;
    att_attribute_t *attr;
    uint8_t err;

    if (len != 3) {
        att_send_error_rsp(bearer,
                           ATT_READ_REQ,
                           0x0000,
                           ATT_ERR_INVALID_PDU);
        return;
    }

    handle = read_le16(&pdu[1]);

    attr = att_db_find_by_handle(handle);
    if (attr == NULL) {
        att_send_error_rsp(bearer,
                           ATT_READ_REQ,
                           handle,
                           ATT_ERR_INVALID_HANDLE);
        return;
    }

    err = att_check_read_permission(conn, attr);
    if (err != ATT_ERR_SUCCESS) {
        att_send_error_rsp(bearer,
                           ATT_READ_REQ,
                           handle,
                           err);
        return;
    }

    att_send_read_rsp(bearer, attr->value, attr->value_len);
}

10.3 Server 收到 Write Request 的基本逻辑

No

Yes

No

Yes

No

Yes

Receive ATT_WRITE_REQ

Parse handle and value

Find attribute

Found?

Writable?

Security OK?

Write value

Send ATT_WRITE_RSP

Send ATT_ERROR_RSP

写和读的最大区别是:

操作 是否修改 value 成功响应
Read 不修改 ATT_READ_RSP
Write Request 修改 ATT_WRITE_RSP
Write Command 修改,但不响应 无响应

11. 3.1 对 ATT Client 实现的要求

ATT Client 需要做两件事:

  1. 发现 handle;

  2. 基于 handle 访问 value。

11.1 Client 不能盲读

错误思路:

att_read(0x0007);  // 假设 0x0007 一定是 Battery Level

正确思路:

1. Discover Primary Services
2. Find Battery Service handle range
3. Discover Characteristics in that range
4. Find Battery Level characteristic value handle
5. Read that handle

流程图:

ATT Server ATT Client ATT Server ATT Client ATT_READ_BY_GROUP_TYPE_REQ Find Primary Services ATT_READ_BY_GROUP_TYPE_RSP Service handle ranges ATT_READ_BY_TYPE_REQ Find Characteristics ATT_READ_BY_TYPE_RSP Characteristic declarations ATT_READ_REQ Read discovered value handle ATT_READ_RSP Attribute Value

11.2 Client 要处理同 type 多实例

Client 查找 UUID 时,要准备接收多个结果。

比如:

Find all characteristics with UUID = Temperature

可能返回多个 handle。

所以 Client 数据结构里应该能保存列表:

typedef struct {
    uint16_t handle;
    uint16_t end_handle;
    att_uuid_t uuid;
} gatt_discovered_attr_t;

而不是只保存一个:

uint16_t temperature_handle;

当然,具体业务如果只关心第一个,那是上层策略,但 ATT/GATT discovery 层不能假设只有一个。


12. Protocol Requirements 与 GATT 的关系

3.1 虽然讲的是 ATT,但它实际上是 GATT 的底座。

GATT 中这些概念都能落到 ATT:

GATT 概念 ATT 基础
Service 一组 Attribute
Characteristic Declaration Attribute
Characteristic Value Attribute
Descriptor Attribute
Characteristic UUID Attribute Type
Characteristic Value Handle Attribute Handle
Read Characteristic 通过 handle 读 attribute value
Write Characteristic 通过 handle 写 attribute value
CCCD 一个有权限和 per-client value 的 descriptor attribute

图示:

GATT

Service

Characteristic

Descriptor

ATT

Attribute

Type / UUID

Handle

Value

Permissions

所以后面学 GATT 时,如果你已经掌握了 ATT 的 type、handle、value、permissions,很多概念会自然顺起来。

否则 GATT 里的 Service、Characteristic、Descriptor 会像一堆套娃,看着都熟,拆开就乱。


13. 抓包视角:3.1 怎么落地?

3.1 不是空谈,它直接体现在抓包里。

13.1 发现 handle

抓包中可能看到:

ATT_READ_BY_GROUP_TYPE_REQ

意思是:

Client 想发现某类 group attribute,比如 Primary Service。

返回:

ATT_READ_BY_GROUP_TYPE_RSP

里面会包含:

start handle
end group handle
attribute value

13.2 按 handle 读取 value

抓包中看到:

ATT_READ_REQ
  Attribute Handle: 0x0007

意思是:

Client 想读取 handle 0x0007 对应 attribute 的 value。

返回:

ATT_READ_RSP
  Attribute Value: ...

13.3 权限失败

如果 Server 不允许读,可能看到:

ATT_ERROR_RSP
  Request Opcode In Error: ATT_READ_REQ
  Attribute Handle In Error: 0x0007
  Error Code: Read Not Permitted

如果需要加密但当前没加密,可能看到:

ATT_ERROR_RSP
  Error Code: Insufficient Encryption

如果需要认证但当前安全等级不够,可能看到:

ATT_ERROR_RSP
  Error Code: Insufficient Authentication

所以抓包时,看到 ATT_ERROR_RSP 不要立刻说“协议栈挂了”。
很多时候它只是 Server 在认真执行权限检查。


14. 3.1 的工程检查清单

实现 ATT Server 时,可以根据 3.1 做一个 checklist。

14.1 Attribute Database 检查

检查项 是否必须
每个 attribute 是否有 type
每个 attribute 是否有 handle
每个 attribute 是否有 value
每个 attribute 是否有 permissions
handle 是否唯一 后续 3.2.2 会明确要求
是否支持按 handle 查找
是否支持按 type 查找 discovery 需要
是否支持权限检查
是否支持加密状态检查 有安全 attribute 时必须
是否支持同 type 多实例

14.2 ATT Client 检查

检查项 说明
是否先 discovery 再访问 不应盲目写死 handle
是否能处理多个相同 UUID 同 type 可以出现多次
是否能处理权限错误 Error Response 是正常协议结果
是否能处理 handle 变化 GATT cache 可能失效
是否能处理加密后重试 安全不足时可能需要 pairing/encryption
是否区分 UUID 和 handle UUID 用于识别,handle 用于访问

15. 这一节里的几个“shall / may”工程含义

虽然 3.1 文字不多,但里面有几个工程上要特别注意的规范语义。

规范语义 工程含义
每个 attribute 有 type DB 里不能有没有类型的 attribute
每个 attribute 有 handle Client 访问必须依靠 handle
每个 attribute 有 value value 是读写对象
同 type attribute 可以多次存在 discovery 不能只返回第一个
permissions 控制读写 访问前必须检查权限
attribute value 可要求加密链路 没加密不能直接返回敏感 value
安全方面另见 Section 4 权限检查不能只看 read/write,还要看 security

16. 常见误区

16.1 误区一:UUID 能直接用来读写

不对。

ATT 的普通读写是基于 handle 的。

UUID 通常用于发现阶段,handle 用于访问阶段。

正确流程:

UUID -> discovery -> handle -> read/write

不是:

UUID -> read/write

16.2 误区二:一个 UUID 只会出现一次

不对。

同一个 attribute type 可以在同一个 Server 上出现多次。

例如多个 Characteristic Declaration 都是 0x2803

16.3 误区三:知道 handle 就一定能访问

不对。

handle 只是门牌号,不是万能钥匙。

还要看:

  • 是否可读;

  • 是否可写;

  • 是否需要加密;

  • 是否需要认证;

  • 是否需要授权;

  • 密钥长度是否足够。

16.4 误区四:ATT 会解释 value 的业务含义

不对。

ATT 只搬运 octets。
业务含义由 GATT、Service、Profile 或应用层定义。

16.5 误区五:权限错误就是异常 bug

不一定。

权限错误是 ATT 协议定义的正常响应。
比如读一个不可读 attribute,Server 返回 Read Not Permitted 是正确行为。


17. 本篇小结

本篇学习了 3 Protocol requirements / 3.1 Introduction,核心结论如下:

  1. 每个 attribute 都有 attribute type。

  2. Attribute type 通过 UUID 标识 attribute 代表什么。

  3. 每个 attribute 都有 attribute handle。

  4. Attribute handle 用于在 Server 上访问 attribute。

  5. 每个 attribute 都有 attribute value。

  6. Attribute value 是真实被读写的数据。

  7. Client 通过 ATT PDU 发现 handles。

  8. Attribute value 通过 handle 访问。

  9. 同一种 attribute type 可以在 Server 上出现多次。

  10. Attribute 有 permissions,用来控制是否可读、可写、是否需要加密链路。

  11. ATT 本身不解释 value 的业务含义。

  12. UUID 用于识别,handle 用于访问。

  13. 权限检查是 ATT Server 实现的核心逻辑。

  14. 安全相关内容会在 Section 4 进一步定义。

  15. GATT 的 Service、Characteristic、Descriptor 都建立在 ATT attribute 模型之上。

可以用一句话总结这一篇:

ATT 的世界里,UUID 负责“认人”,handle 负责“找门”,value 是“房间里的东西”,permissions 是“门禁和保安”。

下一篇继续学习:

第 4 篇:Attribute Type——UUID 是 Attribute 的身份证

下一篇会重点进入:

  • 3.2.1 Attribute type;

  • UUID 的作用;

  • 16-bit / 32-bit / 128-bit UUID;

  • SIG-defined UUID 与 vendor-specific UUID;

  • 32-bit Attribute UUID 为什么要转换成 128-bit;

  • 抓包里 UUID 字节序怎么看;

  • 工程实现中 UUID 比较函数怎么设计。

Logo

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

更多推荐