跳到主要内容

全栈审计 · 驱动层 (Darra_Pnet_Kernel + Darra_Pnet_Core native)

审计智能体: 驱动层审计 (只读, 未改任何代码) 日期: 2026-08-14 范围: Darra_Pnet_Kernel\Windows\Pnet\ (驱动源码+INF+scripts) + Darra_Pnet_Core\main\ (native p-net 移植层) 方法: 逐文件 Read + 跨仓 grep (服务侧 PnetDriverBridge / pnal_port.c 只读交叉核对) 分级: P0 阻断 / P1 必修 / P2 建议


0. 结论摘要

分级数量说明
P0 阻断0未发现崩溃级 / ABI 契约断裂级问题; 2026-08-11/12/13 三轮审计修复 (1168 / 0x3B / 0xD1 / close-after-unload / roundPNETCOMPAT2) 均已真实落地且注释与代码一致
P1 必修1INF Ndi\Interfaces LowerRange 口径与 ETH roundRANGE4 实测终态矛盾 (详见 §1.3)
P2 建议13陈旧注释/死代码/契约文档漂移为主, 均不影响当前运行正确性

Top 问题清单:

  1. [P1] Pnet INF LowerRange="ndis5,ndis4,ndis5_prot" vs ETH roundRANGE4 实测终态 LowerRange=ndis5 — 两侧注释互斥, 一侧必错 (证据: DarraRT_Pnet.inf:51 vs DarraRT_Eth.inf:24-29)
  2. [P2] 诊断环 BIND_CALLBACK 事件参数编码与 Diagnostics.h 注释不符 (1168 排障依据失真)
  3. [P2] RequireExclusiveBinding 已删/已失效, 但 INF/install-pnet.ps1/服务桥/TEST_Driver 四处注释仍称"必须=1"
  4. [P2] Log.h/Instance.h 两个头文件零接线; 事件码 0x0002-0x0005 定义后从未落环
  5. [P2] Nic.c 文件头 "NDIS 6.30" 与双注册防重注释中 "DarraRT_Pnet" 均为陈旧命名残留

1. 命名 / 绑定口径 (审计清单 1)

1.1 协议注册名 = BindForm DarraRTPnet — ✅ 一致 (roundPNETCOMPAT2 已落地)

位置判定
DarraRT_Pnet_Internal.h:62 DARRT_PNET_NDIS_PROTOCOL_NAMEL"DarraRTPnet" (BindForm 去下划线)
DarraRT_Pnet_Nic.c:644 NdisRegisterProtocolDriver 实际注册用上述宏
DarraRT_Pnet_Nic.c:687 DbgPrintroundPNETCOMPAT2 protocol registered name=%wZ — strings 可验
INF 组件 ID (netcfg -i DarraRT_Pnet)DarraRT_Pnet (带下划线, 组件 ID 本就该带)
INF AddService / Ndi\ServiceDarraRT_Pnet (与组件名一致, install-pnet.ps1 sc start/stop/delete 同键)
设备名 / 符号链接\Device\DarraRT_Pnet + \DosDevices\DarraRT_Pnet (Entry.c:541/594; 服务桥 \\.\DarraRT_Pnet)
NDIS 版本注册 6.0 (Nic.c:668 MinorNdisVersion=0, 对齐西门子 Snpnio 实测)

四名分工结论 (与 ETH 参照一致): 组件 ID = 服务键 = sc 目标 (带下划线); 注册名 = BindForm = NDIS Linkage 键 (去下划线)。这是 roundPNETCOMPAT2 的既定设计, Internal.h:55-62 注释有开发机实证据支撑, 不再是残留不一致。

1.2 HW ID / cat 文件名 — ✅ 一致

  • INF:26 %Description% = Install, DarraRT_Pnet ↔ HW ID darrart_pnet (INF:23-24 注释: 必须与 netcfg 组件 ID 同名, 旧 darrartpnet 无下划线是 0xe0000228 根因) ✅
  • CatalogFile = darrart_pnet.cat ↔ 磁盘 DarraRT_Pnet.cat (NTFS 大小写不敏感, install-pnet.ps1:44-46 已注释) ✅

