fix(net-audit): 修 6 处寄存器口径/注释错误 + Trap 记录全量复核与审计章节
智能体团队四路并行只读审计(驱动层逐命令 / NET+测试层逐调用点 / Trap 01-12 复核 / Trap 13-25 复核),三源交叉:芯片手册 + WCH 官方 SDK(CH395CMD.c / CH395INC.H / 21 个例程)+ git 历史。本提交只落 "已确认且低风险"的修法,其余发现登记进文末审计章节待逐项决策。 已修(A 类,全部有手册/SDK 出处): A1 测试 TC-203 反核实写成 st_chk[0]==CH395F_TCP_ESTABLISHED——§5.22 byte0 只有 00H/05H,条件恒假,这道 Trap 14 防线自写下起从未生效 且日志无痕(与 Trap 07 同类的 byte0/byte1 语义越界)。改为 byte0==OPEN && byte1==ESTABLISHED。 A2 测试 Phase3/4 把 GET_RECV_LEN 返回值直接当读取长度(本地 rx_buf[300]/[64],芯片 RX 缓冲 2KB)→ 栈溢出;补夹取 + 留痕 (同文件 TC201/202/204 早已 clamp,这两处是漏)。 A3 CH395F_GINT_STAT_DHCPV6 由 0x8000(bit15) 改 0x1000:SDK 是 (1<<12)、§5.16 明确 CH395F 的 [12:15] 保留。全仓零引用。 A4 ch395f.h 命令分组注释字节数错 4 处(GET_GLOB_INT_STATUS_ALL / GET_UNREACH_IPPT 归"1 字节输出"、SET_FUN_PARA 归"1 入 1 出"、 SET_RETRAN_PERIOD 归"3 字节输入"、GET_SOCKET_STATUS_SN 归"1 字节 输出");KeepAlive 参数注释"秒"改"毫秒"(§5.53/5.54 单位 ms); set_retrans_count 删"0=默认值5"(§5.17 默认 12、无 0=默认语义)。 实现全对、注释误导——Trap 25 的 1 字节缓冲栈越界正是这类注释发起。 A5 net_socket.c 六处注释与手册/HEAD 相反:FUN_PARA(SOCKET_CLOSE=0) 实为 bit3=1(正是 closed-with-data accept 的契约依据,写反会诱导 把 0x08 改回去)、"初始化成功后设置 MAC"(§9.2.1 ① 是之前)、 "复用默认缓冲"(net_init 已为 8 Socket 显式分配)、"由 MSS 推导" (固定布局、Trap 21 已解耦)、"等 SEND_OK"(门控是 SENBUF_FREE)、 UDP 头 [0-1] reserved(§9.2.4 是数据长度)。 A6 ch395f.c write_send_buf 超限静默 return(void 无日志),且上限取 DMA 2048 而非发送缓冲 1024;读路径有 OVERSIZE 金丝雀、写路径没有 → 补 [ERR] 留痕 + >1KB 告警,行为不变(分块责任仍在调用方)。 审计确认"不是 bug"的最危险一项:GET_GLOB_INT_STATUS_ALL 拼装方向。 我们"第1字节|第2字节<<8"与官方 CH395CMDGetGlobIntStatus() 逐字相同, glob & (1<<(sock+4)) = §5.16 bit4..bit11 = SDK GINT_STAT_SOCKn,三源 一致。另 55 条命令码、9 处 16 位字节序、14 条读命令字节数、60 个 常量、12 个单位参数点、48 块缓冲布局逐条核对无异常;17 处 get_socket_status 调用点全是 st[2],Trap 25 的 1 字节 bug 无残留。 文档:Trap_Records 加文末「2026-10-11 寄存器/数值口径全量审计」章节 (干净清单计数 + 15 条新发现含已修/待修 + 文档待修清单)。就地修正: Trap 07 定案更正里"全文 RST 仅见于错误码与引脚"的绝对表述(§5.29 / §9.2.6 其实写了芯片发 TCP RESET,只是都与 close 无关)+ 删不可核验的 "11 个悬空提交";Trap 16 的"IP/端口寄存器大端"(端口 §5.25/5.26 明确 低字节在前)+ 注明 §5.8 总括与官方例程自相矛盾;Trap 18 删悬空 "Trap 19"(该条从未存在)、net_socket() 改 net_bind();速查清单 DMA 1500 改 2052;Trap 13 加复核注(最高优先级:其"部分读后 recv_len 归零"与 §5.34 直接相左、与本仓 TC201 注释相反,且同族结论已被 Trap 21 撤回,却仍被 6 处当现行约束引用);Test_Guide 的 TRAP-07 行仍教 "卡 FIN_WAIT_2 / close(RST)"、悬空的 Trap 19 与两处"见风险 #N"。 待修(B 类,登记未动,需逐项决策与实测):B1 产品路径从未启用 Socket KeepAlive(唯一调用点在 client 分支,产品三服务全是 TCP Server, §5.56 要求服务器在 CONNECT 后开,60s/5s/3 参数空转);B2 tcp_connect 返回值丢弃且 CONNECTING 不在对账范围;B3 net_listen_locked 全 8 Socket 读即清会吞别槽事件;B4 全局中断 bit0-3 从不消费、get_unreach_info 零 调用;B5 getsockname 的 s_addr 与本层约定相反致 FTP 日志设备 IP 反序 (PASV 双重反转恰好正确,勿误判);B6 三处判据只看 byte1 未按 byte0 门控;B7 Phase5 单次写 4093B;B8 Phase4 缓冲块与 sock4 交叠;B9 杂项。 验证:产品构建 0 错 0 警、Code=196912(+124B,写路径两条新日志); 测试路径(PHASE2/3/4 打开)单独编译 0/0;内存快照已刷新;doc-links EXIT=0、无 U+FFFD、pre-commit 全绿;@test 闭环 PASS(戳匹配 + 回读无 差异 + 锚点 x1 + 548ms)。
This commit is contained in:
@@ -170,12 +170,12 @@ Phase 2 测试,2025-07
|
||||
**三条推翻原根因**:
|
||||
|
||||
1. **`FIN_WAIT_2`(0x06) 全程未出现**(15 轮 × 9 个采样点)。实测过渡态只有 `TIME_WAIT`(0x0A)(A 模式一轮在 +0/+50/+100 ms 可见,+150 ms 回 CLOSED)与 `TCP_CLOSED`(0x00)。
|
||||
2. **手册无 RST 语义**:§5.35 只说"关闭 Socket 前 CH395 会自动断开 TCP 连接",全文 RST 仅见于错误码 `CH395_ERR_RST` 与 RST/RSTI 引脚;且主动发 FIN 先进 `FIN_WAIT_1`(05H)、收到 ACK 才进 `FIN_WAIT_2`(06H)——"disconnect 推入 FIN_WAIT_2"本身就跳了一拍。
|
||||
2. **`close` 无 RST 语义**:§5.35 只说"关闭 Socket 前 CH395 会自动断开 TCP 连接"。手册中芯片主动发 RST 只出现在 §5.29(监听 Socket 已有连接时再来连接 →"发送 TCP RESET")与 §9.2.6(多连接找不到可用数据 Socket →"将连接复位")两处,均与 `close`/`disconnect` 无关;此外仅有错误码 `CH395_ERR_RST` 与 RST/RSTI 引脚。且主动发 FIN 先进 `FIN_WAIT_1`(05H)、收到 ACK 才进 `FIN_WAIT_2`(06H)——"disconnect 推入 FIN_WAIT_2"本身就跳了一拍。
|
||||
3. **观测口径错在把 byte1 当独立事实**:§5.22 第 1 字节只有 `00H/05H` 两个取值,第 2 字节才是 TCP 态;官方 SDK `CH395CMDGetSocketStatus()` 注释明确"Second byte — TCP state, **meaningful only if** TCP mode **and the first byte is open**"。当年 Phase 2 收尾代码的判据用的是**正确的 byte0**(`st[0]==CH395F_SOCKET_CLOSED`),break 之后照样打印 byte1 → 一个"已 CLOSED 状态下的残留 TCP 态读数"被读成了"卡在某个 TCP 态"。
|
||||
|
||||
**真正的原因**(C 模式 5/5 复现):`FUN_PARA` bit3 `SOCKET_CLOSE=1`(§5.52 ②,`0x08`/`0x09` 都置了)下,产生 DISCONNECT 后**芯片不关 Socket、不清缓冲**,Socket 长期停在 `byte0=0x05(OPEN) / byte1=0x00(TCP_CLOSED)`;此时直接 `open_socket` 必返 **`0x20` FAIL**——正是 2026-07-19 测试指南问题表里那条 `Phase 2 open_socket: 0x20 (FAIL) / socket 未完全关闭`。**把 Socket 拉回 CLOSED 的动作是 `close`,与 RST 无关。**
|
||||
|
||||
**git 侧佐证**:`ch395f_tcp_disconnect()` 自首个提交起**只有定义、零调用点**(含全部分支与 11 个悬空提交),"disconnect→close" 序列从未进入任何提交代码;本条"发现时间 2025-07"也与仓库不符(仓库首个提交 `b1d05091` = 2026-06-05,Phase 2 对应 2026-07-19 的 `17109d9b`→`7a8a97f4`→`a08d26bc`)。当时驱动已在轮询 `GET_CMD_STATUS`(4 s 上限),故也不是"命令没等完成"。
|
||||
**git 侧佐证**:`ch395f_tcp_disconnect()` 自首个提交起**只有定义、零调用点**(`git log --all -S` 在 `NET/App/test` 仅命中本仓 `bca6cc6` 一次),"disconnect→close" 序列从未进入任何提交代码;本条"发现时间 2025-07"也与仓库不符(仓库首个提交 `b1d05091` = 2026-06-05,Phase 2 对应 2026-07-19 的 `17109d9b`→`7a8a97f4`→`a08d26bc`)。当时驱动已在轮询 `GET_CMD_STATUS`(4 s 上限),故也不是"命令没等完成"。
|
||||
|
||||
**做法为何仍然对**(换成三条有支撑的理由):① §5.35 `close` 已自动断链,`disconnect` 纯属多余;② `disconnect` 会**制造**一个 DISCONNECT 事件,bit3=1 下芯片不自动收尾,该事件必须被消费/预清,否则污染下一条连接(Trap 14 / 17 / 22 实证);③ 它把芯片推进 closing 过渡态,重开需要沉降(Trap 09)。本轮 15 轮重开均未观察到残留 `DISCONNECT`(0x10)——`close` 顺带清掉了锁存,这正是"直接 close"安全的原因。
|
||||
|
||||
@@ -214,7 +214,7 @@ CH395F 的 RECV 中断是电平触发的——只要接收缓冲区有数据就
|
||||
### SPI 通信
|
||||
- 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹
|
||||
- **大数据量收发使用 SPI2 DMA**:`ch395f_write_send_buf()` 和 `ch395f_read_recv_buf()` 已改造为 DMA 批量传输(DMA1_Stream3 RX, DMA1_Stream4 TX),命令和配置操作仍使用逐字节轮询
|
||||
- DMA 缓冲区:`s_spi2_dma_tx_buf[1500]` / `s_spi2_dma_rx_buf[1500]`,4 字节对齐
|
||||
- DMA 缓冲区:`s_spi2_dma_tx_buf/rx_buf[CH395F_SPI_DMA_BUF_SIZE]` = 接收缓冲 2048 + 4 = **2052**(`ch395f.h:148`),4 字节对齐;单次有效载荷上限 2048(历史值 1500 / 4100 均已作废,见 Trap 13 复核注)
|
||||
|
||||
### TCP 参数配置(必须在 INIT_CH395 之前)
|
||||
- **重传参数**:`SET_RETRAN_COUNT`(默认12次,最大20)和 `SET_RETRAN_PERIOD`(默认500ms,最大1000ms),总重传时间 = 次数 × 周期
|
||||
@@ -411,6 +411,8 @@ MobaXterm 上传文件时 CH395F 收到数据(`s1 int=0x04` RECV_OK 持续触
|
||||
### 根因
|
||||
`ch395f_read_recv_buf` 读部分数据后,CH395F 的 `recv_len` 寄存器**被重置为 0**(非递减)。缓冲区中剩余的 1896 字节仍然存在(RECV_OK 标志为真),但 `ch395f_get_recv_len` 报告 0。
|
||||
|
||||
> ⚠ **2026-10-11 复核:该机理未证实,且与手册直接相左——§5.34 明文"读取的数据长度可以小于缓冲区的实际有效数据长度,未读取的数据仍然保留在接收缓冲区中,单片机可以通过此命令继续读取";本仓自己的 TC-NET-201 注释也是相反口径(`test/board/ch395f_test_task.c:419` "只查询积压字节数…可反复调用"、`:476-477` "剩余字节下一轮 get_recv_len 会继续报告,不会丢")。同族结论"部分排空致命"已由 Trap 21 结案撤回,本条当时未同步。现象本身(当年确实观察到 `recv_len` 归零)保留为历史记录;定案前须补一条"部分读 → 再查 `recv_len`"的定向 TC。下方解法数字均为历史值:现 `CH395F_SPI_DMA_BUF_SIZE = 2048+4 = 2052`(`ch395f.h:148`)、`lftpd.c:228` 是 `static unsigned char buffer[1024]`,`s_recv_buf[4096]` 已不存在。**
|
||||
|
||||
同时 `CH395F_DMA_BUF_SIZE=1500`(header 4 + max 1496 data),无法一次读取完整的 4096 字节 CH395F 接收缓冲区。
|
||||
|
||||
### 解决方案
|
||||
@@ -466,7 +468,7 @@ DHCP 状态位仅代表协商流程完成;IP/MASK/GW 寄存器的提交与状
|
||||
NET 层 TCP Client(阶段 7)`net_connect()` 返回 0,但 `net_poll()` 报 `sock0 CONNECT TIMEOUT`,连接永远建立不起来;而硬件层 TCP Client(阶段 2,同一 `net_init`/FUN_PARA=0x08,同一目标 192.168.1.2:8081)完全正常。PC 同网段、防火墙关闭、服务端正常监听。
|
||||
|
||||
### 根因
|
||||
`net_connect_locked()` 把 `sockaddr_in.sin_addr.s_addr`(网络字节序,`net_inet_addr` 返回)按 **低字节在前** 拆成 `remote_ip_arr[4]`,得到 `[2,1,168,192]`,再交给 `ch395f_set_des_ip()`。但 **CH395F 的目的 IP/端口寄存器是大端(网络字节序)**(阶段 2 用 `test_parse_ip("192.168.1.2")` 直接得到 `[192,168,1,2]` 即成功,可证)。于是芯片把 SYN 发往 `2.1.168.192`——一个跨网段、不可达的地址,SYN 被网关丢弃 → 无 SYN-ACK → `CONNECT TIMEOUT`。
|
||||
`net_connect_locked()` 把 `sockaddr_in.sin_addr.s_addr`(网络字节序,`net_inet_addr` 返回)按 **低字节在前** 拆成 `remote_ip_arr[4]`,得到 `[2,1,168,192]`,再交给 `ch395f_set_des_ip()`。但 **`SET_IP_ADDR_SN` 族按点分顺序(`[192,168,1,2]`)写入才生效**(阶段 2 用 `test_parse_ip("192.168.1.2")` 直接得到 `[192,168,1,2]` 即成功,可证;官方例程 `EXAM5_TCP_Server/main.c:39 CH395IPAddr={192,168,1,101}` 同向)。⚠ 2026-10-11 复核:手册 §5.8 的总括"所有包含 IP 输入或输出的命令,字节顺序均为 IP 低字节在前"与官方例程自相矛盾,本仓以实测 + 例程为准;**端口不在此列**——§5.25/§5.26 明确低字节在前,驱动 `ch395f_set_des_port`/`set_sour_port` 即如此且工作正常,勿把"大端数组"套到端口上。于是芯片把 SYN 发往 `2.1.168.192`——一个跨网段、不可达的地址,SYN 被网关丢弃 → 无 SYN-ACK → `CONNECT TIMEOUT`。
|
||||
|
||||
**误导性排查**:`CMD_GET_REMOT_IPP_SN` 回读的是**小端**字节序(`ch395f.c` 注释 "IP和端口均为低字节在前")。把写反的 `[2,1,168,192]` 读回再按小端解释,恰好又得到 `192.168.1.2`,使回读日志看起来"目的地址正确",掩盖了真实写反。
|
||||
|
||||
@@ -477,7 +479,7 @@ NET 层 TCP Client(阶段 7)`net_connect()` 返回 0,但 `net_poll()` 报
|
||||
|
||||
### 注意事项
|
||||
- `net_inet_addr` 返回网络字节序;`sin_addr.s_addr` 一律按网络字节序理解。
|
||||
- 任何写 CH395F IP/端口寄存器(set_des_ip / set_ip_addr / set_gwip_addr / set_mask_addr)都传**大端数组**,与 `test_parse_ip` 产物一致。
|
||||
- 任何写 CH395F **IP 四字节数组**(set_des_ip / set_ip_addr / set_gwip_addr / set_mask_addr)都传**点分顺序数组**,与 `test_parse_ip` 产物一致;**16 位端口一律低字节在前**(§5.25/§5.26),两者口径不同。
|
||||
- 回读类命令(GET_REMOT_IPP / GET_IP_INF 等)若文档标注"低字节在前",打印时务必先按小端重组再格式化,否则会误判。
|
||||
|
||||
### 对应文件
|
||||
@@ -527,8 +529,8 @@ NET 层 TCP Client(阶段 7)`net_connect()` 返回 0,但 `net_poll()` 报
|
||||
1. `net_init`:`ch395f_set_fun_para(0x09)`(bit0=1, bit1=0, bit3=1)。⚠ **2026-10-11 已改回 `0x08`**(bit0 保留必须为 0,见「定案更正」)。
|
||||
2. `ch395f_init()` 之后,循环 0~7 用 `ch395f_set_send_buf(sock, i*6+4, 2)` / `ch395f_set_recv_buf(sock, i*6, 4)` 给每个 Socket 分配独立收发缓冲。按`docs/芯片手册/CH395F.md` §5.45(48 块 × 512B = 24KB)+ §9.2.8 最优分配:每 Socket 6 块 = 接收 4 块(2KB) + 发送 2 块(1KB),`ch395f_set_tcp_mss(1024)`,恰好用尽 0~47 块、互不重叠。
|
||||
3. MSS 选取依据 §9.2.8:接收缓冲(2KB) ≥ 2×MSS(1024) 满足建议、≥ MSS 满足必须;发送缓冲(1KB) ≤ 8KB 满足必须。MSS 取 1024 为 8-Socket 共享 24KB 时的最大值。
|
||||
4. `net_init` 缓冲分配顺序遵循 Trap 01:先配数据 Socket,再配监听 Socket 0(本 Net 层 Socket 按需 open,故统一在 init 一次性配好)。UDP 路径 `net_socket()` 中对 Socket 4~7 的兜底重设也同步为同一布局。
|
||||
5. PC 端 `tcp_server` 改为每连接一线程的并发回显(`--max-conn` 为并发计数),否则 Phase 7 全量连接会触发累计计数上限而拒掉 4~7(Trap 19)。
|
||||
4. `net_init` 缓冲分配顺序遵循 Trap 01:先配数据 Socket,再配监听 Socket 0(本 Net 层 Socket 按需 open,故统一在 init 一次性配好)。UDP 路径 `net_bind()`(`net_socket.c:1000-1014`)中对 Socket 4~7 的兜底重设也同步为同一布局。
|
||||
5. PC 端 `tcp_server` 改为每连接一线程的并发回显(`--max-conn` 为并发计数),否则 Phase 7 全量连接会触发累计计数上限而拒掉 4~7。
|
||||
|
||||
### 注意事项
|
||||
- 4~7 的缓冲必须显式分配,否则其 CONNECT/RECV 中断不触发(Trap 01/02)。
|
||||
@@ -904,3 +906,55 @@ Trap 22 的周期对账(200ms 节拍 + 400ms 去抖 + 1s 冷却)设计目标
|
||||
|
||||
### 发现时间
|
||||
2026-10-11(登记簿 N-30;裸机芯片台架定案实验见本节,实验分支 `n30-chip-bench`)。
|
||||
|
||||
---
|
||||
|
||||
## 2026-10-11 寄存器 / 数值口径全量审计(智能体团队,只读)
|
||||
|
||||
**方法**:四路并行——驱动层逐命令(含官方 SDK 逐字对照)、NET/测试层逐调用点、Trap 01–12 复核、Trap 13–25 复核。三源交叉:`docs/芯片手册/CH395F.md` + WCH 官方例程 `CH395EVT/EXAM/PUB/CH395CMD.c`、`CH395INC.H` + git 历史。
|
||||
|
||||
### 干净清单(核对过、无异常)
|
||||
|
||||
| 项 | 计数 | 结论 |
|
||||
|---|---|---|
|
||||
| `CH395F_CMD_*` 命令码 | 55 | 与 §5 命令表 + SDK `CMDxx_` 逐个一致,无一抄错 |
|
||||
| 16/32 位量字节序 | 9 处 | 全部低字节在前,与手册明文 + SDK 逐字节一致 |
|
||||
| 读命令输出字节数 | 14 条 | 无少读/多读(`GET_SOCKET_STATUS`=2、`GET_IP_INF`=20 且顺序 IP→GW→MASK→DNS1→DNS2、`GET_UNREACH`=8、`GET_REMOT_IPP`=6) |
|
||||
| 常量表 | 60 个 | `ERR_*`18 / `TCP_*`11 / `SOCKET_*`2 / `PHY_*`6 / `PROTO_*`4 / `SINT_STAT_*`6 位号全对;唯一错值见 A3 |
|
||||
| **`GET_GLOB_INT_STATUS_ALL` 拼装方向** | — | **无异常**:我们 `第1字节\|第2字节<<8` 与官方 `CH395CMDGetGlobIntStatus()` 逐字相同;`glob & (1<<(sock+4))` = §5.16 bit4..bit11 = SDK `GINT_STAT_SOCKn` |
|
||||
| `get_socket_status` 缓冲区 | 17 处调用点 | 全部 `uint8_t st[2]`,无 1 字节残留(`db64e6ac` 引入 → `e5733b34` 修复,HEAD 无回归) |
|
||||
| 中断判据 | 17 掩码 / 32 全局读 / 27 SINT 读 | 位号与 §5.16/§5.23 一致;只用 16 位 ALL 版 |
|
||||
| 单位与取值范围 | 12 个参数点 | retrans 8/200 ms、KeepAlive 60000/5000(500 倍数、IDLE>INTVL)、ARP 100 ms 单位、MSS 1024 全部合规 |
|
||||
| 缓冲布局 | 3 处组合 | `net_init` 8×(4收+2发)=48 块恰好用满、无交叠(零裕量) |
|
||||
| 显示假象 | 10 处 `%d.%d.%d.%d` | 只有已定案的 `net_socket.c:1631` 是 MSB 重排假象,无新增同类 |
|
||||
|
||||
### 新发现(去重后按严重度;已修 = 本次提交内)
|
||||
|
||||
| # | 严重度 | 位置 | 问题 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| A1 | 中 | `test/board/ch395f_test_task.c:1005` | TC-203 的 Trap 14 反核实写成 `st_chk[0] == CH395F_TCP_ESTABLISHED`——byte0 只有 `00H/05H`,条件**恒假** → 该防线永久失效且日志无痕(与 Trap 07 同类:byte0/byte1 语义越界) | ✅ 已修(改 `byte0==OPEN && byte1==ESTABLISHED`) |
|
||||
| A2 | 中 | 同上 `:1150` / `:1321` | Phase 3/4 把 `GET_RECV_LEN` 返回值直接当读取长度(本地 `rx_buf[300]`/`[64]`,芯片 RX 缓冲 2 KB)→ 栈溢出 | ✅ 已修(夹到 `sizeof` + 留痕) |
|
||||
| A3 | 低 | `ch395f.h:253` | `CH395F_GINT_STAT_DHCPV6 = 0x8000`(bit15);SDK 是 `(1<<12)`、§5.16 明确 CH395F 的 `[12:15]` 保留 | ✅ 已修(改 `0x1000` + 注明本芯片恒 0;全仓零引用) |
|
||||
| A4 | 低 | `ch395f.h:33-91`、`ch395f.c:484/506`、`ch395f.h:701` | 分组注释字节数错 4 处(`GET_GLOB_INT_STATUS_ALL`/`GET_UNREACH_IPPT` 归"1 字节输出"、`SET_FUN_PARA` 归"1 入 1 出"、`SET_RETRAN_PERIOD` 归"3 字节输入"、`GET_SOCKET_STATUS_SN` 归"1 字节输出");KeepAlive 参数注释写"秒"(§5.53/5.54 是 ms);`set_retrans_count` 写"0=默认值5"(§5.17 默认 12、无 0=默认语义)。**实现全部正确,注释误导**——Trap 25 的 1 字节缓冲栈越界正是这类注释发起的 | ✅ 已修 |
|
||||
| A5 | 低 | `net_socket.c:238/1005/1080/1297/1666/708/3056` | 注释与手册/HEAD 相反:`FUN_PARA(SOCKET_CLOSE=0)`(实为 bit3=1,正是 closed-with-data accept 的契约依据)、"初始化成功后设置 MAC"(§9.2.1 ① 是之前)、"复用默认缓冲"(已 8 Socket 显式分配)、"布局由 MSS 推导"(固定布局、Trap 21 已解耦)、"等 SEND_OK"(门控是 SENBUF_FREE)、UDP 头 `[0-1] reserved`(§9.2.4 是数据长度) | ✅ 已修 |
|
||||
| A6 | 低 | `ch395f.c:1176` | `write_send_buf` 超限**静默 return**(void、无日志),且上限取 DMA 2048 而非发送缓冲 1024;读路径有 OVERSIZE 金丝雀、写路径没有 | ✅ 已修(补 `[ERR]` 留痕 + >1 KB 告警,行为不变) |
|
||||
| B1 | **中** | `net_socket.c:3553` | **产品路径从未启用 Socket KeepAlive**:`set_keepalive_enable` 唯一调用点在 `CONNECTING`(client)分支,产品三个服务(21/8888/7003)全是 TCP Server,`net_connect()` 只有测试在调 → 60 s/5 s/3 参数空转。§5.56 明文"Socket 为 TCP 服务器时,在产生 `SINT_STAT_CONNECT` 后打开 Keepalive",官方 `EXAM5_TCP_Server` 正是在 CONNECT 分支调 | ⏳ 待修(LISTENING→ESTABLISHED 分支补一行;需实测静默断开能否触发 `TIM_OUT`) |
|
||||
| B2 | 中低 | `net_socket.c:1638` | `ch395f_tcp_connect()` 返回值被丢弃(同文件 open/listen 都查),命令级被拒不产生中断 → 停在 `CONNECTING`,要等 30 s recv 超时才知失败;且 `net_reconcile_tick` 只裁 ESTABLISHED/LISTENING,`CONNECTING` 无人收口 | ⏳ 待修 |
|
||||
| B3 | 低 | `net_socket.c:1120-1123` | `net_listen_locked` 对 8 个 Socket 全量 `GET_INT_STATUS_SN`(读即清)→ 吞掉其它在用 Socket 的挂起事件(RECV 是电平语义可下轮补回,CONNECT/DISCONNECT 边沿语义会丢) | ⏳ 待修(只清本 Socket) |
|
||||
| B4 | 低 | `net_socket.c:446/469` | 全局中断 bit0-3(`UNREACH`/`IP_CONFLI`/`PHY_CHANGE`/`DHCP`)被读清但从不消费;`ch395f_get_unreach_info()` 全仓零调用 → IP 冲突、ARP 不可达、链路抖动三类事件完全静默 | ⏳ 待修(可观测性缺口) |
|
||||
| B5 | 低 | `net_socket.c:3849-3854` → `lftpd.c:803-809` | `net_getsockname` 的 `s_addr` 组装方向与本层约定(`net_inet_addr`/`net_inet_ntoa`)相反 → FTP 日志把设备自身 IP 打成 `100.1.168.192`。⚠ 同一 `getsockname` 的 PASV 227 消费点(`lftpd.c:497-503`)做了 `net_htonl` 再 MSB 拆,**双重反转恰好正确,勿误判**;风险前瞻:若把该 `s_addr` 喂给 `net_connect`/`net_sendto` 就会连到反序地址 | ⏳ 待修(改一处须同时核对 PASV) |
|
||||
| B6 | 低 | `net_socket.c:591/1225/3608` | 3 处状态判据只看 `byte1`、未按 §5.22 用 `byte0` 门控;reconcile 的 else-if 链里 `(00H, 陈旧 04H)` 会先命中"补 accept"而非"重建监听" | ⏳ 待修(Trap 07 实测 `byte0=00H` 时 `byte1` 读回 `0x00`,故为低概率) |
|
||||
| B7 | 低 | `ch395f_test_task.c:1379/1504` | Phase 5 单次写 4093 B 超 1 KB 发送缓冲与 2048 DMA 载荷 → 整块被丢;注释仍写"4096 B = 发送缓冲上限"(2026-09-22 布局解耦前的旧事实)。A6 修后会打 `[ERR]` 而非静默 stall | ⏳ 待修(chunk 改 ≤1024 或分块) |
|
||||
| B8 | 低 | `ch395f_test_task.c:1290-1292` | Phase 4 把 sock6 缓冲重排到块 24-27,与 `net_init` 固定布局中 sock4 的 24-27 **交叠**(§5.45 禁止) | ⏳ 待修 |
|
||||
| B9 | 低 | `ch395f_reuse_bench.c:93`、`net_socket.c:39`、`net_socket.c:262` | bench 用 `get_phy_status() != 0` 判链路(01H=断开也成立,`net_task.c:122` 的 `!= CH395F_PHY_DISCONN` 才对);`NET_PHY_CHECK_INTERVAL_MS` 死宏;无芯片版本门控(§5.16 <0x44 不支持 ALL 版、§5.52 bit3/4 需 ≥0x46,实测 0x4A 无影响) | ⏳ 待修(前两项死代码/卫生) |
|
||||
|
||||
### 文档侧待修清单(本轮只改了最要紧的几处,其余登记在此)
|
||||
|
||||
- **最高优先级**:Trap 13 的"部分读后 `recv_len` 归零"与 §5.34 直接冲突(已在本条加复核注),但**同一机理仍被当作现行约束**写在 `CH395F_Test_Guide.md:28/69/930/932/958`、`docs/网络/BSD_Socket_API_函数调用关系.md:196/362`、`net_socket.c` 两处注释里——须与 Trap 21 的撤回同批处置,并补一条"部分读 → 再查 `recv_len`"的定向 TC。
|
||||
- 陈旧数字:`CH395F_Test_Guide.md:14/24/645/660/1141/1200`(DMA 4100 / 载荷 4096,现 2052/2048)、`:72/1201`(`NET_DMA_MAX_PAYLOAD=4096`,现 2048;实际分块上限是 `NET_SEND_CHUNK_MAX`=1024)、`:1020-1040`(TC-NET-1002/1003 期望 4096/4097 单次 DMA)、`docs/网络/BSD_Socket_API_使用指南.md:1246`(`NET_SEND_BUF_SIZE` 宏已不存在)。
|
||||
- 悬空引用:`Trap 19` 从未存在(`Test_Guide.md:878` 仍引用);`Test_Guide.md:353/418` 的"见风险 #4 / 风险表 #1"指向已删除的表。
|
||||
- 口径冲突:`Test_Guide.md:1135` 的 TRAP-07 行仍写"卡 FIN_WAIT_2 / `close_socket`(RST)"(与 Trap 07 定案更正冲突);`:45` 的"TC704 40/40"与 `:880` 的"`PHASE7_MULTI_COUNT` ≤5"矛盾(HEAD 宏值仍是 8);`Drivers/BSP/NET/README.md:35` 与 `net_socket.c:1864` 的"正常 FIN 路径零改动"与 Trap 23 二阶段矛盾。
|
||||
- 机理措辞:Trap 17"等**对端** FIN/ACK"应按 Trap 07 实测改写(自身 FIN 的 ACK + 本地 TIME_WAIT,0~150 ms);Trap 20"硬件发送 FIFO 1 KB"应改"本仓 2 块分配的发送缓冲区"(§5.45 上电默认是 4 块=2 KB)、"等 `SEND_OK`"应为 `SENBUF_FREE`;Trap 25 的 `NET_MSG_FIX` 应为 `NET_MSG_RESYNC_LISTEN`、`GET_REMOTE_IPP` 应为 `GET_REMOT_IPP`、"§5.45"应为 §5.32+§5.23①。
|
||||
- 已失效条目未标注:Trap 01/02/11 的多连接模型随 2026-08-25 `319d00e3` 删除;Trap 09 的 `osDelay(7000)` 已被就绪屏障取代;Trap 10 的"`net_connect()` 不使用消息队列"已失效;Trap 12 的 #2/#4 与仓内 FatFs 源码矛盾(`ff.c:3101-3109` 剥前导分隔符、`:3127-3129` 空名返回根目录),且 `FF_FS_RPATH=0` 下 `"."` 不是合法路径段(HEAD 用 `"0:"`)。
|
||||
- 日期:Trap 01/02/03/04/06/07 的"2025-07"均早于仓库首提交 `b1d05091`(2026-06-05);Trap 03/04/06 的 Phase 编号也错(DHCP=阶段 4、UDP=阶段 3、KeepAlive=阶段 11)。
|
||||
- 证据通则:`*.log` 在 `.gitignore` 内 → 本文所有台架计数(40/40、34/34、15/15、4 轮 11/11、13/13…)**脚本在库、日志未入库 = 不可复核**;Trap 25 引用的实验分支 `n30-chip-bench`(tip `eddbede`)不含 bench 源文件与 uvprojx 注册,裸机芯片台架无法从任何已提交状态重建。
|
||||
|
||||
Reference in New Issue
Block a user