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
(5)IoAttachDeviceToDeviceStack 和 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)一个写请求(串口一次发送的数据)保存的地方
1)irp->MDLAddress, 一个是irp->UserBuffer,一个是irp->AssociatedIrp.SystemBuffer.不同的IO类别,IRP的缓冲区不同。SystemBuffer是一般用于比较简单且不追求效率的情况,将应用层中的内存空间中的缓冲数