1.3 [P1] INF LowerRange 口径与 ETH roundRANGE4 实测终态矛盾

  • 证据 Pnet: DarraRT_Pnet.inf:50-51

    HKR, Ndi\Interfaces, UpperRange, , "noupper"
    HKR, Ndi\Interfaces, LowerRange, , "ndis5,ndis4,ndis5_prot"

    注释 (44-45 行) 声称: "ndis5_prot = 协议媒体类型, NetTrans 类协议注册必需 — 缺它 netcfg 装协议 0x80070002; 旧 'ndis5,ethernet' 缺 ndis5_prot → netcfg 失败"。

  • 证据 ETH: Darra_EtherCAT_Master/Darra_EtherCAT_Kernel/Windows/Eth/DarraRT_Eth.inf:24-29 roundRANGE4 (2026-08-13 rig 实测 FINAL):

    "Binding match uses the protocol's LowerRange against the NIC media (ndis5 <-> ethernet). System protocols (lltdio/rspndr/Ndisuio) all use LowerRange=ndis5 + UpperRange=noupper ... Final form: LowerRange=ndis5 + UpperRange=noupper"

    即: 兄弟驱动在测试机上实测验证 ndis5 即可绑定 (19 绑定正常), 而 Pnet INF 注释断言"裸 ndis5 会 netcfg 失败、必须 ndis5_prot" — 两者互斥, 必有一侧注释是错的 (错误归因历史)。

  • 风险: 当前 Pnet 绑定可用 (roundPNETCOMPAT2 已修注册名), 但错误口径会误导下一次 1168 家族排障; 且多值 LowerRange 与系统协议 (lltdio/rspndr) 的既有形态不一致。

  • 建议 (必修): 以 ETH roundRANGE4 为唯一口径统一为 LowerRange = "ndis5", 同步更正 Pnet INF 44-45 行注释; 改后测试机 netcfg 重装 + Get-NetAdapterBinding 复核绑定数 (与 ag15-dev-pnet-test 波次合并验证)。若 rig 实测证明多值形式确有额外作用, 则反向更新 ETH 注释, 但两侧必须收敛为一个口径。

1.4 [P2] INF 第 2 行注释截断

DarraRT_Pnet.inf:2 ; DarraRT_Eth / DarraRT_Sync) 不得再绑同一网卡 (NDIS 双注册 = 蓝屏)。 — 句首缺主语/左括号 (应为 "(与 DarraRT_Eth / ...")。纯注释完整性, 不影响构建。


2. IOCTL 契约 (审计清单 2)

2.1 驱动 14 个 IOCTL ↔ 服务桥 14 个定义 ↔ pnal 5 个使用 — ✅ 一一对应, 无孤儿

驱动侧 (Internal.h:363-376, 0xB20-0xB2D) 全部在 Entry.c DarraPnetDeviceControl 有 case (Entry.c:194-398), 无未接线 IOCTL。

契约面证据判定
服务桥 C# 定义PnetDriverBridge.cs:388-427 14 个, CtlCode 公式 (0x22<<16)|(access<<14)|(func<<2) 与 CTL_CODE 展开一致; access 位: 读=0x1 / 读写=0x3 与驱动头逐项相同
native pnal 定义pnal_port.c:974-988 — audit-2026-08-10 已修 access 位 (旧固定 0x1<<14 导致 SEND/RECEIVE/MAP/UNMAP 差 0x2000 落 default 分支); 现 access=3/1 与驱动一致
pnal 实际调用SEND_CONTROL (1124) / RECEIVE_CONTROL (1149) / GET_DIAGNOSTICS / MAP_SHARED (1218) / UNMAP_SHARED 全在使用
结构体布局BIND_REQUEST/DEVICE_CONFIG/IOCR_CONFIG/IOCR_CONTROL/CONTROL_FRAME/DIAGNOSTICS/MAP_RESPONSE/SHARED_HEADER 逐字段对齐 Internal.h (含 LoopbackFrames err=122 修复、CpmCycleCounter 复用 Reserved32 尾段 ABI 不变)
共享内存总大小C sizeof = C# Marshal.SizeOf = 224 + 2880 = 3104 (README.md:88 "224=0xE0" 与代码实测一致; 旧文档 0x80 已废弃并有说明)

未用/孤儿盘点:

  • 驱动侧: 无孤儿 IOCTL。
  • 服务桥 GetCapabilities() (PnetDriverBridge.cs:1492) 定义后仅 TEST_Driver 冒烟链使用, 生产路径未见调用 — [P2] 能力查询未接入启动校验链 (建议 StartCore 前置调用做 ABI 门)。
  • SEND/RECEIVE_CONTROL 在 C# 桥无调用方, 但由 native pnal 经注入句柄真用 — 非孤儿 ✅。

