docs: §6.9 补 BLE 分包承载与缓冲边界 + 4 条实现前置项 (V1.15)

- 核实 BLE 链路分包机制: 收/发双向对称, 分包头编码于 pkg[1] 高/低 4 位
  (高 4 位 = 总包数, 低 4 位 = 当前包序), 每包 dat <= 94B @MTU>=103,
  4 位总包数 => 最多 15 包; 发送侧先自增再编码, 线上首包 seq==1, 与接收侧
  low==1 起点 / high==low 收尾完全配对
- 修正 229B 载荷定性: 分包使 229B 确可送达 => 「载荷 > 131B 即越界写
  g_buf_ble_response.dat / tmp_ble_buf(132B)」属可达缺陷, 而非纸面能力
- §6.9.9 实施状态新增 4 条前置改造项: 缓冲扩 >= 260B / set_response_iot_net|topic
  补长度钳制 / 接收侧累加钳制(防 uint8 回绕) / unpack_packs 用起 len 形参
- devlog 归档本轮勘察, vd960DBN 源码零改动
This commit is contained in:
wangfq
2026-09-10 22:59:30 +08:00
parent 2044efe14f
commit 12618578d8
2 changed files with 87 additions and 1 deletions
+77
View File
@@ -4,6 +4,83 @@
>
> 项目定位: DLD960 通信板 — BLE 配网、TCP JSON 协议服务、Loop MCU 串口桥接
## 2026-09-10 — BLE 分包机制核实 + net 229B 载荷可达性修正(§6.9 前置改造项)
> 触发:用户 2026-09-10 两问 ——「net 的 229B 是怎么计算出来的?」「我记得蓝牙小程序有分包机制,看下是不是」。
> **性质:勘察 + 归档,本条目对 `vd960DBN` 源码零改动**;结论用于修订协议 §6.9 的落地前置条件。
### 1. BLE 分包机制 —— 确认存在,收发双向对称
分包头复用 **`pkg[1]`** 字段(原地是 Addr),把总包数与序号压进高/低 4 位:
| 位段 | 含义 |
|------|------|
| `pkg[1] >> 4` | 总包数 `pkg_amount` |
| `pkg[1] % 0x10` | 当前包序号 `pkg_seq` |
**接收**`dbn_ble_srv.c:466-504``unpack_packs()` 内):
- `high == 0` → 单包(不分包),整包直取 `_len - 1` 字节;
- `low == 1` → 第一包,重置缓冲与偏移;
- `low > 1` → 后续包,校验 `amount`/`cmd` 一致 + `seq` 连续,`dat_len += (_len - 1)``memcpy(&dat[_offset], ...)`
- `high == low` → 收包完成,进入命令处理。
**发送**`dbn_ble_srv.c:420-421 / 436-437`):`_pkg_seq += 1`(**先自增再编码**,故线上第一包即 `seq == 1`)→ `buf[1] = (pkg_amount << 4) | pkg_seq`;单包时 `buf[1] = 0``dat_offset += _remain_len` 推进;发完 `pkg_amount == pkg_seq` 清缓冲。
**与接收侧 `low == 1` 起点、`high == low` 收尾完全配对,设计自洽。**
**每包 dat 上限随 MTU 协商**`ble_notify_chunk_max()``_limit = peripheral_get_mtu() - 9`,再被 `MAX_BLE_Notify_Buf_LEN - 6` 夹住;`BLE_BUFF_MAX_LEN = 100` @ `BLE/HAL/include/config.h:115`):
| MTU | 每包 dat | 4 位总包数上限(≤15 包) |
|-----|----------|--------------------------|
| 23(默认) | 14 B | 210 B |
| 96 | 87 B | 1305 B |
| **≥103(现用)** | **94 B** | **1410 B** |
> `dbn_ble_srv.h:81` 的 `//24` 注释是 `BLE_BUFF_MAX_LEN` 的**过期旧值**(原 24,现 100),不可据此推算分块。
### 2. 关键修正:229B **真的可达** ⇒ 越界**真的可达**
上一轮结论「`dat[132]` 装不下 229B,实际硬上限 131B,现场跑不到」**是错的** —— 分包让 `dat_len` 跨包累加,229B = 3 包 × ≤94B **可以送达**
| 方向 | 代码事实 | 后果 |
|------|----------|------|
| 发送 | `set_response_iot_net()``dat[132]` 写最多 229B`i` 全程无钳制 | **越界写**(同文件 `set_response_buf()` 有守卫,这两个没有) |
| 接收 | `dat_len += (_len - 1)``memcpy(&dat[_offset], ...)` 全程无钳制 | 多包累加即越界 |
| 通用 | `dat_len` / `_offset` / `_len` / `i` 均为 `uint8_t` | >255 回绕,解析循环行为错乱 |
定性由「理论上限、跑不到」升级为「**可达缺陷**」。**先撞的永远是 132 那道墙**(`pkg_amount` 4 位 ⇒ 15 包 = 1410B 的上限在更远处)。
### 3. 自我纠错(两处)
1. ❌「实际硬上限 131B」→ ✅ 131B 只是**缓冲区**上限;分包使更长载荷**可达**,越界非纸面。
2. ❌ 曾疑「收方要求 `low == 1` 起、发方 `pkg_seq = 0` 起,序号基准不一致」→ ✅ 发送侧**先自增再编码**,线上第一包即 `seq = 1`,**配对正确,疑点作废**(不该写进文档)。
### 4. §6.9 落地前置改造项(新增,实现前必做)
| # | 项 | 依据 |
|---|-----|------|
| 1 | `g_buf_ble_response.dat` / `tmp_ble_buf` 由 132 B 扩至 **≥260 B** | 229B 载荷可达 ⇒ 现缓冲必越界(132B 当初为 offlog QUERY 129B 所定) |
| 2 | `set_response_iot_net()` / `set_response_iot_topic()` 补长度钳制 | 照抄 `dbn_ble_srv.c:288` `set_response_buf()` 的守卫 |
| 3 | `unpack_packs()` 接收侧累加加钳制 | `dat_len + (_len - 1) > MAX_BLE_DAT_BUF_LEN` 即丢包清缓冲,防 `uint8_t` 回绕 |
| 4 | `unpack_packs()` 用起 `len` 形参 | 该形参在 263 行函数体里从未被引用,memcpy 长度全取自 `pkg[2]` |
改动项 1 需**两侧(DBN 与蓝牙小程序/MRS 工程)同步**,漏改一边即越界踩 `g_notify_buftemp` 一类相邻全局。
### 5. 待现场验证
- **小程序侧源码不在本机**`find` 无命中)→ 其分包实现的**末包判定**与**是否同样按 MTU 协商 94 B 切包**无法核对,需上板抓包。
- 现场是否已出现「host 写长了 MQTT 参数就乱」:按门槛(端口 4 位时 `host + clientid + username + password` 字符数 > 124 即越界)**应已偶发,只是未归因到缓冲区**。
### 6. 文件改动(本条目)
| 文件 | 改动 |
|------|------|
| `vd960DBN` 源码 | **零改动**`TaskLoop.c` 等一律未动) |
| `docs/DLD960_IoT_MQTT协议.md` | §6.9.4.3 补分包承载说明;§6.9.9 加 4 条前置改造项;修订记录加 V1.15 |
| skill `payload-sizing-and-buffer-audit.md` | 修正 §0/§3 定性、新增「BLE 分包机制」节、§5 补第 4 项 |
| skill `dbn-air780-config-sync.md` | 补分包与缓冲边界指针 |
## 2026-09-10 — 4G 配置同步协议定稿(《DLD960_IoT_MQTT协议》§6.90x7D 作废)
> 用户需求 2026-09-10:蓝牙小程序读写网络配置指令,哪些需要同步/转发给 4G(服务器域名/IP、端口、MQTT 账号密码、主题等)。