我正在 Linux 中使用 Bluez 5.65 设置 BLE GATT 服务。我有自己的流程,与 BlueZ 源代码一起编译。在 makefile 中,我将其添加为另一个工具。我的新工具基于现有的 bluez“工具”gatt-service.c
我使用 Bluez 自己的 dbus 和 gdbus 接口与 bluetoothd 进程通信,就像 gatt-service 一样。该工具的整体设计与 gatt-service 相同。
我设法设置了一个具有两个特征的服务,一个用于写入服务,一个用于读取/指示回客户端。
我现在正在考虑添加配对,以启用加密和关键短语。我已经成功地与我的手机建立了配对连接,以便它可以对如下配置的两个特征执行写入和读取操作:
static const char *tx_characteristic_properties[] = { "encrypt-authenticated-read", "encrypt-authenticated-indicate", NULL };
static const char *rx_characteristic_properties[] = { "encrypt-authenticated-write", NULL };
这是我到目前为止添加的所有加密配置,但它似乎有效。在我成功将设备与服务配对之前,它不允许我读取或写入特征。到目前为止,我通过 bluetoothctl 手动进行配对,稍后我将考虑使其自动进行。
我当前的问题是,激活加密后,指示不再起作用。当我从手机上激活特征指示时,btmon 会吐出以下内容:
> ACL Data RX: Handle 68 flags 0x02 dlen 9 #25387 [hci0] 75486.664071
ATT: Write Request (0x12) len 4
Handle: 0x009b Type: Client Characteristic Configuration (0x2902)
Data: 0200
Indication (0x02)
< ACL Data TX: Handle 68 flags 0x00 dlen 9 #25388 [hci0] 75486.664606
ATT: Error Response (0x01) len 4
Write Request (0x12)
Handle: 0x009b
Error: Write Not Permitted (0x03)
> HCI Event: Number of Completed Packets (0x13) plen 5 #25389 [hci0] 75486.784052
Num handles: 1
Handle: 68 Address: 66:65:18:91:30:D5 (Resolvable)
Identity type: Public (0x00)
Identity: A8:79:8D:EB:B9:8B (OUI A8-79-8D)
Count: 1
我的理解是,由于新的安全设置,我不再被允许修改 CCC 描述符来激活指示。如果这是正确的,我的问题是如何配置 CCC 以允许从配对设备写入/读取它?
到目前为止,我遵循 gatt-service.c 工具的设计。我没有为特征创建任何 CCC 描述符,它似乎会作为默认描述符自动添加到我添加的每个指示特征中。这可以在我用来测试连接的 Android BLE 扫描仪应用程序的屏幕截图中看到。
更新1:
gatt-database::parse_chrc_flags 负责根据用户发送的特征属性字符串进行初始 CCC 权限标志设置。
if (!strcmp("encrypt-authenticated-indicate", flag)) {
*ccc_perm |= BT_ATT_PERM_WRITE_AUTHEN;
*props |= BT_GATT_CHRC_PROP_INDICATE;
当我们稍后想要通过写入 CCC 描述符来激活指示时,gatt-server::check_permissions 将失败,因为 BT_ATT_PERM_WRITE 位未设置。
static uint8_t check_permissions(struct bt_gatt_server *server,
struct gatt_db_attribute *attr, uint32_t mask)
{
uint8_t enc_size;
uint32_t perm;
int security;
perm = gatt_db_attribute_get_permissions(attr);
if (perm && mask & BT_ATT_PERM_READ && !(perm & BT_ATT_PERM_READ))
return BT_ATT_ERROR_READ_NOT_PERMITTED;
if (perm && mask & BT_ATT_PERM_WRITE && !(perm & BT_ATT_PERM_WRITE))
return BT_ATT_ERROR_WRITE_NOT_PERMITTED;
如果我修改 gatt-database::parse_chrc_flags 并通过设置 BT_ATT_PERM_WRITE 标志来初始化 ccc_perm,则权限检查将通过,并且指示也开始与 encrypt-authenticated-indicate 属性一起工作。要读取 CCC,我还需要添加 BT_ATT_PERM_READ 权限。
else if (!strcmp("encrypt-authenticated-indicate", flag)) {
*ccc_perm |= BT_ATT_PERM_WRITE_AUTHEN;
*ccc_perm |= BT_ATT_PERM_WRITE;
*ccc_perm |= BT_ATT_PERM_READ;
*props |= BT_GATT_CHRC_PROP_INDICATE;
考虑到我们最初设置了 BT_ATT_PERM_WRITE_AUTHEN,我认为权限检查应该集中在 BT_ATT_PERM_WRITE_AUTHEN 而不是 BT_ATT_PERM_WRITE。我想知道CCC写权限检查是否不知何故不理解我们处于权限写认证模式?
我现在的假设是这是 BlueZ 中的一个错误。
最近添加的加密验证写入类型特征属性可能未正确设置 ccc_perm 所需的所有权限标志。
特性属性设置接口 gatt-database::parse_chrc_flags 只在 ccc_perm 中设置一个专门的写标志,而不是通用的 BT_ATT_PERM_WRITE 标志。
if (!strcmp("encrypt-authenticated-indicate", flag)) {
*ccc_perm |= BT_ATT_PERM_WRITE_AUTHEN;
*props |= BT_GATT_CHRC_PROP_INDICATE;
如果我们检查 gatt-database::parse_desc_flags 中的标志是如何设置的,我们可以看到 BT_ATT_PERM_WRITE 总是与更专门的写权限标志一起设置:
if (!strcmp("encrypt-authenticated-write", flag))
*perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
我会将其作为错误报告给 BlueZ github 存储库,除非其他人提出更好的解释:)
更新1
是的,这是一个问题。几个月前修好了。 https://github.com/bluez/bluez/issues/607