2.2 BIND_ADAPTER NicSelect 匹配逻辑 (1168 家族) — ✅ 已闭环

  • 驱动保存 parameters->AdapterName (NDIS 内部名 \DEVICE\{GUID}) 到 Adapters[i].Name (Nic.c:116-119), NicSelect 用 RtlEqualUnicodeString(..., TRUE) 大小写不敏感精确匹配 (Nic.c:876-880)。
  • 服务侧 ResolveNdisAdapterName (PnetDriverBridge.cs:1660-1758) 下发前把友好名三级解析为 \DEVICE\{GUID} (已写死直用 / NetworkInterface.Id / 注册表 Control\Network 反查)。
  • 排障埋点真值: BIND_CALLBACK (回调是否真被调) + SELECT_RESULT (请求名 hash / 已绑定数 / 匹配结果) 入环, 1168 时可读诊断区分"回调未触发" vs "匹配失败" ✅。
  • 边界注意 (非问题): adapter Name 缓冲 256 WCHAR, NDIS 内部名为短 GUID 串, 截断不可达; BIND 请求尾部 NUL 校验 (Entry.c:228) 防未终止字符串 ✅。

3. 0x / 规范口径 (审计清单 3)

3.1 十进制-hex 混乱 — ✅ 干净

逐处核对 kernel 全部 magic/常量注释, 未发现 audit-2026-08-11 式"十进制写进 hex 注释"残留:

  • 0x100u (CLOSE 自愈事件 arg1) / 0x00010000u|0x00020000u|0x00030000u (绑卡/超时/Quiesce 阶段标记) / 0x7000|stage (卸载失败留痕) — 注释与数值一致 ✅
  • bound_count << 16 | 0x0000FFFF 匹配标记 (Nic.c:869-885) — 口径一致 ✅
  • 周期常量 MIN=1000 / MAX=1000000 µs 十进制, TEST_Driver README 冒烟判据同口径 ✅
  • DARRT_PNET_DATA_STATUS_RT1_DEFAULT 0x25 (Primary 0x01|DataValid 0x04|SPI 0x20) 与 CPM 校验掩码 0x04 分离 (Internal.h:83-92 + Frame.h:26-43) — 与 vendored p-net pf_ppm.c:273 / pf_cpm_driver_sw.c 对齐, 注释自洽 ✅
  • DARRT_PNET_MAX_CYCLE_ADVANCE 61440 十进制常量与 pf_cpm_check_cycle (接受 [1,61440]) 对齐 ✅
  • 尾部 magic 0xDA55 已删 (D1), 严禁恢复 — 三处 (Internal.h:79-82 / Frame.h:20-22 / Shared.c:515-519) 口径一致 ✅

3.2 GSDML 常量 0x8000/0x8001 — ✅ 内核域无 GSDML 常量; native 侧与 docs 规范一致

  • 内核驱动不含任何 GSDML 常量 (GSDML 属服务/写手域, 归 g1-gsdml-writer-hex 审计)。
  • native pnet_slot.h:76 "DAP 使用 0x8000/0x8001"、pnet_slot.h:150 "接口子模块 0x8000 + 端口 1 子模块 0x8001"、pnet_alarm.h:81/169 "0x8000 = 整子模块通道" — 与 docs\GSDML_TIA_导入合规报告.md (SubmoduleIdentNumber 0x00008000/0x00008001, SubslotNumber 十进制 32768/32769) 及 PROFINET 标准一致 ✅。
  • 交叉注意 (域外, 转 g1 agent): GSDML_TIA_导入合规报告.md:21/90 已裁定 writer 注释"十进制会被 TIA 拒绝"为错误注释, writer 输出 hex 合法但违背项目十进制口径 — 该问题属 GSDML writer 域, 驱动层不涉及。

4. 生命周期 (审计清单 4)

4.1 DriverEntry / Unload 清理对称性 — ✅ 对称且全有界

