Files
vd_960/vd960DBN/docs/incidents/2026-07-15-DC045A49718F-protocol-error.md
T
wangfq e3eaa111fe fix(mqtt): 修复 loop_data>512B 溢出发垃圾包致 broker RST 重连风暴 (现场P0)
根因(非平台推测的环形缓冲/event_report队列):
  mqtt_publish 的 mqttBuf=512B < loop_data(4通道)604B
  → MQTTSerialize_publish 返回 -2 不写 buf
  → len 为 uint32_t, -2 变 42.9亿
  → WCHNET 把清零缓冲+越界相邻全局(temp_guide=report_config→report_c)
    当 520B 垃圾包发出 → broker 见非法类型0x00 RST → 重连风暴

修复(net_srv.c):
  - MAX_MQTTBUF_LEN 512→1024 (容纳 604B loop_data)
  - mqtt_publish: len uint32→int + 守卫 if(len<=0)return (序列化失败绝不发残缓冲)
  - keepalive 9→60 (报告建议, 9s过激)

event_report 协议违规修复(iot_mqtt_srv.c):
  - 重连重发保持原 msg_id/ts (V1.04 §5.3-2), 不再作废换号致平台去重失效

验证: tests/test_mqtt_publish_overflow.c 复现旧垃圾包+验证守卫/大缓冲;
      tests/test_event_report.c T8 断言重连同 msg_id. 均全过.
遗留: ts=上电秒数非Unix时间戳, 待定方案(设备无RTC/SNTP)

Refs: docs/incidents/2026-07-15-DC045A49718F-protocol-error.md
2026-07-15 14:58:03 +08:00

58 lines
2.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 抓包存档:DC045A49718F MQTT protocol error 风暴
- **文件**: `2026-07-15-DC045A49718F-protocol-error.pcap`44 包,20s 窗口)
- **抓包时间**: 2026-07-15 14:26 左右(设备 14:20 上电后持续复现)
- **抓包点**: 腾讯云 159.75.137.141`tcpdump -i any port 1883 and host 113.91.145.40`
- **设备**: DC045A49718F (DLD960GA, hard 1.0 / soft 1.0,新版 event_report 重发固件)
## 现象
设备每 ~1s 被 mosquitto 以 `disconnected due to protocol error` 踢下线,
15 分钟内 80+ 次重连、87 次 initialize 上报。
## pcap 关键证据(用 `tcpdump -r <pcap> -nn -ttt -X` 查看)
正常序列先走完:
```
CONNECT (MQTT 3.1.1, client_id=DC045A49718F, u=admin, keepalive=9)
→ CONNACK
→ SUBSCRIBE dld960/DC045A49718F/srv → SUBACK
→ PUBLISH dld960/DC045A49718F/dev {"cmd":"initialize", msg_id:21, ts:393, ...} ← 报文完好
```
紧接着设备发出致命包:
```
TCP 段 520 字节 = 前 512 字节全 0x00 + 尾部 8 字节 ASCII "report_c"
```
- `0x00` 不是合法 MQTT 控制报文类型(type 0 保留)→ broker 立即 RST 断连
- RST 后设备仍继续发第二个 520B 全零段(seq 805:1325
## 诊断
**520 = 512 + 8 → 高度疑似 512B 环形 TX 缓冲区回绕(wrap)处理 bug。**
推测:往 TX 缓冲写 report_config 响应时跨越回绕边界,"report_c" 落在缓冲区
物理尾部,其余部分绕回头部;发送侧却把整块未初始化(全零)缓冲区一次性发出。
本次固件恰好新增了事件待发队列 + 5s 重发机制(V1.04),动过 TX 路径,
建议重点排查:
1. 新待发队列的写指针 / 回绕边界处理
2. 重发定时器与主循环并发 publish 的互斥(两个写者交叉写 TX 流)
3. 发送长度是否误用缓冲区总长而非报文实际长度
## 顺带实锤的协议违规(固件侧待修)
1. **断线重连后重发事件用了新 msg_id**msg_id 9/10 内容完全相同
(car_leave ch1 value=48, ts=76),双双入库 → 平台 (dev_serial,msg_id)
去重失效。V1.04 §5.3 条 2:重发必须用相同 msg_id(跨重连也要保持)
2. **ts 字段是上电秒数**(76/393),不是协议约定的 Unix 时间戳
3. keepalive=9s 过于激进(老问题),建议 30~60s
## 平台侧结论(无需改动)
event_report 必答闭环工作正常:ack <1s、回显 msg_id、先落库后应答;
msg_id 相同的重复包去重有效。重复入库仅发生在固件违规换 msg_id 的场景。