全栈审计 · 驱动层 (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 必修 | 1 | INF Ndi\Interfaces LowerRange 口径与 ETH roundRANGE4 实测终态矛盾 (详见 §1.3) |
| P2 建议 | 13 | 陈旧注释/死代码/契约文档漂移为主, 均不影响当前运行正确性 |
Top 问题清单:
- [P1] Pnet INF
LowerRange="ndis5,ndis4,ndis5_prot"vs ETH roundRANGE4 实测终态LowerRange=ndis5— 两侧注释互斥, 一侧必错 (证据:DarraRT_Pnet.inf:51vsDarraRT_Eth.inf:24-29) - [P2] 诊断环 BIND_CALLBACK 事件参数编码与 Diagnostics.h 注释不符 (1168 排障依据失真)
- [P2]
RequireExclusiveBinding已删/已失效, 但 INF/install-pnet.ps1/服务桥/TEST_Driver 四处注释仍称"必须=1" - [P2] Log.h/Instance.h 两个头文件零接线; 事件码 0x0002-0x0005 定义后从未落环
- [P2] Nic.c 文件头 "NDIS 6.30" 与双注册防重注释中 "DarraRT_Pnet" 均为陈旧命名残留
1. 命名 / 绑定口径 (审计清单 1)
1.1 协议注册名 = BindForm DarraRTPnet — ✅ 一致 (roundPNETCOMPAT2 已落地)
| 位置 | 值 | 判定 |
|---|---|---|
DarraRT_Pnet_Internal.h:62 DARRT_PNET_NDIS_PROTOCOL_NAME | L"DarraRTPnet" (BindForm 去下划线) | ✅ |
DarraRT_Pnet_Nic.c:644 NdisRegisterProtocolDriver 实际注册 | 用上述宏 | ✅ |
DarraRT_Pnet_Nic.c:687 DbgPrint | roundPNETCOMPAT2 protocol registered name=%wZ — strings 可验 | ✅ |
INF 组件 ID (netcfg -i DarraRT_Pnet) | DarraRT_Pnet (带下划线, 组件 ID 本就该带) | ✅ |
INF AddService / Ndi\Service | DarraRT_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 IDdarrart_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-51HKR, 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-29roundRANGE4 (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-netpf_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-1089StopDriver 注释仍写 "驱动状态门: 仅 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 处)
DarraRT_Pnet_Nic.c:4文件头 "注册 NDIS 6.30 协议" — 实际 6.0 (Nic.c:668, 2026-08-13 改注)。陈旧。DarraRT_Pnet_Nic.c:649与:705双注册防重注释引用同名协议"DarraRT_Pnet"(带下划线) — 实际注册名DarraRTPnet。语义仍对 (双注册=蓝屏), 引号内名称陈旧。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 FIXME | pnal_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. 附: 域外交叉发现 (供主线程编排, 非驱动层问题)
- GSDML writer 错误注释 (g1-gsdml-writer-hex 域):
GSDML_TIA_导入合规报告.md:21/90已裁定 — writer 内四处注释声称"十进制会被 TIA 拒绝"与事实相反; hex 输出合法但违背项目十进制口径。 - 服务桥注释陈旧 (ag19-service-rebuild 域): PnetDriverBridge.cs:126 "必须 = 1 (INF 同样含 RequireExclusiveBinding=1)" 与 :1085-1089 STOP 状态门注释均已过时 (见 §2/§4.3)。
- TEST_Driver README 陈旧 (ag17-pnet-tests-fix 域):
测试项目\TEST_Driver\README.mdIOCTL 速查表 BIND_ADAPTER 行仍注RequireExclusiveBinding=1。 - INF LowerRange 统一 (§1.3) 需与 ag15-dev-pnet-test (测试机验证) 串行协作。
8. 审计守则自检
- ✅ 0 代码文件 Edit/Write; 仅新建本 md
- ✅ 0 git 操作
- ✅ 全部结论附 文件:行 证据
- ✅ P0/P1/P2 分级明确; P1 仅 1 项且给出具体修法与验证门