环节证据判定
初始化顺序CyclicInitialize → SharedAcquire → NicInitialize → 符号链接 → dispatch 表 → AcceptingIrps=1 → DO_DEVICE_INITIALIZING 清除 (Entry.c:572-607)
失败回滚CyclicInitialize/SharedAcquire/NicInitialize/符号链接 各自失败即 DarraPnetUnload (内部幂等判 NULL)
NicInitialize 失败清理Tx 槽分配失败走完整 NicShutdown (协议 Deregister + NBL 池 + 半批槽回收), 防重载双注册 0x3B (Nic.c:700-708)
Unload 顺序AcceptingIrps=0 → Stopping=1 → 有界等句柄归零 (300×10ms) → ExWaitForRundownProtectionRelease → CyclicShutdown(5 次有界重试, 2026-08-13 由 100→5, 最坏 ~22s < SCM 30s) → NicDeselect → NicShutdown(Deregister 先行) → SharedRelease → LastCloseEvent 有界等 3s → 删符号链接 → IoDeleteDevice (Entry.c:431-524)
SharedRelease 逆序Unmap 系统 VA → UnlockPages → FreeMdl → Unmap 锚点视图 → ZwClose (Shared.c:225-250, 与 Acquire 严格逆序)

4.2 close-after-unload 挂起家族 (对照 2026-08-12 修法) — ✅ 全部落地

  • CLOSE 取 rundown 与 CREATE 对称 (Entry.c:76-78): 卸载后 CLOSE 返 FALSE → 吞掉成功返回, 不碰已释放扩展 ✅
  • LastCloseEvent: CREATE 成功 Reset (防历史置位假通过, Entry.c:69); 最后 CLOSE 置位 (Entry.c:83); Unload 有界 3s 等待 ✅
  • CLOSE 自愈复位 (Entry.c:96-122): Stopping==0 + PASSIVE + OpenCount==0 三重守卫 → ControlMutex 内 CyclicStop + NicDeselect + 状态/镜像回 STOPPED (含 Header.State 镜像, 2026-08-13 补) ✅
  • DPC 尾部重臂复查 Stopping+TimerActive (Timer.c:98-108): 停止路径定时器必灭, 无卸载后写已释放 KTIMER 窗口 ✅
  • 残余风险面检查: 首道句柄门 (OpenCount>0 → 不卸载返回) + AcceptingIrps=0 阻止新 CREATE → 第二道 OpenCount/LastCloseEvent 检查实际不可达 (纯防御, 无害)。未发现新挂起隐患

4.3 服务侧生命周期配合 (交叉核对, 域外仅报告)

  • [P2] PnetDriverBridge.cs:1085-1089 StopDriver 注释仍写 "驱动状态门: 仅 RUNNING/SAFE 放行 STOP, 否则 err=22" — 与 Entry.c 2026-08-12 驱动修复3 (STOP 幂等化: 任意非 STOPPED 态都执行 CyclicStop) 已不符。当前桥的"状态感知跳过"功能上无害 (CLOSE 自愈兜底), 但注释误导后续维护。

5. 日志 / 陈旧命名 (审计清单 5)

5.1 DbgPrint 串 — ✅ 无旧名残留

全仓 grep darrartpnet / 小写旧名: 仅剩历史注释引用 (INF:24/38 说明旧误改根因, 属合理保留)。全部 DbgPrint 前缀 DarraRT_Pnet: (Entry.c:428 / Nic.c:687,753,768,825 / Timer.c:212) 与设备名一致 ✅。注册名真值已落 strings 可验 (Nic.c:687, roundPNETCOMPAT2) ✅。

5.2 [P2] 陈旧命名注释残留 (3 处)

  1. DarraRT_Pnet_Nic.c:4 文件头 "注册 NDIS 6.30 协议" — 实际 6.0 (Nic.c:668, 2026-08-13 改注)。陈旧。
  2. DarraRT_Pnet_Nic.c:649:705 双注册防重注释引用同名协议 "DarraRT_Pnet" (带下划线) — 实际注册名 DarraRTPnet。语义仍对 (双注册=蓝屏), 引号内名称陈旧。
  3. Darra_Pnet_Kernel\Windows\Pnet\DarraRT_Pnet_Instance.h / DarraRT_Pnet_Log.h 未引用任何陈旧名 (见 §6 死代码)。

5.3 [P2] 诊断环事件编码与头文件注释不符 (1168 排障依据失真)

DarraRT_Pnet_Diagnostics.h:19-20 注释: BIND_CALLBACK "arg0 = (adapter 索引<<24)|(MAC 前 4 字节), arg1 = (MAC 后 2 字节<<16)|(0=进入/1=成功/2=拒绝), NameHash = FNV-1a"。 实际 Nic.c 编码:

  • 回调进入 (Nic.c:102-103): arg0 = FNV-1a 名 hash, arg1 = MAC 前 4 字节
  • 绑卡成功 (Nic.c:171-173): arg0 = (槽位索引<<24)|MAC 前 4 字节, arg1 = 0x00010000
  • open 超时 (Nic.c:156-157): arg0=0, arg1=0x00020000

