RSS订阅 | 匿名投稿
您的位置:网站首页 > 蹭网器好用吗 > 正文

基于WDM-NDIS体系的USB蹭网器驱动程序设计

作者:网络经济城 来源: 日期:2012/11/19 18:59:36 人气: 标签:
 

  1 引言

  USB(Universal Serial Bus)即通用串行总线,正在成为各种新型设备的标准总线,USB的传输速度已由USB1.0的12Mbps提高到了USB2.0的480Mbps,同时USB设备具有即插即用的特点,所以它越来越受到业界的重视。

  基于PCI总线的蹭网器一般符合NDIS体系结构,在台式机上应用广泛。随着计算机的微型化发展,要求设备具即插即用的特点,这种传统PCI的蹭网器已不能适应新的需要,因此开发一种基于USB的蹭网器便有重大的意义。这种蹭网器驱动程序遵循NDIS_WDMW体系结构。它结合了NDIS(Network Driver Interface Specification)和WDM(Win32 Driver Model)两种体系结构的特点。本文将探讨NDIS_WDM驱动程序体系结构特点,及USB蹭网器驱动实现的有关问题。

  2 基于WDM-NDIS体系的USB蹭网器的设计原理

  2.1 系统结构

  NDIS体系结构独立于硬件,用户可以将不同的协议和不同的蹭网器绑定进而完成不同的功能。使网络协议更具有通用性[3]。

  NDIS支持三种类型的驱动程序,从下往上向看,他们分别是微端口驱动程序、中间层驱动程序和协议驱动程序。传统的PCI蹭网器驱动程序位于NDIS的第三层,属于微端口驱动程序(Miniport Driver) ,它有两个基本功能:

  管理一个网络接口卡NIC(Network Interface Card),包括通过NIC发送和接收数据。与高层驱动程序相接[1]。

  但是基于USB的蹭网器驱动程序和传统PCI蹭网器驱动最大的差别是NDIS下层的基础不同。PCI蹭网器驱动的下层是硬件抽象层HAL,USB蹭网器驱动的下层是USB设备栈。如图1所示:

  基于USB的蹭网器驱动向上要和NDIS体系结构交互,本身属于NDIS的一部分,也要完成微端口驱动程序的收发数据功能。但是它不通过HAL而通过符合WDM模型的USB类驱动程序的接口完成,为此,基于USB蹭网器驱动必须自己构造USB请求包URB(Usb Requet Block)请求下层USB设备栈完成数据收发功能。这种驱动程序和传统的NDIS的微端口驱动程序有异有同,和WDM下的USB栈中的客户驱动程序也有异同。

  2.2 收发数据过程

  每当NDIS上层协议或中间驱动请求发送数据时,NDIS_WDM微端口驱动程序的收发函数将被调用,因为它下层是USB设备栈,所以不能直接调用NDIS库里的中断或DMA操作硬件。而是重新在内核的不分页内存中重建一个请求包URB,把上层的请求包转化为URB, 下传给USB设备栈,然后把包标志为pending,等待下层USB设备完成相关的操作后返回,此时,NDIS_WDM驱动程序收到下层的结果后再把原来标志为Pending 的包重新处理,回收在内存中分配的URB空间[3]。返回上层程序。如图2所示:

  3 基于WDM-NDIS体系的USB蹭网器设计的实现

  3.1 蹭网器初始化过程

  NDIS_WDM驱动程序完成对驱动程序对象的注册后,系统探测到硬件设备后,将对蹭网器进行初始化。通常初始化主要完成蹭网器的注册及发送和接收资源的分配,NDIS_WDM还要探索USB设备及配置USB设备。

  3.1.1 注册自定义蹭网器对象

  由于NDIS_WDM Miniport Driver要将上层的协议驱动程序或是中间驱动程序的请求包转交给下层的USB设备栈完成,因此,在自定义的蹭网器对象中除了有通常蹭网器对象中的接收链表,发送链表,蹭网器地址信息,和状态统计信息外,还必须有如下关键结构:

  PIRP StatusIndicationIrpNDIS_WDM Miniport Driver在不分页内存中分配的URB请求包,表示当前驱动程序正要处理或正在处理的请求。

  DEVICE_OBJECT TargetDeviceObject表示在整个设备栈体系中NDIS_WDM Miniport 设备对象的下层第一个设备对象。当NDIS_WDM 驱动要要完成收发数据时,构造一个StatusIndicationIrp下传给它。

  除了这两个结构外,蹭网器对象还包括其他信息,具体如下:

  typedef struct _MP_ADAPTER

  {

  网址名称及地址信息

  发送队资源及操作信息

  接收队资源及操作信息

  PIRP StatusIndicationIrp

  DEVICE_OBJECT TargetDeviceObject

  蹭网器状态统计信息

  }

  通过StatusIndicationIrp TargetDeviceObject 这两个数据结构完成了NDIS和USB设备栈的连接。蹭网器可以通过StatusIndicationIrp保存当前处理的IRP(IO Request Packet),并且能跟踪IRP的去向。

  3.1.2 自定义请求转换函数

  正如图2所示,上层的驱动程序请求不能直接下传给下层USB设备栈,必须要把上层的NDIS请求转化为IRP请求,下去才能接收并处理。NDIS请求中包括如下信息:请求的操作类型,输入缓冲区,输出缓冲区,NDIS_WDM驱动程序必须把这些信息转化为IRP请求包发送到下层的USB设备栈中,并报告下下层设备的执行结果。据此自定义一个转换函数。

  NICMakeSynchronousIoctl

  (

  INPDEVICE_OBJECT TopOfDeviceStack,INPFILE_OBJECT FileObject,IN ULONG IoctlControlCode,INOUT PVOIDInputBuffer, INULONG InputBufferLength, IN OUT PVOID OutputBuffer,INULONG OutputBufferLength,OUT PULONG BytesReadOrWritten

   )

  其中,TopOfDeviceStack指明下层的第一个设备栈,BytesReadOrWritten 返回下层的执行结果。

  该函数的实现过程的关键例程如下:

  调用IoAllocateIrp在内核的不分页内存之中分配一个空白的IRP请求包。

  利用NICMakeSynchronousIoctl的参数对刚创建的IRP初始化

  设置完成例程IoSetCompletionRoutine,这个完成例程在下层设备完成IRP后捕捉它,以完成报告执行结果及回收IRP的工作。

  把初始化后的IRP下传到下层设备栈 IoCallDriver(TopOfDeviceStack, irp)

  等待下层设备栈完成,调用KeWaitForSingleObject函数,与下层设备栈同步。

  这个自定义函数很重要,上层的每个一个请求最终都会调用它来完成。

  3.1.3探索下层的设备栈接口

  NDIS_WDM微端口驱动程序必须要知道其下层的类驱动程序接口(USBI),才能确定IRP的去向,因此在初始化函数之中,必须找到下层的USB设备栈接口(USBDI)。为此调用一个关键的函数:

  NdisMGetDeviceProperty(

  MiniportAdapterHandle,&Adapter->Pdo,&Adapter->Fdo,

  &Adapter->NextDeviceObject, NULL,NULL

  );

  第三个参数Adapter->NextDeviceObject返回的就是下层的USB设备对象,用Adapter->TargetDeviceObject指向这个对象。作为以后IRP的去向。

  3.1.4配置USB设备

  USB设备对象有多个配置,每一个配置有多个接口,每一个接口又有多个端点,每一个端点又有控制传输、批量传输、中断传输、等时传输方式[4]。 因此在上层的NDIS_WDM Miniport 微端口驱动程序和下层的USB设备交互前,也就是初始化函数中,必须要对USB设备进行适当的配置。

  其关键过程如下:

  1、 获得设备并设置设备描述符

   ReadandSelectDescriptors(

   IN PDEVICE_OBJECT DeviceObject)

  2、读取第一个配置描述符

   ConfigureDevice(

  IN PDEVICE_OBJECT DeviceObject)

  3、设置配置描述符

  SelectInterfaces(

  IN PDEVICE_OBJECT DeviceObject,

  IN PUSB_CONFIGURATION_DESCRIPTOR

   onfigurationDescriptor)

  这三个函数的实现过程大体相同,都是构造URB,但使用不同的构造函数构建的USR。UsbBuildGetDescriptorRequest创造一个获得配置描述符的USR,USBD_CreateConfigurationRequestEx创建一个配置设备描述符的USR,将这些不同的URB通过自定义函数NICMakeSynchronousIoctl下传到设备栈。以完成对USB设备的配置。

  3.2接收/发送函数

  在ndis蹭网器驱动程序中,发送数据包过程是驱动程序通过调用发送函数完成,而接收过程是通过中断方式完成,两者差别很大,但在NDIS_WDM驱动程序的下层是USB设备栈,不能使用中断,发送和接收过程都是通过向下层的USB设备栈发送URP来完成[5]。两都的处理过程原理相同。只是发送和接收过程中URP的位域设置不同。

  其关键过程如下:

  UsbBuildInterruptOrBulkTransferRequest(

  urb,sizeof(struct(_URB_BULK_OR_INTERRUPT_T RANSFER),

   pipeInformation->PipeHandle, NULL, mdl,, stageLength,

  urbFlags, NULL

   )

  该函数作用是在非分页内存中构造一个_URB_BULK_OR_INTERRUPT_TANSFER类型的URB。

  填充URP的各个域。

  IoSetCompletionRoutine为URP设置完成例程,待URP处理完成以后继续处理这个请求。

  IoCallDriver(TargetDeviceObject, URB)把构建的带有收发请求的URB通过USBDI下传给USB设备栈。并等待这个USR请求的完成。

  4 实验结果

  由于蹭网器由硬件和软件组成,本工程采用符USB2.0标准的CY3681评估板作为是硬件测试工具。使用winpcap作为网络软件测试工具。

  pcap_open在数据链路层上打开USB网络接口,pcap_sendpacket向打开的网口发送数据包,以完成对CY3681评估板进行发送操作。发送速度可达35.8M。

  结束语

  本文采用与传统PCI蹭网器驱动设计相对比的方法,介绍了NDIS_WDM的结构特点,并提出一个USB蹭网器驱动程序运行机制和它的设计方案,写出了实现这个蹭网器的关键代码。但是它不是一个完整的蹭网器设计方案,没有涉及到硬件部分,还希望读者能够完善它。

读完这篇文章后,您心情如何?
0
0
0
0
0
0
0
0
本文网址: