第二部分
第一章 NDIS NIC 小口驱动器
这一章介绍windows2000网络接口卡NIC小口驱动器。主要讨论下面课题:
NIC小口驱动器的种类,在1.1节中
网络接口卡的支持,在1.2节中
小口驱动器代码重要属性,在1.3节中
驱动器示例,在1.4节中
1.1 NIC小口驱动器的种类
NDIS支持下面几种类型的网络接口卡驱动器:
无连接小口驱动器,控制无连接网络媒体的NIC,如以太网,FDDI和令牌网。
无连接小口驱动inyibu划分有如下的子类型:
串行驱动,依赖于NDIS串行化调用它们的MiniportXxx函数和管理发送队列。
非串行化驱动,典型地运行在多处理器系统上来达到性能的提升,对其内部所有收到的发送包串行化操作它们自己的MiniportXxx函数和队列,而不是依赖于NDIS来执行这些函数,这就获得了更好的全双工性能,使驱动器临界代码(一个时刻只有单一线程可执行)更小。然而,非串行小口驱动需要满足更多的附加条件和设计要求,因此增加了排错与测试时间。
面向连接的小口驱动为面向连接的网络媒体控制NIC,如ATM。
面向连接的小口驱动总是非串行化的。也就是说,它们总是对其内部所有收到的发送包串行操作它们自己的MiniportXxx函数和队列。
NDIS库继续支持遗留的NDIS3.0 NIC驱动器。然而,只有NDIS4.0和NDIS5.0小口驱动可以获得当前NDIS库对NIC小口驱动所提供的增强功能和优点。对未来的NDIS库,也只有NDIS小口NIC能够获得这些优点。
1.2 所支持的网络接口卡
Windows2000支持下列类型的网络接口卡:
以太网卡(802.3)
令牌卡(802.5)
FDDI
LocalTalk
Raw ARCNET(一套封装下的ARCNET)
ARCNET878.2
WAN(点对点和WAN卡)
面向连接的WAN
无线网卡
ATM
IrDA
在NDIS调用NIC驱动器的MiniportInitialize函数时,它传送一个NDIS支持的媒体数组,如果这个NIC支持一个媒体类型,它接选择这个媒体类型,如果NIC驱动器支持多个类型,它就选择它最喜欢的媒体类型返回给NDIS。
在高层NDIS协议驱动器调用NdisOpenAdapter来绑定指定的NIC时,它提供一个在其上可以操作的媒体类型列表。NDIS利用这些来自NIC驱动的信息和来自协议驱动器的信息适当地绑定它们。这种绑定提供了数据包向下传送和发送到网络上的捷径。用此绑定,接受的数据包也被向上传送到高层驱动器。
对ARCNET,NDIS定义的媒体类型是NdisMediumArcnet878_2。这个定义对Raw ARCNET与Novell的ARCNET完全兼容。
RawARCNET格式,在ARCNET包头定义标准中(Novell出版的)也由NetWare所使用。支持这种格式的传输驱动器负责从三种不同的帧格式(短的,长的,其它的)中选择,这依赖于所要发送的数据长度。传输驱动器而后根据使用的标准执行必要的活动,包括分段,焊接和设置分割标志和顺序号。
NdisMediumArcnet878_2格式允许传输驱动器感知它正在运行于ARCNET之上,不必知道分段和组合的细节。使用NdisMediumArcnet878_2,在线的格式与RAW RACNET格式相同。然而,绝大多数帧格式的细节对传输驱动器是屏蔽的。NIC驱动器负责对帧进行分段,选择适当的帧格式,插入焊点,分割标志,顺序号和其它相关字段。NDIS库执行803.3到ARCNET的发送包封装和接收包的解封装。
Windows2000 TcpIp和NwLink传输驱动器也使用NdisMediumArcnet878_2。Windows2000的Nbf 传输(也称之为NetBEUI)不使用它。
NdisMediumAtmosphere格式允许NIC驱动器使用NDIS5.0本身对ATM的支持。
NdisMediumTrda格式允许NIC驱动器使用NDIS5.0本身对红外设备的支持。
NIC的种类
NdisXxx函数是小口驱动调用来初始化其适配器和发送接收包的函数,它们依赖于NIC的特征:
1、 总线仲裁的DMA NIC
这些NIC可以直接通过板级DMA访问主存储器,在网络和贮存之间管理数据传输,不需要使用Host CPU.
对于发送,小口驱动器设置NIC映射到输出缓冲。然后是设备从这个存储其启动传输。NIC的DMA控制器从共享的系统存储传输数据到网络,并在传输完成后中断CPU。对于接收DMA控制器传输输入数据到主存,然后用中断通知主机。
总线仲裁DMA NIC典型地有一个在板环形缓冲,小口驱动器映射这个缓冲到一个系统存储缓冲集。一般NIC可被编程同时有效地处理几个包。管理这样的NIC的小口驱动通常都支持多包发送和接收,因为NIC可以有效地处理几个包,故此改进了它的I/O吞吐量。
2、 非总线仲裁DMA NIC
这包括三种普通类型的NIC:
具有板上共享存储空间的NIC
这种管理NIC的小口驱动必须映射NIC的共享存储到主存中,并且然后把包拷贝出来到NIC存储或从NIC存储把包拷贝进由上层驱动器或其他驱动器提供的缓冲。这样的小口驱动一般并不能由于支持多包发送和接收来改进性能。
仆从DMA的NIC
管理这种NIC的小口驱动使用系统的DMA控制器来管理数据包在网络上的传输。数据传输要求主CPU协同操作。
使用编程I/O的NIC
这种管理一个PIO设备的小口驱动使用NDIS函数来逐个字节,逐个字或逐个长字地移动输出帧到设备寄存器,然后触发设备发送数据。这样的设备驱动器并不能从NDIS支持的多包发送和接收中获得好处。这种类型的小口驱动应该实现象在第四章描述的单包发送和接收。
1.3 小口驱动代码的重要特征
这一节介绍下面一些小口驱动代码的主要特征:
MiniportXxx函数
链接到NDIS库
小口驱动的适配器关联
VC关联(仅对面向连接的小口驱动)
网络OIDs
1.3.1 MiniportXxx 函数
典型的小口驱动器都使用少量的函数通过NDIS与上层和硬件通讯。全部上端函数(MiniportXxx),NDIS可能称为与小口驱动通讯的函数,无论是关乎于它自己的还是关乎于协议驱动器的,都在2.2.1和2.2.2节中描述;并不是所有这些函数都需要。3.1.2.2节中描述了那些函数是可选的,并且说明为什么。
NDIS NIC小口驱动和上层驱动器使用NDIS库(ndis.sys)通过调用NdisXxx函数来互相通讯。一个关于小口驱动可以调用的NdisXxx函数和宏的简要介绍在2.3节中给出。
很多小口驱动函数ikeyizai同步下操作也可以在异步下操作。异步函数都有一个操作完成时必须调用的函数NdisXxx---Complete。例如,如果协议驱动器调用NdisReset来重置NIC,小口的MiniportReset函数可以通过返回一个NDIS_STATUS_PENDING使操作处于未决状态。最后,MiniportReset函数必须调用NdisMResetComplete来表达重置请求的最终状态。关于异步MiniportXxx和对应的完成函数的更多信息请参见第二章和网络驱动器参考等资料。
1.3.2 NDIS库的连接
NDIS库包装于ndis.sys中,是和模式下作为一个函数集输出的库,重点是其中的宏,提供了程序性能的最大化。(一个具有.sys形式的输出库,其函数类似于动态链接库)这些NDIS库函数在网络驱动器参考中给出描述。无论是协议驱动还是NIC驱动,包括WAN NIC驱动,都与NDIS库紧密相关。
Windows2000DDK提供ndis.h作为小口驱动主要的头文件。这个文件定义了小口驱动的入口点,NDIS库函数,和通用的数据结构。网络参考中描述了小口驱动,协议驱动,和NdisXxx函数,以及通用数据结构和OID。
1.3.3 小口适配器关联
NDIS使用一个称之为逻辑适配器的软件对象来表述系统中的每一个NIC。这个对象由NDIS来维护,并且对小口驱动和协议驱动是不透明的。NDIS传递一个指向这个结构的Handle到NIC驱动器的MiniportInitialize函数。小口驱动而后使用这个handle来调用所有NdisXxx函数,这些函数是由这个Handle指派给这个NIC的。
当一个小口驱动初始化他所管理的NIC时,它建立一个自己内部的数据结构来表示这个NIC。驱动器使用这个结构,并称之为小口驱动的适配器关联,为了维护设备指定的状态信息,它需要管理这个NIC。驱动器在其MiniportInitialize函数调用NdisMSetAttributes或NdisMSetAttributesEx时,传递一个这个结构的Handle到NDIS。当NDIS调用属于这个NIC的小口驱动的MiniportXxx函数时,传递这个Handle以利于驱动器识别正确的NIC。这个小口适配器关联有这个小口驱动所拥有,且有这个小口驱动所维护,对NDIS和协议驱动是透明的。
1.3.4 VC关联
在产生一个呼叫之前,面向连接的客户端请求面向连接的小口驱动建立一个虚拟连接(VC)使得在其上可以收发数据包。类似的,在表述一个接收呼叫到面向连接的客户端之前,呼叫管理或集成的小口呼叫管理(MCM)请求小口驱动为这个接到的呼叫建立一个VC。虚拟连接是在两个面向连接的实体之间建立的逻辑连接。面向连接的发送和接收总是发生在特定的VC上。
面向连接的小口驱动在小口驱动分配的关联区域维护相关VC的状态信息。每一个VC关联都由小口驱动维护,并且是NDIS和协议驱动透明的。在它的MiniportCoCreateVc函数中,面向连接的小口驱动传递这个VC关联区域的Handle到NDIS,而NDIS传递一个NdisVcHandle返回给小口驱动,面向连接的客户端,呼叫管理器或集成的小口呼叫管理器(MCM)来唯一地标识这个VC。
在VC上可以发送和接收数据之前,他必须被激活。呼叫管理器通过调用Ndis(M)CmActivateVC来初始激活这个VC,并传包含有被激活VC属性的递调用参数。在响应这个调用中,NDIS调用小口驱动的MiniportCoActivateVC函数,它激活这个VC。
在一个呼叫完成后或VC不在需要时,呼叫管理可以通过调用Ndis(M)CmDeactivateVC来灭活这个VC,这就触发NDIS调用小口驱动的MiniportCODeactivateVc函数。面向连接的客户端或呼叫管理器都可以通过调用NdisCoDeleteVc发起删除VC的操作,这也触发NDIS调用小口驱动的MinportCoDeleteVc函数。
关于小口驱动在VC上的操作,更多信息请参看小口驱动设计导引的第一部分。
1.3.5 网络OIDs
小口驱动维护其能力和当前状态信息,以及它控制的每个NIC的信息。每一种类型的信息都通过对象标示符(OID)加以识别。OIDs是系统定义的。
NDIS和高层驱动可以查询这些信息,有时也可以设置使用OID的信息。
对无连接媒体的高层驱动调用NdisRequest查询或设置无连接小口驱动的信息。对于执行查询操作,NDIS调用小口驱动的MiniportQueryInformation函数。对于执行设置操作,NDIS调用小口驱动的MiniportSetInformation函数。
对于面向连接的媒体,高层驱动调用NdisCoRequest查询或设置面向连金额小口驱动的信息。在执行查询和设置操作中,NDIS调用小口驱动的MiniportCoRequest函数。
NDIS为小口驱动映射许多系统定义的OIDs到全球一致的标识符(GUIDs)。NDIS以内核模式Windows管理形式(WMI)注册这些GUIDs,它也支持Web上企业管理(WBEM)的用户模式应用。当WMI客户查询或设置这些GUIDs时,NDIS传送这种请求到查询OID操作或设置OID操作,然后传递适当的返回状态和信息到WMI。驱动器作者可以映射客户GUIDs到客户OIDs或小口驱动状态。小口驱动在使用NDIS初始化期间必须注册客户GUID到OID或GUID到状态的映射。
更多关于查询和设置OIDs,建立OIDs,以及NDIS对WMI支持信息,请参见第五章。对于系统定义的OIDs描述,参见网络驱动器参考。
1.4 驱动器示例
DDK包含小口驱动的示例代码,它们管理几种类型的网卡。这些示例驱动程序可以按开发者的需要进行剪裁。示例中含有可以适合于新的类似驱动程序的函数。驱动程序开发者总要写一些硬件相关的函数。然而,有很多函数都是相当标准的。例如,与NDIS库而不是网卡通讯的函数一般是标准的。对于这些驱动器函数,示例驱动器中的代码或许是有用的,或只需少量的修改。