将 NDIS 微型端口驱动程序移植到 NetAdapterCx
本页介绍如何将 NDIS 6.x 微型端口驱动程序转换为 NetAdapterCx 客户端驱动程序。
有关 WDF 的一般信息,请查看 WDF 驱动程序开发指南。
编译设置
在 Visual Studio 中打开现有的 NDIS 微型端口驱动程序项目,并使用以下步骤将其转换为 KMDF 项目。
首先,导航到配置属性驱动程序>设置驱动程序>模型并验证驱动程序类型是否设置为 KMDF,并且 KMDF 版本主要版本和 KMDF 版本次要版本均为空。
在项目属性中,打开 Driver 设置->Network Adapter Driver,并将“链接到网络适配器类扩展”设置为“是”。
- 如果转换后的驱动程序仍会调用 NDIS API,请继续链接到
ndis.lib
该 API。
- 如果转换后的驱动程序仍会调用 NDIS API,请继续链接到
删除 NDIS 预处理器宏,例如
NDIS650_MINIPORT=1
。将以下标头添加到每个源文件(或通用/预编译标头):
#include <ntddk.h> #include <wdf.h> #include <netadaptercx.h>
将 标准 WDF 修饰 添加到 INF:
[Yourdriver.Wdf] KmdfService = Yourdriverservice, Yourdriver.wdfsect [Yourdriver.wdfsect] KmdfLibraryVersion = <insert here>
将新的所需网络关键字 (keyword)添加到 INF 的 NT 部分:
*If连接orPresent
*连接ionType
*DirectionType
*AccessType
*HardwareLoopback
有关这些关键字 (keyword)和示例的详细信息,请参阅 NetAdapterCx 客户端驱动程序的 INF 文件。
驱动程序初始化
从 DriverEntry 中删除对 NdisMRegisterMiniportDriver 的调用,并添加以下内容:
WDF_DRIVER_CONFIG_INIT(&config, EvtDriverDeviceAdd);
status = WdfDriverCreate(. . . );
if (!NT_SUCCESS(status)) {
return status;
}
如果已设置,请从调用 WdfDriverCreate 中删除 WdfDriverInitNoDispatchOverride 标志。
DriverUnload 是 WDF 网络客户端驱动程序的可选例程,因此可以根据需要将其删除。 请勿从 DriverUnload 调用 NdisMDeregisterMiniportDriver。
设备初始化
接下来,将代码从 MiniportInitializeEx 分发到相应的 WDF 事件回调处理程序中,其中几个是可选的。 有关回调序列的详细信息,请参阅 网络适配器 WDF 客户端驱动程序的 Power-Up 序列。
在启动 net 适配器时,将调用等效于 NdisMSetMiniportAttributes 的方法,但在调用 NetAdapterStart 之前。 但是,客户端驱动程序调用不同函数来设置不同类型的功能,而不是使用泛型 NDIS_MINIPORT_ADAPTER_ATTRIBUTES 结构调用一个例程。
有关需要提供的回调以及何时启动 net adapter 的信息,请参阅 设备和适配器初始化。
从注册表读取配置
接下来,将对 NdisOpenConfigurationEx 和相关函数的调用替换为 NetConfiguration*
方法。 这些 NetConfiguration*
方法与 Ndis*Configuration*
函数类似,无需重构代码。
有关详细信息,请参阅 访问配置信息。
从用户模式接收 I/O 控制代码(IOCTL)
如果 NDIS 驱动程序调用 NdisRegisterDeviceEx(一个用于创建控制设备对象(CDO)的例程来从用户模式接收 IOCTL,请阅读此部分。
下面是在 WDF 网络客户端驱动程序中执行此操作的两种方法。
最简单的端口是通过从客户端的EVT_WDF_DRIVER_DEVICE_ADD回调调用 WdfControlDeviceInitAllocate 来创建控制设备对象。 有关详细信息,请参阅 “使用控制设备对象”。
但是,建议的解决方案是创建设备接口,如使用设备接口中所述。
完成设备初始化
此时 ,在EVT_WDF_DRIVER_DEVICE_ADD中,可以执行任何要初始化设备的其他操作,例如分配中断。
处理电源状态更改通知
WDF 客户端驱动程序不会收到电源状态更改OID_PNP_标准版T_POWER。
相反,WDF 客户端会注册可选的回调函数来接收电源状态更改通知。 有关概述,请参阅 函数驱动程序中的支持 PnP 和电源管理。
通常,OID_PNP_标准版T_POWER处理程序中的代码将移动到EVT_WDF_DEVICE_D0_EXIT和EVT_WDF_DEVICE_D0_ENTRY。
由于 WDF 电源状态机略有不同,因此可能需要对代码进行轻微修改。
具体而言,在 MiniportInitializeEx 回调函数中,NDIS 微型端口驱动程序执行一次性初始化任务,以及将设备引入 D0 状态的工作。 然后,它会重复工作以转到其OID_PNP_标准版T_POWER处理程序中的 D0。
相比之下,WDF 客户端在EVT_WDF_DEVICE_D0_ENTRY之前在事件回调中执行一次性初始化任务,在此期间设备处于低功率状态。 然后,它会在EVT_WDF_DEVICE_D0_ENTRY中执行 D0 的工作。
总之,在 WDF 中,你将“转到 D0”代码放在一个位置而不是两个位置。
有关回调序列的详细信息,请参阅 NetAdapterCx 客户端驱动程序的 Power-Up 序列。
查询和设置电源管理功能
同样,WDF 客户端驱动程序不会收到 OID_PM_PARAMETERS 来查询或设置网络适配器的电源管理硬件功能。
相反,驱动程序会从 NETPOWER标准版TTINGS 对象查询必要的 LAN 唤醒(WoL)配置。 有关详细信息,请参阅 配置电源管理。
返回的实际标志具有与 NDIS 6 微型端口相同的语义,因此无需对逻辑进行深入更改。 主要区别在于,现在可以在关闭电源顺序期间查询这些标志。 请参阅 NetAdapterCx 客户端驱动程序的关闭顺序。
移动此代码后,可以删除用于OID_PNP_标准版T_POWER和OID_PM_PARAMETERS的 OID 处理程序。
由于 NetAdapter 框架在主机使用网络接口时将设备保持在 D0,因此客户端通常不实现电源逻辑;默认的 NetAdapter 电源行为已足够。
数据路径
数据路径编程模型发生了显著变化。 下面是一些主要差异:
- 在 NetAdapter 模型中,网络流量不再是每个适配器,就像在 NDIS 中一样,而是每个 WDF 队列。 请参阅 创建 I/O 队列。
- NetAdapterCx 不NET_BUFFER_LIST和NET_BUFFER池,而是引入了由网络数据包组成的环形缓冲区,该缓冲区映射到 NDIS,如下所示:
- NET_PACKET类似于NET_BUFFER_LIST + NET_BUFFER。
- NET_PACKET_FRAGMENT类似于内存描述符列表(MDL)。 每个 NET_PACKET 都有一个或多个。
- 有关替换结构以及如何使用这些结构的详细信息,请参阅 数据包描述符和扩展。
- 在 NDIS 6.x 中,微型端口需要处理启动和暂停语义。 在 NetAdapterCx 模型中,情况不再如此。
- EVT_RXQUEUE_ADVANCE回调类似于 NDIS 6.x 中的MINIPORT_RETURN_NET_BUFFER_LISTS。
- EVT_TXQUEUE_ADVANCE回调类似于 NDIS 6.x 中的MINIPORT_标准版ND_NET_BUFFER_LISTS。
删除设备
WDF NIC 驱动程序的设备删除与任何其他 WDF 设备驱动程序中的设备删除相同,无需进行网络特定的处理。 网络数据路径首先关闭,后跟 WDF 设备。 有关 WDF 关闭的信息,请参阅 用户拔出设备。
MiniportHaltEx 处理程序很可能在EVT_WDF_DEVICE_D0_EXIT和EVT_WDF_DEVICE_RELEA标准版_HARDWARE之间分布。
WDF 客户端不需要删除 NetAdapter 或其创建的任何数据路径队列。 WDF 会自动删除这些对象。
可以删除 MiniportShutdownEx、MiniportResetEx 和 MiniportCheckForHangEx。 不再支持这些回调。
NDIS-WDF 函数等效项
大多数 NdisXxx
函数都可以替换为 WDF 等效项。 通常,你应该发现,从中 NDIS.SYS
导入的功能很少。
有关函数等效项的列表,请参阅 NDIS-WDF 函数等效项。
调试
!ndiskd.netadapter 调试器扩展显示的结果与 NDIS 6 驱动程序的 !ndiskd.miniport 显示的结果类似。
结束语
使用本主题中的步骤,应具有启动和停止设备的工作驱动程序。
注意:NetAdapterCx 当前不支持 iSCSI 启动。