fix(bt): M54 入站 ACL(> ACL)解析 — 耳机自主回连后 connected=0 而声音正常
bt_acl_parse 原先只认行内 "< ACL ",而 hcitool con 对**远端发起**的连接打的是
"> ACL "。耳机自动回连(最常见的连接方式)时于是:bt connected 空、bt status
connected=0、bt connect 报「未生效(hcitool con 无该 ACL)」,而 audiod 用
strstr("ACL") 认得出、声音正常从耳机出 —— 用户看到的就是「看不出到底连没连」。
改法:白名单取代裸子串匹配 —— 行首(可带空白)→ '<' 或 '>' → ' ' → "ACL" → ' '
→ 17 字符 BD_ADDR(且必须在此断词:再跟 hex/':' 不算)。因此 SCO 行、表头、
截断行都不收。MAC 统一大写(与 audiod bt_dev_acl_macs / bluetoothctl 一致)。
单一解析器:bt_acl_macs / bt_acl_has_tri(写后真态复查)/ bt_connected_text /
bt_status.connected_n 全部经 bt_acl_parse,无第二套。
单测用真机原始字节(od -c 校对):
入站 0.8.50 设备 10.58.215.50 2026-11-11 20:53 "\t> ACL 33:DE:2E:21:AD:30
handle 11 state 1 lm MASTER AUTH ENCRYPT \n"
出站 devdocs/evidence/m50_bt_result_20261111.log:8 "\t< ACL ... handle 0
state 5 lm MASTER \n"
覆盖 >/</>SCO/<SCO/表头/空/NULL/无方向符/截断(行中与行尾)/伪 MAC/大小写/CRLF/
max 裁剪,另加端到端:入站时 connected、status connected=1、connect 不报未生效、
SCO-only 不计连接、disconnect 假成功对入站 ACL 也报「仍有该 ACL」。
用旧解析器跑同一套测试 18 条 FAIL(证明用例不是自证)。
真机验证:同一时刻 0.8.50 旧二进制 bt status connected=0,而按新源码交叉编译
(mipsel 静态)的探针在设备上对**实时 > ACL** 链路报 connected=1 且
bt_connected_text 列出 "Device 33:DE:2E:21:AD:30 MOONDROP Pudding"。
This commit is contained in:
1 parent
26cab3a0ed
commit
6e2774ff5c
2 files changed
+118
-27
No files matched your search
@@ -970,8 +970,14 @@ static int bt_scan_line_parse(const char *raw, char *mac, size_t mcap, char *nam
|
||||
}
|
||||
|
||||
/* 解析 `hcitool con` 输出 → ACL MAC 列表(返回数量 ≤max)。
|
||||
* 行样本:"\t< ACL 33:DE:2E:21:AD:30 handle 12 state 1 lm MASTER";只认 "< ACL" 行,
|
||||
* MAC 不完整(截断)跳过;表头 "Connections:" 自然不匹配。 */
|
||||
* 真机行样本(od -c 校对,行首是 TAB):
|
||||
* "\t> ACL 33:DE:2E:21:AD:30 handle 11 state 1 lm MASTER AUTH ENCRYPT " ← 远端发起(耳机自己回连)
|
||||
* "\t< ACL 33:DE:2E:21:AD:30 handle 0 state 5 lm MASTER " ← 本端发起
|
||||
* 方向符 `>`/`<` 必须**都认**:耳机自动回连是 `>`(M54 真机 0.8.50 实测,只认 `<` 时
|
||||
* `bt connected` 空、`bt status connected=0`,而声音其实正常从耳机出)。
|
||||
* 白名单 = 行首(可带空白)→ '<' 或 '>' → 空格 → "ACL" → 空格 → 17 字符 BD_ADDR;
|
||||
* 不写成裸 "ACL" 子串匹配,所以 "< SCO ..."(SCO 链路不是 ACL)、"Connections:" 表头、
|
||||
* 截断行都不收。MAC 统一大写(与 audiod bt_dev_acl_macs / bluetoothctl 输出一致)。 */
|
||||
static int bt_acl_parse(const char *raw, char macs[][24], int max)
|
||||
{
|
||||
int n = 0;
|
||||
@@ -980,18 +986,26 @@ static int bt_acl_parse(const char *raw, char macs[][24], int max)
|
||||
while (line && *line && n < max) {
|
||||
const char *nl = strchr(line, '\n');
|
||||
const char *e = nl ? nl : line + strlen(line);
|
||||
const char *acl = NULL;
|
||||
for (const char *q = line; q + 6 <= e; q++) {
|
||||
if (!strncmp(q, "< ACL ", 6)) { acl = q + 6; break; }
|
||||
}
|
||||
if (acl) {
|
||||
int ok = 1;
|
||||
for (int i = 0; i < 17 && ok; i++) {
|
||||
const char *q = line;
|
||||
while (q < e && (*q == ' ' || *q == '\t' || *q == '\r')) q++;
|
||||
if (q + 6 <= e && (q[0] == '<' || q[0] == '>') && !memcmp(q + 1, " ACL ", 5)) {
|
||||
const char *acl = q + 6;
|
||||
int ok = (acl + 17 <= e);
|
||||
for (int i = 0; ok && i < 17; i++) {
|
||||
if (i % 3 == 2) { if (acl[i] != ':') ok = 0; }
|
||||
else if (bt_hex((unsigned char)acl[i]) < 0) ok = 0;
|
||||
}
|
||||
if (ok && acl + 17 <= e) {
|
||||
memcpy(macs[n], acl, 17); macs[n][17] = 0; n++;
|
||||
/* MAC 必须在此断词:后面还跟 hex/':' 说明不是完整 BD_ADDR */
|
||||
if (ok && acl + 17 < e) {
|
||||
unsigned char c = (unsigned char)acl[17];
|
||||
if (c == ':' || bt_hex(c) >= 0) ok = 0;
|
||||
}
|
||||
if (ok) {
|
||||
for (int i = 0; i < 17; i++) {
|
||||
char c = acl[i];
|
||||
macs[n][i] = (c >= 'a' && c <= 'f') ? (char)(c - 'a' + 'A') : c;
|
||||
}
|
||||
macs[n][17] = 0; n++;
|
||||
}
|
||||
}
|
||||
line = nl ? nl + 1 : NULL;
|
||||
|
||||
Reference in new issue
Block a user