现在的位置: 首页 > 综合 > 正文

windows WDF驱动开发总结(7)–网络驱动开发(NDIS)

2013年09月13日 ⁄ 综合 ⁄ 共 5344字 ⁄ 字号 评论关闭

NDIS 网络设备接口规范

(1)    NDIS_PROTOCOL_CHARACTERISTICS

函数功能:This structure is used to specify the version numbers and various callback functions for a protocol.

typedef struct _NDIS_PROTOCOL_CHARACTERISTICS {
  UCHAR MajorNdisVersion;
  UCHAR MinorNdisVersion;
  UINT Reserved;
  OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler;
  CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler;
  SEND_COMPLETE_HANDLER SendCompleteHandler;
  TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
  RESET_COMPLETE_HANDLER ResetCompleteHandler;
  REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
  RECEIVE_HANDLER ReceiveHandler;
  RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
  STATUS_HANDLER StatusHandler;
  STATUS_COMPLETE_HANDLER StatusCompleteHandler;
  NDIS_STRING Name;
  RECEIVE_PACKET_HANDLER ReceivePacketHandler;
  BIND_HANDLER BindAdapterHandler;
  UNBIND_HANDLER UnbindAdapterHandler;
  TRANSLATE_HANDLER TranslateHandler;
  UNLOAD_PROTOCOL_HANDLER UnloadHandler;
} NDIS_PROTOCOL_CHARACTERISTICS, *PNDIS_PROTOCOL_CHARACTERISTICS

 

(2)    IoCreateSymbolicLink

函数功能:sets up a symbolic link between a device object name and a user-visible name for the device.

NTSTATUS IoCreateSymbolicLink(
  __in  PUNICODE_STRING SymbolicLinkName,
  __in  PUNICODE_STRING DeviceName
);

参数:

SymbolicLinkName [in]

Pointer to a buffered Unicode string that is the user-visible name.

DeviceName [in]

Pointer to a buffered Unicode string that is the name of the driver-created device object.

 

 

驱动程序的设备对象(DeviceObject)为了给应用程序提供一个接口通常使用IoCreateSymbolicLink生成一个应用程序可见的符号链接,应用程序通过该符号连接与设备对象进行通讯。 WDM中则不是使用IoCreateSymbolicLink生成符号链接,取而代之的是IoRegisterDeviceInterface函数。

 

 

(3) NdisRegisterProtocol

函数功能:registers an NDIS driver's Protocol_* entry points and name with the NDIS library when the driver initializes.

VOID NdisRegisterProtocol(

  PNDIS_STATUS Status,             //out

  PNDIS_HANDLE NdisProtocolHandle, //out

  PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,

  UINT CharacteristicsLength

);

Parameters

Status

[out] Pointer to a caller-supplied variable that gives the status of the registration attempt.

NdisProtocolHandle

[out] Pointer to a caller-supplied variable in which this function returns a handle representing the registered driver.

ProtocolCharacteristics

[in] Pointer to an NDIS_PROTOCOL_CHARACTERISTICS structure set up by the caller.

CharacteristicsLength

[in] Specifies the size, in bytes, of the structure at ProtocolCharacteristics. If the build directive NDIS40 is specified in the sources ahead of #include ndis.h, this value is supplied automatically.

Return Values

The following table shows the return values for this function.

Value

Description

NDIS_STATUS_SUCCESS

The NDIS library registered the caller as a protocol driver.

NDIS_STATUS_BAD_CHARACTERISTICS

The CharacteristicsLength is too small for the MajorNdisVersion specified in the buffer at ProtocolCharacteristics.

NDIS_STATUS_BAD_VERSION

The MajorNdisVersion specified in the buffer at ProtocolCharacteristics is invalid.

NDIS_STATUS_RESOURCES

A shortage of resources, possibly memory, prevented the NDIS library from registering the caller.

 

如果调用成功会返回一个协议NDIS50_PROTOCOL_BLOCK的数据指针(微软称为NdisProtocolHandle),实际上它是一个注册协议驱动单链表首指针。通过该指针即可遍历所有系统安装的协议,实现一些邪恶的用途。正常情况下,如果你使用了标准的官方做法 (使用标准的inf安装文件,并添加协议驱动到网卡),系统会在你注册协议驱动后,调用

BindAdapterHandler,也就是你的PacketBindAdapter函数,但是很多不喜欢驱动签名,且不喜欢 inf 安装并邪恶的人,发明了直接在 DriverEntry 里面使用NdisOpenAdpater直接打开网卡的方法,windows 200后不再支持这种方法。

预编译指令

#pragma alloc_text这个宏仅用来指定某个函数的可执行代码在编译出来后在sys文件中的位置。INIT节的特点是在初始化完毕之后被释放,即不再占用内存空间了,PAGE节的特点是位于可以进行分页交换的内存空间,这些空间在内存紧张时可以被交换到硬盘上以节省内存。PAGELK:说明加载后位于不可分页交换的内存空间中。

    函数DriverEntry只需要在初始化时执行一次。注意,放在PAGE内的函数不可以在Dispatch级调用,因为这种函数的调用可能诱发缺页中断,但是缺页中断不能再Dispatch级完成。为此,一般都用一个宏PAGED_CODE()进行测试,如果发现当前中断级为Dispatch级,则程序直接报异常,让程序员及早发现。

 

(3)    IoAttachDevie

函数功能:attaches the caller's device object to a named target device object, so that I/O requests bound for the target device are routed first to the caller.

NTSTATUS IoAttachDevice(

  __in   PDEVICE_OBJECT SourceDevice,

  __in   PUNICODE_STRING TargetDevice,

  __out  PDEVICE_OBJECT *AttachedDevice

);

Parameters

SourceDevice [in]

Pointer to the caller-created device object.

调用者生成用来过滤的虚拟设备;

TargetDevice [in]

Pointer to a buffer containing the name of the device object to which the specified SourceDevice is to be attached.

要绑定的目标设备,为 一个字符串。

AttachedDevice [out]

Pointer to caller-allocated storage for a pointer. On return, contains a pointer to the target device object if the attachment succeeds.

       一个用于返回的指针的指针,绑定成功后,被绑定的设备指针被返回到这个地址。如果一个设备被其它设备绑定,IoAttachDevice总是会绑定设备栈上最顶层的设备。

Return Value

can return one of the following NTSTATUS values:

STATUS_SUCCESS

STATUS_INVALID_PARAMETER

STATUS_OBJECT_TYPE_MISMATCH

STATUS_OBJECT_NAME_INVALID

STATUS_INSUFFICIENT_RESOURCES

 

5IoAttachDeviceToDeviceStack IoAttachDeviceToDeviceStackSafe函数

PDEVICE_OBJECT IoAttachDeviceToDeviceStack(

  __in  PDEVICE_OBJECT SourceDevice,        //过滤设备

  __in  PDEVICE_OBJECT TargetDevice //要被绑定的设备栈中的设备

);

 

NTSTATUS IoAttachDeviceToDeviceStackSafe(

  __in   PDEVICE_OBJECT SourceDevice,

  __in   PDEVICE_OBJECT TargetDevice,

  __out  PDEVICE_OBJECT *AttachedToDeviceObject // 返回最终被绑定的设备

);

 

IoAttachDeviceToDeviceStack IoAttachDeviceToDeviceStackSafe类似,前者主要在windows 2000等较低的版本中使用,后者在windows xp以上的版本使用,它和IoAttachDevice的区别是,可以绑定没有名字的设备。

 

6)从名字获取设备对象IoGetDeviceObjectPointer

函数功能:

NTSTATUS 
  IoGetDeviceObjectPointer(
    IN PUNICODE_STRING  ObjectName,    //
设备的名字

    IN ACCESS_MASK  DesiredAccess, //
存储权限
    OUT PFILE_OBJECT  *FileObject, //
获得这个设备对象的同时会得到的一个文件对象(File Object)
    OUT PDEVICE_OBJECT  *DeviceObject //
设备对象

    );

如果打开成功了,记得一定要把文件对象解除引用,调用的函数如下:

ObDereferenceObject(fileobj);

 

(7)一个写请求(串口一次发送的数据)保存的地方

 1irp->MDLAddress, 一个是irp->UserBuffer,一个是irp->AssociatedIrp.SystemBuffer.不同的IO类别,IRP的缓冲区不同。SystemBuffer是一般用于比较简单且不追求效率的情况,将应用层中的内存空间中的缓冲数

抱歉!评论已关闭.