fix(NET)+docs: lftpd 对端地址修复、E6 裁决收口、陷阱编号迁移重排 TRAP-NET-01~21
- lftpd:net_inet_ntoa 段序改 MSB 首 + 新增 net_getpeername,FTP 日志打印 真实对端地址(真机实证 192.168.1.2:55524,登记 TRAP-NET-21) - E6:NET_U15_PROBE 命中=0(含压测)→ 阶段 3 项 4 不立项,U15 登记观察项; 插桩留仓(宏=0 零成本),soak 驱动 test/host/e6_soak.py 入库 - 编号:全库 Trap NN → TRAP-NET-<nn> 迁移并重排连续 01~21(单调映射, 沿革见 CH395F_Trap_Records.md 头注);死号 12/13/19/21 引用全部清除; GD5F 域引用补正为 TRAP-GD5F-NN - 陷阱文档全新化:索引 21 行行行真陷阱;删误判存档/发现时间/git 考古/ FTP 附录;台架纪律教训沉淀第六章方法论 - RAM:Code 211348→211456(+108 lftpd 修复),RW+ZI 净增 +4B; 优化方案/台账受管区/tsv 同笔同步 - ftp_abort_probe.py 挪 test/host/;引用关系图重生成 - 回归:@build 0/0;@test PASS;ftp_abort 10/10;relisten :7003 20/20; ci_local L0+L0.5 全绿;E6 窗口零复位,7 条 WD stall 登记压测假象备查
This commit is contained in:
+157
-86
@@ -39,6 +39,24 @@
|
||||
*/
|
||||
#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔(ms) */
|
||||
|
||||
/* N34 E6 实验插桩(U15 失配频率,docs/网络/N34-自愈审计/实验方案.md §E6):
|
||||
* 假设=「RX 非空但 readable=0」(RECV_OK 中断丢失的数据面形态)在生产真实
|
||||
* 发生。置 1 烧实验固件:net_poll 每 32 轮对在用 fd 发一条 GET_RECV_LEN,
|
||||
* 命中计数 + 低频日志(每小时 ≤1 条防刷屏);跑 24h 常态 + E1 压测。
|
||||
* 判据:命中 >0 → 阶段 3 项 4(U15 内化)立项;=0(含压测)→ 上层 32 轮
|
||||
* 盲收保留现状、U15 登记观察项。**默认 0 = 产品构建零成本(编译剔除)**。
|
||||
* E6 已裁决(2026-10-13,实验方案 E6 结果):命中=0(含压测)→ 项 4 不立项,维持默认 0。
|
||||
* ⚠ 必须定义在文件最前部:bring_up 的 armed 日志与 net_poll 探测环两处消费。 */
|
||||
#define NET_U15_PROBE 0
|
||||
#if NET_U15_PROBE
|
||||
#define NET_U15_PROBE_PERIOD 32U /* 每 32 轮 net_poll 探测一次(≈32ms) */
|
||||
#define NET_U15_PROBE_LOG_MS 3600000U /* 命中日志每小时至多 1 条 */
|
||||
static uint32_t s_u15_round; /* net_poll 轮次计数 */
|
||||
static uint32_t s_u15_hits; /* 累计确认命中次数(判据数据) */
|
||||
static uint32_t s_u15_last_log; /* 上次命中日志时刻(tick) */
|
||||
static uint8_t s_u15_cand[NET_MAX_SOCKETS]; /* 两级确认的候选标记(per-socket) */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 全局变量定义区 - 尽量避免使用全局变量
|
||||
*/
|
||||
@@ -235,7 +253,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
* 2. 启用 TCP Server 多连接模式(bit1=1),设置 TCP MSS、重传参数、KeepAlive 参数
|
||||
* 3. 配置 IP/网关/子网掩码,或启用 DHCP
|
||||
* 4. 初始化 CH395F 协议栈并使能 PING 响应
|
||||
* 5. mac 非空且非全零:初始化**之前**设置 MAC(§9.2.1 ①,Trap 24;
|
||||
* 5. mac 非空且非全零:初始化**之前**设置 MAC(§9.2.1 ①,TRAP-NET-19;
|
||||
* 写芯片 EEPROM,每上电重放同值幂等)
|
||||
*/
|
||||
int net_init(const char *ip, const char *mask, const char *gateway, const uint8_t *mac) {
|
||||
@@ -260,7 +278,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
ch395f_reset();
|
||||
|
||||
/* 芯片版本留痕 + 0-6 版本门控(N34 阶段0,§5.52 表):bit3 SOCKET_CLOSE
|
||||
* 需芯片 ≥0x46、TCP_SERVER 需 ≥0x44。本台架芯片实测 ≥0x46(Trap 25 定案
|
||||
* 需芯片 ≥0x46、TCP_SERVER 需 ≥0x44。本台架芯片实测 ≥0x46(TRAP-NET-20 定案
|
||||
* SOCKET_CLOSE 实际生效);门控防批次漂移——版本不足则**拒置 bit3**
|
||||
* (退回芯片自动关断语义)并 [ERR] 留痕,不静默带病运行 */
|
||||
uint8_t chip_ver = ch395f_get_version();
|
||||
@@ -276,18 +294,18 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
DBG_INFO("ch395f ver=0x%02X fun_para=0x%02X", chip_ver, fun_para);
|
||||
|
||||
/* 功能参数(§5.52 表):bit3=1 SOCKET_CLOSE——DISCONNECT/TIMEOUT 后芯片
|
||||
* 不清缓冲,由 MCU 读出残留数据后再关 Socket(Trap 25 三次定案的排空契约);
|
||||
* 不清缓冲,由 MCU 读出残留数据后再关 Socket(TRAP-NET-20 三次定案的排空契约);
|
||||
* bit1=0 TCP_SERVER 多连接模式不用(本项目单连接模型:每监听器独占一个
|
||||
* Socket,监听转数据通道);bit0 保留必须为 0——旧注释"bit0=1 多 Socket
|
||||
* 模式"手册与网络资料均无出处(多 Socket 由 SN 命令族寻址实现,与 FUN_PARA
|
||||
* 无关),且违反保留位规定 → 0x09 改 0x08(2026-10-11 定案:官方手册
|
||||
* V1C/V1E/V2.2/V2.3 的 bit0 全是保留位,官方例程 bit0=0 下 Socket 0~7 照常
|
||||
* 可用、FTP 例程本身就传 0x08;证据链见 Trap 18「定案更正」,
|
||||
* 可用、FTP 例程本身就传 0x08;证据链见 TRAP-NET-15,
|
||||
* 0x08 下的多 Socket 台架复测登记 N-31) */
|
||||
ch395f_set_fun_para(fun_para);
|
||||
|
||||
/* 设置 TCP MSS:维持 1024(512 裕量方案未采纳,当年支撑它的台架判据不可信,
|
||||
* 已随 TC-NET-604 结案为非缺陷一并撤回(2026-09-23,见 Trap 21)) */
|
||||
* 已随 TC-NET-604 结案为非缺陷一并撤回(2026-09-23)) */
|
||||
/* 手册(§5.45):内部缓冲共 48 块 × 512B = 24KB,每 Socket 分配 6 块(接收 4 块 = 2KB + 发送 2 块 = 1KB) */
|
||||
/* 块布局固定(与 MSS 解耦);MSS=1024 为满足布局的最大值(接收 = 2×MSS),
|
||||
* 真值源为 ch395f.h 的 CH395F_TCP_MSS */
|
||||
@@ -347,7 +365,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
/* 每 Socket 6 块:接收 CH395F_RECV_BLOCKS(=4 块=2KB) + 发送 CH395F_SEND_BLOCKS(=2 块=1KB),用满 48 块 */
|
||||
/* recv_start = i×6,send_start = recv_start+4;Socket 7 占块 42~47,恰好用尽 0~47,互不重叠 */
|
||||
/* 布局以手册 §5.45 为准;若实际芯片为其它缓冲规格需重新核算 */
|
||||
/* Trap 01:先配数据 Socket 1~7,再配监听 Socket 0 */
|
||||
/* TRAP-NET-01:先配数据 Socket 1~7,再配监听 Socket 0 */
|
||||
uint8_t blocks_per_socket = (uint8_t)(CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS);
|
||||
for (int i = NET_MAX_SOCKETS - 1; i >= 0; i--) {
|
||||
uint8_t recv_start = (uint8_t)(i * blocks_per_socket);
|
||||
@@ -424,21 +442,6 @@ static void net_bench_cmd_log(char tag, int sock, int detail) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* N34 E6 实验插桩(U15 失配频率,docs/网络/N34-自愈审计/实验方案.md §E6):
|
||||
* 假设=「RX 非空但 readable=0」(RECV_OK 中断丢失的数据面形态)在生产真实
|
||||
* 发生。置 1 烧实验固件:net_poll 每 32 轮对在用 fd 发一条 GET_RECV_LEN,
|
||||
* 命中计数 + 低频日志(每小时 ≤1 条防刷屏);跑 24h 常态 + E1 压测。
|
||||
* 判据:命中 >0 → 阶段 3 项 4(U15 内化)立项;=0(含压测)→ 上层 32 轮
|
||||
* 盲收保留现状、U15 登记观察项。**默认 0 = 产品构建零成本(编译剔除)**。 */
|
||||
#define NET_U15_PROBE 0
|
||||
#if NET_U15_PROBE
|
||||
#define NET_U15_PROBE_PERIOD 32U /* 每 32 轮 net_poll 探测一次(≈32ms) */
|
||||
#define NET_U15_PROBE_LOG_MS 3600000U /* 命中日志每小时至多 1 条 */
|
||||
static uint32_t s_u15_round; /* net_poll 轮次计数 */
|
||||
static uint32_t s_u15_hits; /* 累计命中次数(判据数据) */
|
||||
static uint32_t s_u15_last_log; /* 上次命中日志时刻(tick) */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 函数功能:轮询 CH395F 中断状态,更新 Socket 连接状态并处理事件
|
||||
* 入口参数:无
|
||||
@@ -576,26 +579,39 @@ int net_poll(void) {
|
||||
}
|
||||
|
||||
#if NET_U15_PROBE
|
||||
/* E6 探测(宏说明见文件上方):RX 非空而 readable=0 = RECV_OK 中断丢失
|
||||
* 的数据面形态。独立于上面的缓存刷新环:GET_RECV_LEN 是独立 SPI。 */
|
||||
/* E6 探测(宏说明见文件前部):RX 非空而 readable=0 = RECV_OK 中断丢失
|
||||
* 的数据面形态。**两级确认去良性竞态**:数据刚到、本轮中断尚未读取的
|
||||
* 竞态窗(≤1 个 poll)会在下一探测轮自然消失;丢中断则持续存在直到
|
||||
* 盲收/超时。候选轮标记 → 下一探测轮仍成立才计确认命中。排除 CLOSED:
|
||||
* closed-with-data 是已知被救回形态,非 U15 假设对象。独立于上面的
|
||||
* 缓存刷新环:GET_RECV_LEN 是独立 SPI。 */
|
||||
s_u15_round++;
|
||||
if ((s_u15_round % NET_U15_PROBE_PERIOD) == 0U) {
|
||||
for (int i = 0; i < NET_MAX_SOCKETS; i++) {
|
||||
uint16_t rlen;
|
||||
|
||||
if (s_net_socks[i].in_use == 0U) {
|
||||
s_u15_cand[i] = 0U;
|
||||
continue;
|
||||
}
|
||||
rlen = ch395f_get_recv_len((uint8_t)i);
|
||||
if ((rlen > 0U) && (s_net_socks[i].readable == 0U)) {
|
||||
s_u15_hits++;
|
||||
/* 首次命中必打(last_log=0 会被 uptime<1h 抑制);此后每小时 ≤1 条 */
|
||||
if ((s_u15_hits == 1U) ||
|
||||
((uint32_t)(HAL_GetTick() - s_u15_last_log) >= NET_U15_PROBE_LOG_MS)) {
|
||||
s_u15_last_log = HAL_GetTick();
|
||||
DBG_INFO("U15 probe: sock%d rx=%u readable=0 hits=%lu",
|
||||
i, (unsigned int)rlen, (unsigned long)s_u15_hits);
|
||||
if ((rlen > 0U) && (s_net_socks[i].readable == 0U) &&
|
||||
(s_net_socks[i].state == NET_SOCK_STATE_ESTABLISHED)) {
|
||||
if (s_u15_cand[i] != 0U) {
|
||||
s_u15_cand[i] = 0U;
|
||||
s_u15_hits++;
|
||||
/* 首次命中必打(last_log=0 会被 uptime<1h 抑制);此后每小时 ≤1 条 */
|
||||
if ((s_u15_hits == 1U) ||
|
||||
((uint32_t)(HAL_GetTick() - s_u15_last_log) >= NET_U15_PROBE_LOG_MS)) {
|
||||
s_u15_last_log = HAL_GetTick();
|
||||
DBG_INFO("U15 probe: sock%d rx=%u readable=0 hits=%lu",
|
||||
i, (unsigned int)rlen, (unsigned long)s_u15_hits);
|
||||
}
|
||||
} else {
|
||||
s_u15_cand[i] = 1U;
|
||||
}
|
||||
} else {
|
||||
s_u15_cand[i] = 0U;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -615,7 +631,7 @@ int net_poll(void) {
|
||||
#define NET_RECON_STABLE_DEATH 4U /* 形态① 连接已失(M3 让位窗 400ms,勿改小) */
|
||||
|
||||
/*
|
||||
* 函数功能:芯片/本层 socket 状态周期对账(Trap 22 丢中断自愈)+ 监听器 pump
|
||||
* 函数功能:芯片/本层 socket 状态周期对账(TRAP-NET-17 丢中断自愈)+ 监听器 pump
|
||||
* (N-32 P2)—— N34 阶段 3 合并为单一 100ms tick(docs/网络/N34-自愈审计/实施方案.md §5 项 1)
|
||||
* 入口参数:无
|
||||
* 出口参数:无
|
||||
@@ -712,7 +728,7 @@ static void net_reconcile_tick(void) {
|
||||
} else if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
if (c.tcp_state == CH395F_TCP_ESTABLISHED) {
|
||||
/* ② 本层 LISTENING 而芯片已完成握手(丢 CONNECT 中断)→ 补做 accept
|
||||
* N-30(Trap 25)幽灵态甄别:拆链收尾窗口内芯片假报 ESTABLISHED,
|
||||
* N-30(TRAP-NET-20)幽灵态甄别:拆链收尾窗口内芯片假报 ESTABLISHED,
|
||||
* 回读对端端口 = 上一条连接端口 → 不补 accept(补了会把数据发给
|
||||
* 已死的旧连接 = 生产 LIST#4 数据被吞的直接成因),等拆净或新 SYN。
|
||||
* 这是本 tick 唯一的按需 SPI(仅形态②命中时发) */
|
||||
@@ -737,7 +753,7 @@ static void net_reconcile_tick(void) {
|
||||
* 被动修正零风险:不去抖、不占冷却(原 pump 同口径) */
|
||||
DBG_INFO("sock%d reconcile: chip listening, resync CLOSED->LISTENING (U11)", i);
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* N-30(Trap 25):死连接对端端口转登幽灵甄别基准 + 探针计数清零
|
||||
/* N-30(TRAP-NET-20):死连接对端端口转登幽灵甄别基准 + 探针计数清零
|
||||
* —— 芯片监听器未被重开,芯片侧对端信息可能仍是上一条连接的,
|
||||
* 必须转登为基准,否则形态② 的幽灵拦截会失效 */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
@@ -787,7 +803,7 @@ static void net_reconcile_tick(void) {
|
||||
i, c.open, c.tcp_state);
|
||||
/* 仅修 MCU 侧;新连接的 CONNECT 中断会把两侧重新同步 */
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* N-30(Trap 25):死连接对端端口转登幽灵甄别基准 + 探针计数清零 */
|
||||
/* N-30(TRAP-NET-20):死连接对端端口转登幽灵甄别基准 + 探针计数清零 */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
/* 取消本 fd 在死连接上的挂起 recv(必通知,防调用方挂死) */
|
||||
@@ -811,7 +827,7 @@ static void net_reconcile_tick(void) {
|
||||
/*
|
||||
* 函数功能:netTask 主循环核心 —— 自愈 tick 宿主 + 消息队列分派器。每轮
|
||||
* 先跑三个非阻塞自愈 tick(D10 重监听 / L3 挂起 recv /
|
||||
* Trap 22 状态对账),再非阻塞排空队列按 msg.type 分派到 _locked 实现。
|
||||
* TRAP-NET-17 状态对账),再非阻塞排空队列按 msg.type 分派到 _locked 实现。
|
||||
* 入口参数:无
|
||||
* 出口参数:无
|
||||
* 返回值:无(void);消息结果经 xTaskNotify 通知值回传(成功=字节数/描述符,
|
||||
@@ -823,7 +839,7 @@ static void net_reconcile_tick(void) {
|
||||
* 节拍重试 open+listen,2s 总时限到期放弃留痕;本 fd 有在途挂起 recv 时跳过(L3 保险)
|
||||
* 3. net_pending_tick(L3):按节拍了结挂起 recv(数据/到点[仅显式预算]/断连);
|
||||
* L3 tripwire(N34 阶段 1.5):挂起超 60s 只 DBG_ERROR 留痕一次,不再强制了结/伪造返回值
|
||||
* 4. net_reconcile_tick(Trap 22 + pump 合并,N34 阶段 3):每 100ms 对账
|
||||
* 4. net_reconcile_tick(TRAP-NET-17 + pump 合并,N34 阶段 3):每 100ms 对账
|
||||
* ①②⑤ + ③④ 重建 + U11 重同步,判据读驱动状态缓存(net_poll 每轮
|
||||
* 全量刷新,E2 背书);去抖分级(②=1 轮/③④⑤=2 轮/①=4 轮,M3 让位窗)
|
||||
* + 1s 冷却;重建失败进 D10 重试队列,reconciler 不重复催
|
||||
@@ -841,11 +857,11 @@ void net_process_messages(void) {
|
||||
}
|
||||
|
||||
/* 三个非阻塞自愈 tick 置于消息处理之前:断连后即使无应用消息,监听器也能自主恢复 */
|
||||
/* D10 重监听重试(Trap 09):沉降后重开芯片监听器 */
|
||||
/* D10 重监听重试(TRAP-NET-09):沉降后重开芯片监听器 */
|
||||
net_listener_retry_tick();
|
||||
/* L3 挂起 recv 完成检查:数据到达 / 到点 / 断连时通知调用方 */
|
||||
net_pending_tick();
|
||||
/* Trap 22 状态对账 + 监听器 pump(N34 阶段 3 合并单一 100ms tick):
|
||||
/* TRAP-NET-17 状态对账 + 监听器 pump(N34 阶段 3 合并单一 100ms tick):
|
||||
* 判据读驱动缓存(net_poll 每轮全量刷新),①②⑤ 失同步 + ③④ 重建 +
|
||||
* U11 重同步全部在此(本层唯一周期重建入口,N-32 P2 单一所有者) */
|
||||
net_reconcile_tick();
|
||||
@@ -1083,7 +1099,7 @@ int net_socket(int domain, int type) {
|
||||
* net_setblocking(fd, 0) 显式设置)。close 的 memset 会清零本字段,
|
||||
* 新 fd 必须在此显式置 1(同 released_abnormal 的"不得继承"纪律) */
|
||||
p_sock->blocking = 1;
|
||||
/* 新 fd 不得继承上一条连接的释放原因(Trap 23 待办 #3) */
|
||||
/* 新 fd 不得继承上一条连接的释放原因(TRAP-NET-18 待办 #3) */
|
||||
p_sock->released_abnormal = 0;
|
||||
/* N-32(P1):新 fd 不得继承"上一条会话已结束"电平(否则新建即 EOF,
|
||||
* 消费侧连数据都收不到)——与 released_abnormal 同理,显式清零 */
|
||||
@@ -1157,7 +1173,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
uint8_t status;
|
||||
|
||||
/* net_init 已为全部 8 个 Socket 分配缓冲;此处仅对 Socket 4~7 兜底重设,
|
||||
* 使用与 net_init 相同的布局(固定 6 块/Socket,与 MSS 解耦,见 net_init / Trap 21) */
|
||||
* 使用与 net_init 相同的布局(固定 6 块/Socket,与 MSS 解耦,见 net_init) */
|
||||
if (sockfd >= 4) {
|
||||
/* 每 Socket 块数 = 接收 + 发送 */
|
||||
uint8_t blocks_per_socket = (uint8_t)(CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS);
|
||||
@@ -1218,7 +1234,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
* 2. 内部序列=E4 定案:读空 RX -> CLOSE -> 排空事件(quiescent) ->
|
||||
* 轮询 byte0=00H;WAIT_CLOSE 内置 LISTEN 态二段 CLOSE 补发
|
||||
* (E2 补充发现:一次 CLOSE 只拆监听 byte0 恒 05)
|
||||
* 3. 超时留痕返 -1,调用方按原语义兜底(Trap 09 重试环 / close 放行)
|
||||
* 3. 超时留痕返 -1,调用方按原语义兜底(TRAP-NET-09 重试环 / close 放行)
|
||||
*/
|
||||
static int net_sock_reset_sync(int sockfd, ch395f_reset_mode_t mode) {
|
||||
/* 起始时刻(600ms 上限基准) */
|
||||
@@ -1252,7 +1268,7 @@ static int net_sock_reset_sync(int sockfd, ch395f_reset_mode_t mode) {
|
||||
* 出口参数:无
|
||||
* 返回值:0 - 成功,-1 - 失败 int
|
||||
* 限定条件:sockfd 已绑定且为 TCP;netTask 上下文
|
||||
* 函数说明:1. 芯片侧 open + TCP_LISTEN(端口=控制块 local_port;open 失败重试 3 次,见 Trap 09)
|
||||
* 函数说明:1. 芯片侧 open + TCP_LISTEN(端口=控制块 local_port;open 失败重试 3 次,见 TRAP-NET-09)
|
||||
* 2. 成功置 LISTENING 并启用 auto_relisten(BSD 风格监听常驻)
|
||||
* 3. 启动监听前清**本 Socket** 中断状态寄存器(读即清),防残留误触发;
|
||||
* 全局中断寄存器交 net_poll 集中读清(B3,详见函数体内注释)
|
||||
@@ -1281,11 +1297,11 @@ int net_listen_locked(int sockfd) {
|
||||
/* 本地端口 = 控制块 local_port */
|
||||
ch395f_set_sour_port(sockfd, p_sock->local_port);
|
||||
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(Trap 09),故失败重试最多 3 次。
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(TRAP-NET-09),故失败重试最多 3 次。
|
||||
* P2b 收口(N34 阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
|
||||
* sock_reset(读空 RX -> CLOSE -> 排空事件 -> 等 byte0=00H,内置 LISTEN
|
||||
* 态二段 CLOSE 补发;E4 定案 60 轮实证复位后 open 必成)。GRACEFUL
|
||||
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,Trap 09 语义保留 */
|
||||
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,TRAP-NET-09 语义保留 */
|
||||
for (int open_try = 0; open_try < 3; open_try++) {
|
||||
/* 尝试打开芯片侧 Socket */
|
||||
status = ch395f_open_socket(sockfd);
|
||||
@@ -1315,7 +1331,7 @@ int net_listen_locked(int sockfd) {
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* 单连接模式:连接断开后由 net 层自动回到 LISTEN(模拟 BSD 监听常驻) */
|
||||
p_sock->auto_relisten = 1;
|
||||
/* N-30(Trap 25):新监听会话,丢中断去抖计数清零 */
|
||||
/* N-30(TRAP-NET-20):新监听会话,丢中断去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
/* 读即清:仅本 Socket 的中断状态——丢弃上一条会话残留的 DISCONNECT/
|
||||
* TIMEOUT,避免监听刚开始就误触发事件。
|
||||
@@ -1326,10 +1342,10 @@ int net_listen_locked(int sockfd) {
|
||||
* (芯片无按位清除手段),而 net_poll 只在**全局位置位时**才去读该
|
||||
* Socket 的 SINT(见 :469 门控)→ 全量清等于把别的在用 Socket 的门一并
|
||||
* 焊死,其 CONNECT/DISCONNECT 等边沿事件永久丢失(RECV 属条件位,下轮
|
||||
* 可补回,见 Trap 08)。
|
||||
* 可补回,见 TRAP-NET-08)。
|
||||
* 全局寄存器交 net_poll 集中读清(AGENTS 模块约定:所有 CH395F 中断经
|
||||
* net_poll 集中读取并清除);本 Socket 残留的全局位被 net_poll 读到时
|
||||
* SINT 已为 0,无害了结。Trap 14/17/23 指定的两级预清落在
|
||||
* SINT 已为 0,无害了结。TRAP-NET-12/-18 指定的两级预清落在
|
||||
* net_connect_locked / net_close_locked / relisten 隔离段,均为单 Socket,
|
||||
* 本次未动。 */
|
||||
(void)ch395f_get_sock_int_status((uint8_t)sockfd);
|
||||
@@ -1405,7 +1421,7 @@ int net_listen(int sockfd) {
|
||||
* (芯片状态寄存器 → ESTABLISHED)但 **CONNECT 中断被丢**——纯事件驱动的 accept
|
||||
* 永远等不到 → 数据被吞 / 425。固定沉降延时、Socket 轮换、listen 后 close 重试、
|
||||
* 缓冲重分配均已被实验证伪;唯一有效 = "中断 + 状态轮询"双信源(修复组 15/15
|
||||
* 全过,机制触发 5 次全部救回)。→ CH395F_Trap_Records.md Trap 25
|
||||
* 全过,机制触发 5 次全部救回)。→ CH395F_Trap_Records.md TRAP-NET-20
|
||||
* 幽灵态甄别:拆链窗口内芯片也会直接假报 ESTABLISHED(旧连接未拆净),此时回读
|
||||
* 对端端口 = 上一条连接端口;新连接临时端口几乎必然不同 → 端口相同不 accept,
|
||||
* 等旧连接拆净 / 新 SYN 到达(新连接若也丢中断,后续轮询以新端口命中)。 */
|
||||
@@ -1441,7 +1457,7 @@ static void net_lost_connect_probe(net_sock_t *p_sock) {
|
||||
/* 对端端口(小端 2 字节) */
|
||||
uint16_t peer = (uint16_t)(remote[4] | (remote[5] << 8));
|
||||
/* 幽灵甄别:仅"端口非零且 = 上一条连接端口"才判幽灵拦截;
|
||||
* peer==0(芯片对端端口提交滞后,Trap 15 同类)不拦截——宁可补 accept
|
||||
* peer==0(芯片对端端口提交滞后,TRAP-NET-13 同类)不拦截——宁可补 accept
|
||||
* 也不退回丢中断死等(2026-10-11 验证轮实测:peer==0 拦截把首连接
|
||||
* 丢中断的原有对账救援也挡死,LIST#1 卡满 20s,比修复前更糟) */
|
||||
if ((peer != 0U) && (peer == p_sock->last_peer_port)) {
|
||||
@@ -1466,9 +1482,9 @@ static void net_lost_connect_probe(net_sock_t *p_sock) {
|
||||
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
|
||||
* 限定条件:Socket 处于 LISTENING 状态
|
||||
* 函数说明:1. 单连接:监听 Socket 自身在 CONNECT 后已转为 ESTABLISHED
|
||||
* 2. 等待期叠加芯片状态轮询探针(丢 CONNECT 中断自愈,Trap 25)
|
||||
* 2. 等待期叠加芯片状态轮询探针(丢 CONNECT 中断自愈,TRAP-NET-20)
|
||||
* 3. CLOSED + 芯片 RX 缓冲有残留数据:接受"已关但可读"连接排空
|
||||
* (FUN_PARA §5.52 ② 保留现场契约,Trap 25 三次定案)
|
||||
* (FUN_PARA §5.52 ② 保留现场契约,TRAP-NET-20 三次定案)
|
||||
*/
|
||||
static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
/* 监听 Socket 控制块 */
|
||||
@@ -1484,7 +1500,7 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
/* 先轮询一次:把状态机刷新到芯片侧最新状态 */
|
||||
net_poll();
|
||||
|
||||
/* N-30(Trap 25):监听等待期兼做芯片状态第二信源——丢 CONNECT 中断时
|
||||
/* N-30(TRAP-NET-20):监听等待期兼做芯片状态第二信源——丢 CONNECT 中断时
|
||||
* 去抖补 accept(裸机台架实证:拆链窗口丢中断是数据被吞/425 的主根因,
|
||||
* 纯事件等待无自愈可能;详见 net_lost_connect_probe 区块注释) */
|
||||
if (p_listen_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
@@ -1683,7 +1699,7 @@ int net_listener_armed(int sockfd) {
|
||||
* 函数说明:1. ESTABLISHED → 看 readable(net_poll 在 RECV_OK 置位、读空清零)
|
||||
* 2. 非 ESTABLISHED / 描述符失效一律返回 1:必须让上层真的 recv 一次
|
||||
* 拿到 EOF/错误并复位自身状态,门掉它会把"连接已不存在"永久藏住
|
||||
* 3. ⚠ readable 仅由 RECV_OK 中断置位,Trap 22 对账不含"RX 非空但
|
||||
* 3. ⚠ readable 仅由 RECV_OK 中断置位,TRAP-NET-17 对账不含"RX 非空但
|
||||
* readable=0" → 中断丢失时本函数恒返 0,调用方须保留低频兜底 recv
|
||||
*/
|
||||
int net_can_read(int sockfd) {
|
||||
@@ -1780,7 +1796,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
* 限定条件:net_init() 已调用;必须在 netTask 上下文中调用
|
||||
* 函数说明:1. 校验控制块(in_use、TCP 类型、地址参数)并保存对端地址
|
||||
* 2. 芯片侧 OPEN(失败重试 3 次,每次失败走 sock_reset 确定性排渣,
|
||||
* 见 Trap 09 / P2b)+ 配置源/目的端口与目的 IP
|
||||
* 见 TRAP-NET-09 / P2b)+ 配置源/目的端口与目的 IP
|
||||
* 3. 清本 Socket 残留中断状态(丢弃上一条连接遗留的 DISCONNECT)
|
||||
* 4. 发起 TCP_CONNECT(驱动内已轮询 CMD_STATUS)并置 CONNECTING;
|
||||
* 命令级被拒立即关 Socket 返 -1,TCP 层成败仍由 CONNECT/TIMEOUT 裁定
|
||||
@@ -1831,11 +1847,11 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
/* 设置协议类型为 TCP */
|
||||
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
|
||||
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(Trap 09),故失败重试最多 3 次。
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(TRAP-NET-09),故失败重试最多 3 次。
|
||||
* P2b 收口(N34 阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
|
||||
* sock_reset(读空 RX -> CLOSE -> 排空事件 -> 等 byte0=00H,内置 LISTEN
|
||||
* 态二段 CLOSE 补发;E4 定案 60 轮实证复位后 open 必成)。GRACEFUL
|
||||
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,Trap 09 语义保留 */
|
||||
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,TRAP-NET-09 语义保留 */
|
||||
for (int open_try = 0; open_try < 3; open_try++) {
|
||||
/* 尝试打开芯片侧 Socket */
|
||||
status = ch395f_open_socket(sockfd);
|
||||
@@ -1928,7 +1944,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
*/
|
||||
#define NET_DMA_MAX_PAYLOAD ((int)CH395F_SPI_DMA_MAX_PAYLOAD)
|
||||
/* 单次写入 CH395F 发送 FIFO 的最大字节数:受硬件发送缓冲(CH395F_SEND_BUF_SIZE_BYTES=1KB)
|
||||
* 与 SPI DMA 载荷(NET_DMA_MAX_PAYLOAD=2KB) 双重限制,以硬件发送缓冲为硬上限(见 Trap 20),
|
||||
* 与 SPI DMA 载荷(NET_DMA_MAX_PAYLOAD=2KB) 双重限制,以硬件发送缓冲为硬上限(见 TRAP-NET-16),
|
||||
* 否则单次写 2KB/4KB 会写穿 1KB 发送 FIFO。 */
|
||||
#define NET_SEND_CHUNK_MAX ((int)CH395F_SEND_BUF_SIZE_BYTES < NET_DMA_MAX_PAYLOAD ? \
|
||||
(int)CH395F_SEND_BUF_SIZE_BYTES : NET_DMA_MAX_PAYLOAD)
|
||||
@@ -1941,7 +1957,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
* 出口参数:无
|
||||
* 返回值:实际发送字节数(>= 0);-1 表示参数无效或 Socket 未连接 int
|
||||
* 限定条件:p_sock 非空;Socket 处于 ESTABLISHED 状态;netTask 上下文
|
||||
* 函数说明:1. 按 NET_SEND_CHUNK_MAX(硬件发送缓冲上限,见 Trap 20)分块写入 CH395F 发送 FIFO
|
||||
* 函数说明:1. 按 NET_SEND_CHUNK_MAX(硬件发送缓冲上限,见 TRAP-NET-16)分块写入 CH395F 发送 FIFO
|
||||
* 2. 发送前等待 send_ready 置位,超时返回已发送字节数
|
||||
* 3. 每写完一块等待 SENBUF_FREE 中断(send_ready 清零后重新置位,§5.32/§5.23①)
|
||||
* 4. 发送中途断连(状态非 ESTABLISHED)→ 立即失败并返回已发字节
|
||||
@@ -1972,7 +1988,7 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
|
||||
while (sent < len) {
|
||||
/* 剩余待发字节 */
|
||||
int chunk = len - sent;
|
||||
/* 单块以硬件发送缓冲为上限(Trap 20:防写穿 1KB FIFO) */
|
||||
/* 单块以硬件发送缓冲为上限(TRAP-NET-16:防写穿 1KB FIFO) */
|
||||
if (chunk > NET_SEND_CHUNK_MAX) {
|
||||
chunk = NET_SEND_CHUNK_MAX;
|
||||
}
|
||||
@@ -2095,7 +2111,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)read_len);
|
||||
/* 累计接收字节统计 */
|
||||
p_sock->recv_bytes += (uint32_t)read_len;
|
||||
/* 已消费数据(部分读安全:手册 §5.34 未读数据保留可续读,旧"Trap 13
|
||||
/* 已消费数据(部分读安全:手册 §5.34 未读数据保留可续读,旧"部分读归零
|
||||
* 部分读归零"已降级为未证实历史观察;下一次 RECV_OK 重新置 readable) */
|
||||
p_sock->readable = 0;
|
||||
/* 返回本次读出字节数 */
|
||||
@@ -2159,8 +2175,8 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
* (INT# 电平触发链保证缓冲有数据时每轮重读 SINT 重位置位)
|
||||
* ② 到点(仅当登记时带显式预算 net_recv_to;无限等待登记无 deadline)→ NET_ERR_TIMEDOUT
|
||||
* ——这是调用方策略的正常兑现,不是伪造
|
||||
* ③ CLOSED:先排空(bit3=1 芯片断连后残数据留缓冲待 MCU 读——Trap 25 排空契约;
|
||||
* 旧注归 Trap 13 已随其复核注降级)→ 有数据按数据完成,否则 EOF(0) + 自动重监听
|
||||
* ③ CLOSED:先排空(bit3=1 芯片断连后残数据留缓冲待 MCU 读——TRAP-NET-20 排空契约;
|
||||
* 旧注归"部分读归零"机理、已随复核注降级)→ 有数据按数据完成,否则 EOF(0) + 自动重监听
|
||||
* 其他状态(CONNECTING/LISTENING/…)保持等待状态迁移(CONNECT→ESTABLISHED 是合法路径;
|
||||
* 陈旧 resync 由显式取消处理)——不做状态推断取消,避免误杀正在建链的等待
|
||||
* tripwire(N34 阶段 1.5 降级):挂起超 60s = "完成逻辑缺位"探针 → 只 [ERR] 留痕一次,
|
||||
@@ -2366,9 +2382,9 @@ static void net_pending_tick(void) {
|
||||
/* 非阻塞:失败由 D10 重试轮询接管(N-32 §10:入口收敛到 net_listener_try) */
|
||||
(void)net_listener_try(i);
|
||||
}
|
||||
/* Trap 23 待办 #3:异常释放(TIMEOUT/RST)不是正常 EOF(对端未发正常 FIN)
|
||||
/* TRAP-NET-18 待办 #3:异常释放(TIMEOUT/RST)不是正常 EOF(对端未发正常 FIN)
|
||||
* → 以连接重置了结:应用(lftpd STOR)对异常结束回 5xx 而非误报 226;
|
||||
* 正常 FIN(DISCONNECT)仍回 0(在途 FIN 与正常完成不可区分——协议边界,见 Trap 23 记录) */
|
||||
* 正常 FIN(DISCONNECT)仍回 0(在途 FIN 与正常完成不可区分——协议边界,见 TRAP-NET-18 记录) */
|
||||
/* 异常释放:以连接重置了结(回 5xx,不误报 226) */
|
||||
if (p_sock->released_abnormal != 0U) {
|
||||
/* 异常释放(错误码由 net_pending_complete 记入本任务槽位) */
|
||||
@@ -2527,7 +2543,7 @@ static void net_pending_settle_close(net_sock_t *p_sock) {
|
||||
* (唯一读者=net_poll;原循环读全局会焊死其它 Socket 事件位)
|
||||
* 3. 快路径:芯片已 CLOSED(byte0=00H)→ 跳过复位只清残留事件
|
||||
* 4. 复位超时照常放行(同原 500ms 超时容忍;后续 relisten 由
|
||||
* Trap 09 open 重试环吸收)
|
||||
* TRAP-NET-09 open 重试环吸收)
|
||||
*/
|
||||
static int net_close_locked(net_sock_t *p_sock) {
|
||||
/* 由控制块指针反推描述符 */
|
||||
@@ -2546,7 +2562,7 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
}
|
||||
|
||||
/* 清零控制块(memset 0 = 释放本 fd 全部状态) */
|
||||
/* N-30(Trap 25):幽灵甄别基准跨 fd 释放保留(幽灵属芯片 Socket 级状态,
|
||||
/* N-30(TRAP-NET-20):幽灵甄别基准跨 fd 释放保留(幽灵属芯片 Socket 级状态,
|
||||
* 与 fd 复用无关——close 后新 listen 落在同一芯片 Socket 上仍可能撞幽灵) */
|
||||
uint16_t keep_peer = p_sock->remote_port;
|
||||
memset(p_sock, 0, sizeof(net_sock_t));
|
||||
@@ -2570,7 +2586,7 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
* (PC 内核自动 ACK keepalive,僵尸判不死),单连接监听被永久
|
||||
* 占住;应用又不得 net_close 监听 fd(毁监听)——本函数补上
|
||||
* "拆连接不拆监听"的应用侧形态
|
||||
* 2. 拆除=sock_reset QUARANTINE(Trap 23 异常释放语义:FIN + 排渣 +
|
||||
* 2. 拆除=sock_reset QUARANTINE(TRAP-NET-18 异常释放语义:FIN + 排渣 +
|
||||
* 排空事件(quiescent) + 等 byte0=00H,内置二段 CLOSE 补发)
|
||||
* 3. auto_relisten(监听型 fd):收口 CLOSED 后即时 net_listener_try
|
||||
* (芯片已 CLOSED 直接 open 必成,E4 定案;失败交 D10 重试 +
|
||||
@@ -2585,7 +2601,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
/* L3:先了结本 fd 挂起 recv(排空/取消 + 必通知),再拆芯片会话 */
|
||||
net_pending_settle_close(p_sock);
|
||||
|
||||
/* 确定性拆除(异常释放 → QUARANTINE 400ms 底,Trap 23 语义) */
|
||||
/* 确定性拆除(异常释放 → QUARANTINE 400ms 底,TRAP-NET-18 语义) */
|
||||
if (net_sock_reset_sync(sockfd, CH395F_RESET_QUARANTINE) != 0) {
|
||||
DBG_ERROR("sock%d drop_conn: sock_reset not done", sockfd);
|
||||
/* 超时继续收口本层;芯片侧交 reconciler/pump 对账接管 */
|
||||
@@ -2594,7 +2610,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
/* 会话簿记收口(保留 fd:不 memset、不动 local_port/auto_relisten) */
|
||||
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||||
p_sock->readable = 0U;
|
||||
/* N-30(Trap 25):新会话起点,丢中断去抖计数清零 */
|
||||
/* N-30(TRAP-NET-20):新会话起点,丢中断去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
if (p_sock->auto_relisten) {
|
||||
@@ -2619,7 +2635,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
* (netTask 阻塞在 xTaskNotifyWait 而无人处理消息);netTask 内请直接用 net_send_locked()
|
||||
* 2. Socket 须处于 ESTABLISHED 状态
|
||||
* 3. net_init() + MX_FREERTOS_Init() 已执行,netMsgQueueHandle 已由 net_init 创建
|
||||
* 函数说明:1. 所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 Trap 16)
|
||||
* 函数说明:1. 所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 TRAP-NET-14)
|
||||
* 2. 本函数不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到 netMsgQueueHandle
|
||||
* 3. netTask 的 net_process_messages() 取出并在 netTask 上下文调用 net_send_locked() 真正写 CH395F
|
||||
* 4. 调用方经 FreeRTOS TaskNotify 阻塞等待处理结果,对外呈现"同步发送"语义
|
||||
@@ -3049,7 +3065,7 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
while (sent < len) {
|
||||
/* 剩余待发字节 */
|
||||
int chunk = len - sent;
|
||||
/* 单块以硬件发送缓冲为上限(Trap 20) */
|
||||
/* 单块以硬件发送缓冲为上限(TRAP-NET-16) */
|
||||
if (chunk > NET_SEND_CHUNK_MAX) {
|
||||
chunk = NET_SEND_CHUNK_MAX;
|
||||
}
|
||||
@@ -3442,6 +3458,9 @@ uint32_t net_inet_addr(const char *cp) {
|
||||
* 返回值:成功返回 buf 指针;buf 为 NULL 时返回 NULL char *
|
||||
* 限定条件:buf 非空且长度足够(>= 16 字节)
|
||||
* 函数说明:1. 先经 NET_NTOHL 转为主机字节序再格式化输出
|
||||
* 2. ⚠ 段序(N34 E13 §6 修复):NTOHL 后主机序数值的高字节才是
|
||||
* 点分第一段(192.168.1.100 → 0xC0A80164 → "192.168.1.100")。
|
||||
* 原实现低段在前,显示成字节反转的 "100.1.168.192"
|
||||
*/
|
||||
char *net_inet_ntoa(uint32_t addr, char *buf) {
|
||||
/* 网络序 → 主机序 */
|
||||
@@ -3452,12 +3471,12 @@ char *net_inet_ntoa(uint32_t addr, char *buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 四段格式化为点分十进制(最低段在前,16B 缓冲) */
|
||||
/* 四段格式化为点分十进制(高段在前,16B 缓冲) */
|
||||
snprintf(buf, 16, "%lu.%lu.%lu.%lu",
|
||||
(unsigned long)(naddr & 0xFF),
|
||||
(unsigned long)((naddr >> 8) & 0xFF),
|
||||
(unsigned long)((naddr >> 24) & 0xFF),
|
||||
(unsigned long)((naddr >> 16) & 0xFF),
|
||||
(unsigned long)((naddr >> 24) & 0xFF));
|
||||
(unsigned long)((naddr >> 8) & 0xFF),
|
||||
(unsigned long)(naddr & 0xFF));
|
||||
|
||||
/* 返回输出缓冲 */
|
||||
return buf;
|
||||
@@ -3656,7 +3675,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
|
||||
/* 监听态:DISCONNECT 落在监听器上 */
|
||||
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
/* Trap 22 / N-6:监听态收到 DISCONNECT——bit3=1(0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
|
||||
/* TRAP-NET-17 / N-6:监听态收到 DISCONNECT——bit3=1(0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
|
||||
* 触发 = 断连后 <~1s 快速复连时 CONNECT 中断未上报(控制块滞留 LISTENING)后该连接断开(2026-09-23 生产固件复现);
|
||||
* N-32 P2:本分支**只回读留痕、不再 relisten** —— 重建统一交
|
||||
* net_reconcile_tick 形态③(每 100 ms 读驱动缓存,监听失位即重建)。原处直接
|
||||
@@ -3695,7 +3714,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
}
|
||||
/* F-NET-17 M3(N34 实验 2026-10-13):矛盾态可疑门——芯片 Socket 仍 OPEN(0x05)
|
||||
* 而 TCP 槽 0x00 且本层 ESTABLISHED = 逻辑矛盾(活连接应 0x04):陈旧 DISCONNECT
|
||||
* (拆链完成滞后锁存,Trap 14)与"真断开恰被旧拆链覆写槽"在 D20 上不可分辨
|
||||
* (拆链完成滞后锁存,TRAP-NET-12)与"真断开恰被旧拆链覆写槽"在 D20 上不可分辨
|
||||
* (结构性失明,F-NET-15 Q1)。处置:不吃边沿,置可疑电平返回,交对账①
|
||||
* (ESTABLISHED + 芯片 TCP==CLOSED)电平去抖再入本函数(N34 阶段 3 合并
|
||||
* 后=4×100ms,NET_RECON_STABLE_DEATH,让位租约 400ms 不变 + 冷却):
|
||||
@@ -3724,9 +3743,9 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
* 留给 net_recv_locked 把剩余数据读出来再关,置 CLOSED 等待应用重新监听 */
|
||||
DBG_INFO("sock%d DISCONNECTED, releasing (chip st=0x%02X/0x%02X)",
|
||||
p_sock->ch395_sock, st[0], st[1]);
|
||||
/* Trap 23 推广(2026-09-24 台架实证):正常 DISCONNECT 释放留下的芯片收尾状态
|
||||
/* TRAP-NET-18 推广(2026-09-24 台架实证):正常 DISCONNECT 释放留下的芯片收尾状态
|
||||
* 会在复用同一 fd 的下一条连接上以"伪 DISCONNECT"形式投递(实测 accept 后约 10~20ms)→ 该连接被提前释放,应用把已到的 2048B 当整份文件并回报 226;
|
||||
* 仅**本连接收过数据**时登记沉降(实测触发源 = 收过数据的数据通道被关闭),纯连接即关/只发不收的连接免沉降,保住 Trap 22 的快速复连时序(:21 @0ms ×50 全通过) */
|
||||
* 仅**本连接收过数据**时登记沉降(实测触发源 = 收过数据的数据通道被关闭),纯连接即关/只发不收的连接免沉降,保住 TRAP-NET-17 的快速复连时序(:21 @0ms ×50 全通过) */
|
||||
/* F-NET-15 M1(N34 实验 2026-10-12):沉降**无条件**登记。原 recv_bytes!=0 门的
|
||||
* 受害者由事件时序定义(accept 后 ~20ms 被陈旧 DISCONNECT 杀 → recv_bytes==0 是
|
||||
* 构造性必然),门对"残渣循环自持"形态失效(n30_repro 背靠背 9/10 失败,E1 实测);
|
||||
@@ -3749,7 +3768,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
* recv 的 DONTWAIT 快路径先返数据(recv_len>0 优先),数据尽后判据
|
||||
* 落到本标志 → 仍得 EOF,不因排空慢而漏报 */
|
||||
p_sock->session_dead = 1U;
|
||||
/* N-30(Trap 25):登记本连接对端端口(幽灵态甄别基准,须在状态
|
||||
/* N-30(TRAP-NET-20):登记本连接对端端口(幽灵态甄别基准,须在状态
|
||||
* 迁移前记录——remote_port 此刻仍有效,relisten 清零) */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
/* 状态 → CLOSED */
|
||||
@@ -3776,11 +3795,11 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
* 限定条件:net_poll() 检测到 RECV_OK 中断后调用;netTask 上下文
|
||||
* 函数说明:1. 仅触发 NET_EVENT_DATA_RECEIVED 回调通知上层
|
||||
* 2. 不在此读取 recv_len:单一读取点归 net_recv_locked(省一次 SPI
|
||||
* 查询;Trap 13 时代的"读取冲突"顾虑已随复核注降级,结构保留)
|
||||
* 查询;旧"部分读归零"时代的"读取冲突"顾虑已随复核注降级,结构保留)
|
||||
*/
|
||||
static void handle_recv_event(net_sock_t *p_sock) {
|
||||
/* RECV_OK 中断已触发,直接通知上层。不在此读 recv_len,
|
||||
* 单一读取点在 net_recv_locked(省 SPI;原 Trap 13 顾虑已降级) */
|
||||
* 单一读取点在 net_recv_locked(省 SPI;原"部分读归零"顾虑已降级) */
|
||||
/* 置可读标志,供 net_select 在无 SPI 访问下判读 */
|
||||
p_sock->readable = 1;
|
||||
/* 触发数据到达事件回调 */
|
||||
@@ -3825,7 +3844,7 @@ static void handle_timeout_event(net_sock_t *p_sock) {
|
||||
} else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||
/* 已建立连接超时 */
|
||||
DBG_ERROR("sock%d TIMEOUT", p_sock->ch395_sock);
|
||||
/* Trap 23:异常释放(TIMEOUT,例如客户端中止上传)→ 复监听前隔离,
|
||||
/* TRAP-NET-18:异常释放(TIMEOUT,例如客户端中止上传)→ 复监听前隔离,
|
||||
* 等对端在途数据落尽并排空 RX 残渣(详见 net_relisten_locked 区块注释) */
|
||||
{
|
||||
/* 反推描述符 */
|
||||
@@ -3836,11 +3855,11 @@ static void handle_timeout_event(net_sock_t *p_sock) {
|
||||
net_listener_settle(qfd, NET_LISTENER_SETTLE_QUARANTINE);
|
||||
}
|
||||
}
|
||||
/* Trap 23 待办 #3:标记异常释放——L3 挂起 recv 排空断连后以
|
||||
/* TRAP-NET-18 待办 #3:标记异常释放——L3 挂起 recv 排空断连后以
|
||||
* NET_ERR_CONNRESET 了结(而非 EOF),应用(lftpd STOR)回报 5xx
|
||||
* 而非误报 226(见 net_pending_tick 断连分支) */
|
||||
p_sock->released_abnormal = 1U;
|
||||
/* N-30(Trap 25):异常释放同样登记对端端口(幽灵甄别基准) */
|
||||
/* N-30(TRAP-NET-20):异常释放同样登记对端端口(幽灵甄别基准) */
|
||||
p_sock->last_peer_port = p_sock->remote_port;
|
||||
/* N-32(P1 不变量 I):异常结束同样是"本会话已结束"电平(TIMEOUT/RST
|
||||
* 已在下方 requarantine,本标志只表达"会话结束了"这一事实,与
|
||||
@@ -3982,3 +4001,55 @@ int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
/* 成功(0) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取 Socket 对端地址(IP + Port)—— N34 E13 §6 lftpd 对端显示收口
|
||||
* 入口参数:sockfd - socket 描述符 int
|
||||
* 出口参数:addr - 输出:对端地址 struct net_sockaddr *
|
||||
* addrlen - 输入输出:地址结构体长度 int *
|
||||
* 返回值:0 - 成功,-1 - 失败(NOTCONN:尚无 CONNECT 事件回读过对端) int
|
||||
* 限定条件:socket 已连接(standalone accept / connect 成功后)
|
||||
* 函数说明:1. 数据源=CONNECT 事件时 ch395f_get_remot_ipp 回读并缓存的
|
||||
* remote_ip/remote_port(net_types.h),**不发 SPI**
|
||||
* 2. 单连接模型下监听 fd 转数据通道后同样有效(对端=刚接入的客户端)
|
||||
*/
|
||||
int net_getpeername(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
/* 描述符越界 → BADF */
|
||||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_BADF);
|
||||
}
|
||||
|
||||
/* 控制块(const:本函数只读 Socket 信息) */
|
||||
const net_sock_t *p_sock = &s_net_socks[sockfd];
|
||||
|
||||
/* 未在用 → BADF */
|
||||
if (!p_sock->in_use) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_BADF);
|
||||
}
|
||||
|
||||
/* 输出参数无效(NULL 或长度不足)→ INVAL */
|
||||
if (addr == NULL || addrlen == NULL || *addrlen < (int)sizeof(struct net_sockaddr_in)) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_INVAL);
|
||||
}
|
||||
|
||||
/* 尚无对端(未连接/未收到 CONNECT 回读)→ NOTCONN */
|
||||
if (p_sock->remote_port == 0U) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_NOTCONN);
|
||||
}
|
||||
|
||||
/* 强转为 IPv4 地址结构体 */
|
||||
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
|
||||
/* 清零地址结构体(防御:全部字段归零) */
|
||||
memset(p_addr_in, 0, sizeof(struct net_sockaddr_in));
|
||||
/* 地址族 = IPv4 */
|
||||
p_addr_in->sin_family = NET_AF_INET;
|
||||
/* 对端端口(主机序 → 网络序) */
|
||||
p_addr_in->sin_port = net_htons(p_sock->remote_port);
|
||||
/* 对端 IP:CONNECT 时已按网络序缓存,直传 */
|
||||
p_addr_in->sin_addr.s_addr = p_sock->remote_ip;
|
||||
/* 回填结构体长度 */
|
||||
*addrlen = sizeof(struct net_sockaddr_in);
|
||||
|
||||
/* 成功(0) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user