NDIS 示例 - Realtek 8168/8169/8111/8110 的 6.0 小驱动程序






4.26/5 (11投票s)
Realtek 8168/8169/8111/8110 系列千兆以太网控制器的 NDIS 6.0 小驱动程序
- 下载 lso-jumbo.support-added.zip - 91.9 KB
- 下载 release.zip - 342.4 KB
- 下载 pm-support-added.zip - 91.7 KB
引言
对于那些渴望为新的或现有的以太网控制器编写 NDIS 6.0 小 Windows(桌面 PF)设备驱动程序的人来说,唯一可用的示例源代码是 Microsoft DDK 中的 E100BEX。网上还有其他几种 NDIS 驱动程序,如 IM,但据我所知,没有用于网卡的小驱动程序。
E100BEX 示例,下文简称 e100,是针对 Intel 的 EtherExpress 100Mbps 网卡系列。因此,如果一个人想通过实时调试来理解这个 e100,除了静态代码分析之外,他/她必须拥有这种类型的卡,而如今 IMO 这种卡很少见了。
所以,我想,为什么不为如今很容易找到的另一种流行的以太网控制器编写一个 NDIS 6 驱动程序呢?我选择了 Realtek 的 8111/8168/8169/8110 系列千兆以太网控制器,这些控制器可以作为廉价的 PCI 卡(约 9 美元,品牌如 Hawkings、Startech)以及许多现代主板上的 LOM(板载网卡)。
背景
我采取的方法是——与其从头开始,不如将 Microsoft DDK 示例 e100 从 Intel 移植到 Realtek 硬件。
好处是——经过充分测试的 e100 核心和 NDIS 相关逻辑、各种状态机、各种同步机制都得以保留,只更改了硬件部分。
好吧,说起来容易做起来难。一方面,尽管 e100 设计/编写得很好,但我总觉得 NDIS 代码似乎与硬件相关的代码紧密耦合。从性能角度来看是可以理解的。另一方面,Intel 硬件和驱动程序设计主要基于主机和设备之间共享的链表数据结构,而 Realtek 硬件似乎是面向数组的。因此,挑战在于将为链表设计的 e100 适配到面向数组的结构,而不改变原始代码的任何逻辑流程。
关于示例
关于驱动程序
以 DDK build 6001 的 e100 示例作为基线。后来从 Windows 2008 Server DDK 的 e100 示例中提取了一些部分并合并,以修复 SEND 问题。稍后将对此进行更多说明。
代码工作原理
我希望原始 e100 中充足的注释和我的补充注释应该足以解释这些内容。只要我还有时间,我将继续向这一部分添加更多内容。
原始的 e100bex.htm 可能是起点
编译说明
* 使用了 DDK build 6000。直接的命令行“build -cZ”即可。无需批处理文件。
安装说明
使用提供的 RLTK1GIG.INF 文件,标准的未签名驱动程序安装方式。
对于新手——进入设备管理器,选择 Realtek 网卡设备,右键选择“更新驱动程序”。一直手动操作到底,切勿让安装向导控制进程。
测试结果
- 驱动程序在 VISTA32 免费版下,在重度网络负载/压力条件下进行了测试。在数小时的连续运行中没有出现崩溃,表现良好。我希望能够使用更复杂的测试工具在通信频繁的网络环境中进行更严格的测试,但由于我没有这些工具,希望以后有人能向本论坛提供此类测试结果。我也希望能够使用 Microsoft WLK(旧称 HCT)中的“NDISTEST”,但不幸的是,正如许多人所知,DTM 控制器只能在 Server 2003 上运行。微软为何这样做,实际上疏远了小型/个人/非企业设备驱动程序开发人员,这一点不得而知。
- 我测试了 Realtek 千兆以太网控制器系列中的 2 种流行型号。一种是 Hawkings PCI 卡,配备 Realtek 8169S;另一种是 GIGABYTE-G33 主板,其 LOM 为 Realtek 8111b。成功。迄今为止没有已知问题。
注意——我同时测试了 100M 和 1G 连接。
免责声明
显然,这不能用于生产环境。仅供参考和学习之用。作者不对任何人使用此代码产生的任何后果负责。
未来和计划的功能添加
- VLAN
已知问题
目前还没有。
杂项说明
- 64位准备——此代码可以编译为 64 位,尽管我尚未在 VISTA64 上进行测试。我将在进行测试后向您报告结果。
更新:64 位驱动程序在 vista64 上运行正常。但是,将来我必须修改此 INF 文件,以支持 32 位和 64 位 PF。因此,目前在安装之前,请用 64 位 rltkgbit.sys 替换 32 位 rltkgbit.sys,并使用相同的 INF 文件。
- 用于创建此驱动程序的 Realtek 硬件数据手册可以在互联网上找到。也可以通过简单的电子邮件从 Realtek 获取。我从 Realtek 获取了一份,消息很简单:“……你不应该透露给他人……”没有复杂的 NDA,只是简单地向他们保证,未经许可,你不会公开发布。
否则,此处提供的 Realtek 8139 数据手册
http://www.datasheet4u.com/html/R/T/L/RTL8139DL_RealtekMicroelectronics.pdf.html 在理解此示例方面非常接近,至少在发送/接收操作方面。
更新
对于所有这些新更新,我切换到了最新的 W2008Server 6001.18000 DDK。
添加了大发送卸载 (LSO) 支持
LSO,也称为任务发送卸载 (TSO)。所有相关代码都可以在条件编译 **指令 #if OFFLOAD** 下找到。
所需步骤
第 1 步。
NdisMSetMiniportAttributes(.,.,.) 必须通过初始化 NDIS_TCP_LARGE_SEND_OFFLOAD_V1 结构来完成。这在 MPInitialize (.,.,.) 中通过 InitLSO (Adapter) 完成;
/*** Initialize NDIS_OFFLOAD ****/
NdisZeroMemory( NdisOffload,
sizeof(NDIS_OFFLOAD));
NdisOffload->Header.Type = NDIS_OBJECT_TYPE_OFFLOAD ;
NdisOffload->Header.Revision = NDIS_OFFLOAD_REVISION_1 ;
NdisOffload->Header.Size = sizeof(NDIS_OFFLOAD);
//
// Initialize the NDIS_TCP_LARGE_SEND_OFFLOAD_V1 structure
// embedded in NDIS_OFFLOAD
//
LsoV1->IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3 ;
LsoV1->IPv4.MaxOffLoadSize = MP_MAX_TCP_OFFLOAD_SIZE ;
LsoV1->IPv4.MinSegmentCount = TCP_OFFLOAD_MIN_SEGMENTS ;
LsoV1->IPv4.TcpOptions = NDIS_OFFLOAD_SUPPORTED ;
LsoV1->IPv4.IpOptions = NDIS_OFFLOAD_SUPPORTED ;
//
/*** Initialize NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES ****/
//
NdisZeroMemory (
&OffloadAttributes,
sizeof(NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES)
);
OffloadAttributes.Header.Type =
NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES ;
OffloadAttributes.Header.Revision =
NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1 ;
OffloadAttributes.Header.Size =
NDIS_SIZEOF_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1 ;
OffloadAttributes.HardwareOffloadCapabilities =
OffloadAttributes.DefaultOffloadConfiguration = NdisOffload ;
status = NdisMSetMiniportAttributes( Adapter->AdapterHandle,
(PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&OffloadAttributes);
第 2 步。
支持 OID_OFFLOAD_ENCAPSULATION
* 如果我们不返回 NDIS_STATUS_SUCCESS,我们就不会从 NDIS 收到任何用于 LSO 的大包。
这是代码
#if OFFLOAD
case OID_OFFLOAD_ENCAPSULATION :
{
PNDIS_OFFLOAD_ENCAPSULATION Encap ;
//
// Verify the length
//
if (InformationBufferLength < sizeof(NDIS_OFFLOAD_ENCAPSULATION) )
{
return(NDIS_STATUS_INVALID_LENGTH);
}
Encap = (PNDIS_OFFLOAD_ENCAPSULATION)InformationBuffer ;
Adapter->NdisOffloadEncapSulation = Encap->IPv4.Enabled ;
if ( NDIS_OFFLOAD_SET_ON == Encap->IPv4.Enabled )
Encap->IPv4.EncapsulationType = NDIS_ENCAPSULATION_IEEE_802_3 ;
Status = NDIS_STATUS_SUCCESS ;
BytesRead = InformationBufferLength;
break ;
}
#endif
#if OFFLOAD
步骤 3。
当 NDIS 调用 MPSendNetBufferLists (.,.,..) 发送 NBL 时,使用 NBL 中的 SCRATCH 区域来存储有关 LSO 的一些上下文信息。
这是代码
// and initialize some LSO related fields there
MoveLSOinfoFromNBLtoContext ( Adapter, CurrNetBufferList )
此函数从 NBL 中检索 2 个主要项:MSS 和 TcpHeaderOffset,并将它们保存在私有上下文区域 (NBL->SCRATCH) 中。
步骤 4
NDIS 6.0 小驱动程序在完成(发送)NBL 时应该返回“TcpPayLoad”。但由于 rtl8169 硬件不返回此值(AFAIK),我们必须在将其发送到硬件之前,从 NBL (NB) 数据中找出它。我们的做法是:
NBL->TcpPayLoad = TotalBytesInNBL - NBL->TcpHeaderOffset + TcpHeaderLength;
这是代码
#if OFFLOAD PeekTcpHeader ( pMpTcb->NetBufferList, pMpTcb->NetBuffer ) ; #endif
步骤 5
通过在 Realtek 8169 硬件发送缓冲区描述符中设置 MSS 值和 LGSEN 位来编程硬件。
#if OFFLOAD if ( bLSOenabled ) { pHwTbd->status |= (LGSENbit | pNBLcontext->MSS) ; } #endif
步骤 6
在发送完成中断处理程序中,为上层消费设置已完成 NBL 中的“TcpPayLoad”。
#if OFFLOAD UPDATE_LSO_TCP_PAYLOAD ( NetBufferList ) ; #endif
添加了巨型帧支持
没什么了不起的,就是这样。发送/接收硬件没有任何变化。
#if JUMBO_FRAME_SUPPORT #define NIC_MAX_RECV_FRAME_SIZE 6464 #else #define NIC_MAX_RECV_FRAME_SIZE 1664 #endif #if OFFLOAD || JUMBO_FRAME_SUPPORT #define NIC_MAX_XMIT_FRAME_SIZE 7040 // multiple 0f 64 #else #define NIC_MAX_XMIT_FRAME_SIZE 1664 #endif
添加了电源管理功能
在 D0 和 D3 过渡时没有对硬件进行任何操作。我们只是向 NDIS 指示我们有能力。
pPower_Management_Capabilities->Flags = NDIS_DEVICE_WAKE_UP_ENABLE ; pPower_Management_Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateD3; pPower_Management_Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; pPower_Management_Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified ; *pulInfoLen = sizeof (*pPower_Management_Capabilities); *pStatus = NDIS_STATUS_SUCCESS; }
测试:Magic Packet WOL 在此代码下工作正常。
关于版权
- 虽然本程序是 copyLEFT 且可免费在任何地方使用,但我保留了原始源代码中发现的 INTEL 和 MICROSOFT 的版权声明。无论如何,由于 e100 是 DDK 示例的一部分,可供公众使用,版权可能不那么严格。有关版权问题,请参考原始 e100bex DDK 示例代码。我概不负责。
- 感谢 Linux 开发者社区,我从 Realtek Linux 驱动程序借用了最初的芯片 MAC/PHY 配置代码,并为了公平地表彰他们,我将这些文件命名为 linux_init.c 和 linux_h.h。我不确定 GNU 许可将如何影响这个我本意为 FREE 的项目。
最后
欢迎在本论坛或发送至 alex_@esdsinc.com 的任何形式的评论和建议。
删除下划线。
祝您好运!
历史
- 首次发布日期:2008 年 3 月 14 日。版本 6.0.6000.31308
- 第二次发布日期:2008 年 5 月 1 日。版本 6.0.6000.050108。添加了 LSO 和巨型帧支持。
- 第三次发布日期:2008 年 5 月 2 日。版本 6.0.6000.050208。添加了电源管理功能。