头文件描述的混合编码与实现已漂移。服务桥 (PnetDriverBridge.cs:813-821) 只按 ev/arg0/arg1 十六进制原样打印, 不依赖注释; 但人工排障 (1168 场景) 按注释解读会误判。建议: 更正 Diagnostics.h 注释为上述实际编码, 或统一编码后改服务解读。


6. 死代码 / 孤儿 (审计清单 6)

位置判定
Log.h 全文件零接线DarraRT_Pnet_Log.h:12-25 PNET_LOG_TAG/ERROR/WARN/INFO 定义后无任何 .c include (grep #include "DarraRT_Pnet_Log.h" = 0), 全仓 DbgPrint 直接裸调[P2] 删除或接线 (对齐"Facade 不退场"原则)
Instance.h 全文件零接线DarraRT_Pnet_Instance.h 仅 vcxproj 列出, 无 .c include (g_Pnet extern 已在 Internal.h:532)[P2] 删除或并入 Internal.h
事件码 0x0002-0x0005 定义后从未落环Diagnostics.h:13-16 WATCHDOG_TRIP / LINK_DOWN / BIND_OK / UNBIND 全仓 grep 仅定义处命中。实际: 看门狗跳变只增 WatchdogTrips 计数不落环; 链路 Down 走 ForceSafe 无事件; 绑定成功/解绑已用 BIND_CALLBACK 编码替代[P2] 补齐落环 (诊断闭环) 或删定义
CONTROL_IOCR 运行态分支 = 文档化死代码Entry.c:304-311 门限仅 CONFIGURED 态; Iocr.c:800-816 的 RUNNING/SAFE (de)activate 处理经本 IOCTL 不可达。有意的保守设计 (运行态热改 IOCR 契约待服务侧会话流程定义), 注释已如实标注记录 (非 bug, 未来契约)
OutputDirty 令牌语义未生效Shared.h:94 / 服务 WriteOutputArea 置位请求发送; 驱动 DarraPnetSendPpm (Iocr.c:264-312) 每到期周期无条件读发, SharedReadPpm 读后清零 — "置 1 请求"实为"每周期发送+读后清 0"[P2] 文档语义与实现不符: 要么按令牌门控发送, 要么把契约改为"服务写后驱动下周期必发"并改注释
native os_sem_wait FIXMEpnal_port.c:299 "超时未递减, 保留上游行为 (FIXME 已注明未递减)"[P2] 上游行为保持可接受, 但 FIXME 应升级为明确注释或修正
ControlSend 槽 InFlight 置位竞态Iocr.c:616 InterlockedCompareExchange(&slot->InFlight, -1, 0) == 0 — 将 0(可用)→-1(空闲?) 置位后发; 但 TX 槽约定 "-1=空闲, 0=可用, 1=在途" (Internal.h:384): 置 -1 而非 1, NicSend 内 previous != -1 && CAS(1,0)!=0 可放行 (把 -1 视同空闲) — 语义靠 NicSend 的双段判定兜底, 脆弱但当前正确[P2] 统一 InFlight 置位语义 (直置 1 或加注释), 防未来改动踩雷

7. 附: 域外交叉发现 (供主线程编排, 非驱动层问题)

  1. GSDML writer 错误注释 (g1-gsdml-writer-hex 域): GSDML_TIA_导入合规报告.md:21/90 已裁定 — writer 内四处注释声称"十进制会被 TIA 拒绝"与事实相反; hex 输出合法但违背项目十进制口径。
  2. 服务桥注释陈旧 (ag19-service-rebuild 域): PnetDriverBridge.cs:126 "必须 = 1 (INF 同样含 RequireExclusiveBinding=1)" 与 :1085-1089 STOP 状态门注释均已过时 (见 §2/§4.3)。
  3. TEST_Driver README 陈旧 (ag17-pnet-tests-fix 域): 测试项目\TEST_Driver\README.md IOCTL 速查表 BIND_ADAPTER 行仍注 RequireExclusiveBinding=1
  4. INF LowerRange 统一 (§1.3) 需与 ag15-dev-pnet-test (测试机验证) 串行协作。

8. 审计守则自检

  • ✅ 0 代码文件 Edit/Write; 仅新建本 md
  • ✅ 0 git 操作
  • ✅ 全部结论附 文件:行 证据
  • ✅ P0/P1/P2 分级明确; P1 仅 1 项且给出具体修法与验证门