BlueZ v5.64 Mgmt API 0x0054设置广播间隔不生效问题
问题背景
使用BlueZ v5.64正式版本管理API时,遇到扩展广播间隔配置不生效问题。
Mgmt API中编号为0x0054的Add Extended Advertising Parameters Command(添加扩展广播参数命令),官方文档标注参数结构如下:
Command Code: 0x0054 Controller Index: <controller id> Command Parameters: Instance (1 Octet) Flags (4 Octets) Params (2 Octets) Duration (2 Octets) Timeout (2 Octets) MinInterval (4 Octets) MaxInterval (4 Octets) TxPower (1 Octet) Return Parameters: Instance (1 Octet) TxPower (1 Octet) MaxAdvDataLen (1 Octet) MaxScanRspLen (1 Octet)
目前该官方文档的参数描述存在错误,已梳理清楚命令实际要求的参数格式,该问题不影响命令正常下发。
异常现象
向控制器下发0x0054配置命令时,btmon捕获的MGMT命令报文如下:
@ MGMT Command: Add Extended Advertising Parameters (0x0054) plen 20 Instance: 1 Flags: 0x00000002 Advertise as Discoverable Duration: 0 Timeout: 0 Min advertising interval: 200.000 msec (0x0140) Max advertising interval: 200.000 msec (0x0140) TX power: 0 dbm (0x00)
但btmon捕获到内核向控制器下发的HCI命令中,广播间隔被设置为1280msec:
< HCI Command: LE Set Extended Advertising Parameters (0x08|0x0036) plen 25 Handle: 0x01 Properties: 0x0013 Connectable Scannable Use legacy advertising PDUs: ADV_IND Min advertising interval: 1280.000 msec (0x0800) Max advertising interval: 1280.000 msec (0x0800)
后续下发0x0055: Add Extended Advertising Data Command(添加扩展广播数据命令)后,设备正常发起广播,但实际广播间隔为1280msec,并非0x0054命令中设置的200msec。
根因定位
1280msec的数值来源于/sys/kernel/debug/bluetooth/hci0/路径下的adv_min_interval与adv_max_interval节点,两个节点默认读取值均为2048,按照BLE广播时隙计算规则:2048 * 0.625ms/slot = 1280ms,与实际生效间隔完全匹配。
此前通过向上述sysfs节点写入数值的方式修改广播间隔,但该方式仅在停止并重启广播后才会生效,无法满足动态实时修改广播间隔的场景需求。
解决方案
该现象是BlueZ v5.64版本内核侧MGMT API的默认处理逻辑导致:处理0x0054命令时,内核会强制将用户传入的广播间隔与sysfs节点存储的全局最小/最大广播间隔做边界校验,若用户传入值小于sysfs配置的最小值,会直接覆盖为sysfs节点值,且不返回任何参数错误提示。
要让0x0054命令携带的广播间隔参数直接生效,可选择以下两种方案:
- 动态调整sysfs全局边界值:在下发
0x0054命令前,提前向adv_min_interval和adv_max_interval节点写入BLE协议允许的边界值,后续下发的MGMT间隔参数只要落在该区间内就不会被覆盖。该操作不需要重启蓝牙服务或已有广播,写入sysfs节点后立即对后续新下发的MGMT配置命令生效,可满足动态修改需求。操作示例:# 设置全局最小广播间隔为BLE协议允许最小值20ms(对应32个0.625ms时隙) echo 32 > /sys/kernel/debug/bluetooth/hci0/adv_min_interval # 设置全局最大广播间隔为BLE协议允许最大值10.24s(对应16384个0.625ms时隙) echo 16384 > /sys/kernel/debug/bluetooth/hci0/adv_max_interval - 内核补丁修改逻辑:定位内核源码中
net/bluetooth/hci_request.c文件内处理扩展广播参数的函数,删除/注释掉将用户传入间隔与hdev->adv_min_interval、hdev->adv_max_interval做强制对齐的逻辑,重新编译蓝牙内核模块加载即可。该方案一劳永逸,不需要提前操作sysfs节点,但需要自行维护内核补丁。
注意:不要在广播处于启动状态时直接修改间隔参数,需要先通过0x0056 Remove Extended Advertising命令移除当前广播实例,重新下发0x0054配置参数后再启动广播,否则新参数不会被重载。
内容的提问来源于stack exchange,提问作者Matt

