Windows驱动_WSK驱动之三WSK编程注意事项
今天在天涯上看到一篇帖子,真的是好震撼,原来对于那些人来说,自己已经足够幸福了,我们无法去体会那样的痛苦,只有经历的人才才能真正感受,我都无法想象自己,在那种情况下,需要怎样一种担当啊。虽然,男人真的就应该这样,但是,这句话容易说,无法去做,看到后来感觉自己真要流泪了。我应该怀着一颗感恩的心去对待这个社会,每一个人,对于我这个年纪的人来说,金钱,是必需的,但不需要过于追求,差不多就行,这绝不是,让自己放弃追求,而是让自己,可以享受偶尔的休息,为了更好的出发!
Winsock Kernel Programming Considerations
Sharing Transport Addresses
在大多数情况下,WSK应用不能绑定一个套接字到一个本地传输地址,这个传输地址已经被其它动态套接字使用了。WSK应用可以使用SO_EXCLUSIVEADDRUSE
和SO_REUSEADDR套接字选项去控制已经被绑定了套接字的本地传输地址的共享。默认情况下,没有选项对套接字进行控制。
如下的表格显示了,对一个被另外一个套接字绑定的本地传输地址上,进行第二个套接字绑定的结果。Wildcard和Specific指定了是否套接字被绑定在一个
通用的本地传输地址还是特殊的本地传输地址。
First bind
Second bind No socket options (default)
Wildcard Specific
No socket options (default) Wildcard INUSE SUCCESS
Specific CHECK INUSE
SO_REUSEADDR Wildcard DENIED SUCCESS
Specific CHECK DENIED
SO_EXCLUSIVEADDRUSE Wildcard INUSE INUSE
Specific CHECK INUSE
First bind
Second bind SO_REUSEADDR
Wildcard Specific
No socket options (default) Wildcard INUSE SUCCESS
Specific CHECK DENIED
SO_REUSEADDR Wildcard SUCCESS SUCCESS
Specific SUCCESS SUCCESS
SO_EXCLUSIVEADDRUSE Wildcard INUSE INUSE
Specific CHECK INUSE
First bind
Second bind SO_EXCLUSIVEADDRUSE
Wildcard Specific
No socket options (default) Wildcard INUSE SUCCESS
Specific DENIED INUSE
SO_REUSEADDR Wildcard DENIED SUCCESS
Specific DENIED DENIED
SO_EXCLUSIVEADDRUSE Wildcard INUSE INUSE
Specific DENIED INUSE
SUCCESS:
在第二个套接字上的绑定操作成功,WSK子系统返回STATUS_SUCCESS.
INUSE:
在第二个套接字上的绑定操作失败,WSK子系统返回STATUS_ADDRESS_ALREADY_EXISTS.
DENIED:
在第二个套接字上的绑定操作失败,WSK子系统返回STATUS_ACCESS_DENIED.
CHECK:
进入检查操作被执行,为了去探测在第二个套接字上的绑定操作时成功还是失败。如果进入的权限被赢得,绑定成功,WSK子系统返回STATUS_SUCCESS,
绑定失败,WSK子系统返回STATUS_ACCESS_DENIED.
在预前表格的定义进入检查被执行,第二个套接字安全上下文相对于第一个套接字的安全描述符被检查。
套接字的安全上下文在套接字被创建的时候,可以通过传递给WskSocket或WskSocketConnect函数的参数OwningProcess和OwningThread来检查。如果在套接字被创建的时候没有特殊的进程或线程被指定,创建套接字的安全上下文的进程被使用。
套接字的安全描述符在套接字被创建的时候,通过传递给WskSocket或WskSocketConnect函数的参数SecurityDescriptor来指定。如果没有指定特殊的安全描述符,WSK子系统使用默认的安全描述符,不允许共享传输地址。通过使用SO_WSK_SECURITY套接字选项,在套接字创建以后也可以使安全描述符应用于套接字。
如果两个套接字被绑定到两个不同的指定的本地传输地址上,在两个传输地址上都没有共享。在这种条件下,第二个绑定操作将一直完成成功。
Using TDI Transports
WSK子系统提供了对使用TDI传输的支持。为了通过WSK NPI使用TDI传输,WSK应用必须映射地址组,套接字类型,以及和每一个TDI传输相关联的设备名的协议。WSK应用可以通过WSK_TDI_DEVICENAME_MAPPING客户控制操作来映射这些资源。
// Number of TDI mappings
#define MAPCOUNT 2
// Array of TDI mappings
const WSK_TDI_MAP TdiMap[MAPCOUNT] =
{
{SOCK_STREAM, ..., ..., ...},
{SOCK_DGRAM, ..., ..., ...}
};
// TDI map info structure
const WSK_TDI_MAP_INFO TdiMapInfo =
{
MAPCOUNT,
TdiMap
}
// Function to set the TDI map
NTSTATUS
SetTdiMap(
PWSK_APP_BINDING_CONTEXT BindingContext
)
{
NTSTATUS Status;
// Perform client control operation
Status =
BindingContext->
WskProviderDispatch->
WskControlClient(
BindingContext->WskClient,
WSK_TDI_DEVICENAME_MAPPING,
sizeof(WSK_TDI_MAP_INFO),
&TdiMapInfo,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return status of client control operation
return Status;
}
在创建任何套接字之前,WSK应用必须映射地址,套接字类型,TDI传输名字的协议。当WSK应用成功将这些资源映射以后,应用可以创建新的套接字来使用映射的TDI传输。
Using NMR for WSK Registration and Unregistration
WSK应用除了通过WSK注册函数来附加或卸载到WSK子系统以后,WSK也可用通过使用网络模块注册(NMR)附加在WSK子系统上面。
WSK应用使用NMR注册自己作为WSK NPI的客户端,通过如下的节:
Initializing NMR Data Structures
WSK应用使用NMR注册之前,必须初始化如下的结构。
NPI_MODULEID
NPI_CLIENT_CHARACTERISTICS
NPI_REGISTRATION_INSTACNE包含在NPI_CLIENT_CHARACTERISTICS结构。
所有的这些数据结构必须保持有效而且一直驻留在内存中,直到WSK应用通过NMR注册。
如下的代码演示了WSK应用如何初始化所有的数据结构。
// Include the WSK header file
#include "wsk.h"
// Structure for the WSK application's network module identification
const NPI_MODULEID ModuleId =
{
sizeof(NPI_MODULEID),
MIT_GUID,
{ ... } // A GUID that uniquely identifies the WSK application
};
// Prototypes for the WSK application's NMR API callback functions
NTSTATUS
ClientAttachProvider(
IN HANDLE NmrBindingHandle,
IN PVOID ClientContext,
IN PNPI_REGISTRATION_INSTANCE ProviderRegistrationInstance
);
NTSTATUS
ClientDetachProvider(
IN PVOID ClientBindingContext
);
VOID
ClientCleanupBindingContext(
IN PVOID ClientBindingContext
);
// Structure for the WSK application's characteristics
const NPI_CLIENT_CHARACTERISTICS Characteristics =
{
0,
sizeof(NPI_CLIENT_CHARACTERISTICS),
ClientAttachProvider,
ClientDetachProvider,
ClientCleanupBindingContext,
{
0,
sizeof(NPI_REGISTRATION_INSTANCE),
&NPI_WSK_INTERFACE_ID,
&ModuleId,
0,
NULL
}
};
WSK应用调用NmrRegisterClient函数使用NMR注册应用。
// Variable to contain the handle for the registration with the NMR
HANDLE RegistrationHandle;
// DriverEntry function
NTSTATUS
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status;
.
.
.
// Register the WSK application with the NMR
Status = NmrRegisterClient(
&Characteristics,
NULL,
&RegistrationHandle
);
if(!NT_SUCCESS(Status)) {
.
.
.
return Status;
}
.
.
.
}
WSK应用不需要在DriverEntry函数中调用NmrRegisterClient函数。举例来说,如果WSK应用在一个复杂驱动的一个子部件,注册应用的动作可以发生在当其子部件激活的时候。
Attaching the WSK Client to the WSK Subsystem
WSK应用使用NMR注册成为WSK NPI的客户以后,如果WSK子系统被加载并使用NMR注册了自己以后,NMR会立即调用应用程序的ClientAttachProvider事件回调函数。如果WSK子系统没有使用NMR来注册,NMR就不会调用应用的ClientAttachProvider回调函数,直到WSK子系统使用NMR注册。
WSK应用应该使用如下的调用顺序来完成之后的流程。
1,当NMR调用WSK应用的ClientAttachProvider回调函数的时候,它将传递一个和WSK子系统相关联的NPI_REGISTRATION_INSTANCE结构指针给回调函数。WSK应用的ClientAttachProvider回调函数可以使用NMR传递给它的数据去探测是否可以附加在WSK子系统上。一般来说WSK应用只需要WSK子系统NPI_REGISTRATION_INSTANCE结构的成员NpiSpecificCharacteristice指定的WSK_PROVIDER_CHARACTERISTICS的版本信息。
2,如果WSK应用发现,它可以附加在WSK子系统上,WSK应用的ClientAttachProvider回调函数为了附加到WSK子系统上分配并初始化绑定上下文结构。应用调用NmrClientAttachProvider函数继续进行附加流程。
如果NmrClientAttachProvider返回STATUS_SUCCESS,WSK应用就已经成功附加在WSK子系统上。在这个条件下,当NMR调用应用的ClientAttachProvider函数的时候,WSK应用的ClientAttachProvider回调函数应该保存NMR传递给NmrBindingHandle参数的绑定句柄。WSK应用的ClientAttachProvider回调函数也必须保存指向WSK_CLIENT和WSK_PROVIDER_DISPATCH变量的指针。这些变量分别在传递给NmrClientAttachProvider函数的参数ProviderBindingContext和ProviderDispatch中。在WSK应用已经成功的附加在WSK子系统后,WSK应用的ClientAttachProvider回调函数返回STATUS_SUCCESS.
3,如果NmrClientAttachProvider返回STATUS_NOINTERFACE,WSK应用可以通过再次调用NmrClientAttachProvider函数,试图附加在WSK子系统之上,传递给ClientDispatch的不同WSK_CLIENT_DISPATCH结构体指针,WSK NPI支持的版本。
4,如果调用NmrClientAttachProvider函数没有返回STATUS_SUCCESS,WSK应用没有做进一步的操作去附加自己到WSK子系统,WSK应用的ClientAttachProvider回调函数应该清除所有的它在调用NmrClientAttachProvider的资源。在这种情况下,WSK应用的ClientAttachProvider回调函数必须在最后一次调用NmrClientAttachProvider函数时返回状态代码。
5,如果WSK应用发现,它不能附加到提供的模板上,应用的ClientAttachProvider回调函数必须返回STATUS_NOINTERFACE.
如下的代码演示了WSK应用如何将自己附加在WSK子系统上。
// Context structure type for the WSK application's
// binding to the WSK subsystem
typedef struct WSK_APP_BINDING_CONTEXT_ {
HANDLE NmrBindingHandle;
PWSK_CLIENT WskClient;
PWSK_PROVIDER_DISPATCH WskProviderDispatch;
.
. // Other application-specific members
.
} WSK_APP_BINDING_CONTEXT, *PWSK_APP_BINDING_CONTEXT;
// Pool tag used for allocating the binding context
#define BINDING_CONTEXT_POOL_TAG 'tpcb'
// The WSK application uses version 1.0 of WSK
#define WSK_APP_WSK_VERSION MAKE_WSK_VERSION(1,0)
// Structure for the WSK application's dispatch table
const WSK_CLIENT_DISPATCH WskAppDispatch = {
WSK_APP_WSK_VERSION,
0,
NULL // No WskClientEvent callback
};
// ClientAttachProvider NMR API callback function
NTSTATUS
ClientAttachProvider(
IN HANDLE NmrBindingHandle,
IN PVOID ClientContext,
IN PNPI_REGISTRATION_INSTANCE ProviderRegistrationInstance
)
{
PNPI_MODULEID WskProviderModuleId;
PWSK_PROVIDER_CHARACTERISTICS WskProviderCharacteristics;
PWSK_APP_BINDING_CONTEXT BindingContext;
PWSK_CLIENT WskClient;
PWSK_PROVIDER_DISPATCH WskProviderDispatch;
NTSTATUS Status;
// Get pointers to the WSK subsystem's identification and
// characteristics structures
WskProviderModuleId = ProviderRegistrationInstance->ModuleId;
WskProviderCharacteristics =
(PWSK_PROVIDER_CHARACTERISTICS)
ProviderRegistrationInstance->NpiSpecificCharacteristics;
//
// The WSK application can use the data in the structures pointed
// to by ProviderRegistrationInstance, WskProviderModuleId, and
// WskProviderCharacteristics to determine if the WSK application
// can attach to the WSK subsystem.
//
// In this example, the WSK application does not perform any
// checks to determine if it can attach to the WSK subsystem.
//
// Allocate memory for the WSK application's binding
// context structure
BindingContext =
(PWSK_APP_BINDING_CONTEXT)
ExAllocatePoolWithTag(
NonPagedPool,
sizeof(WSK_APP_BINDING_CONTEXT),
BINDING_CONTEXT_POOL_TAG
);
// Check result of allocation
if (BindingContext == NULL)
{
// Return error status code
return STATUS_INSUFFICIENT_RESOURCES;
}
// Initialize the binding context structure
...
// Continue with the attachment to the WSK subsystem
Status = NmrClientAttachProvider(
NmrBindingHandle,
BindingContext,
&WskAppDispatch,
&WskClient,
&WskProviderDispatch
);
// Check result of attachment
if (Status == STATUS_SUCCESS)
{
// Save NmrBindingHandle, WskClient, and
// WskProviderDispatch for future reference
BindingContext->NmrBindingHandle = NmrBindingHandle;
BindingContext->WskClient = WskClient;
BindingContext->WskProviderDispatch = WskProviderDispatch;
}
// Attachment did not succeed
else
{
// Free memory for application's binding context structure
ExFreePoolWithTag(
BindingContext,
BINDING_CONTEXT_POOL_TAG
);
}
// Return result of attachment
return Status;
}
Unregistering and Unloading the WSK Client
任何使用NMR注册将其自己附加在WSK子系统上的WSK应用在其驱动卸载之前,应该使用NMR进行反注册。当WSK应用调用NmrDeregisterClient函数使用NMR进行反注册,NMR调用应用的ClientDetachProvider回调函数,以至于应用可以从WSK子系统上进行卸载,这个作为WSK应用反注册流程的一部分。
此外,不太可能,但是有可能,在WSK子系统使用NMR进行反注册,NMR也调用WSK应用的ClientDetachProvider回调函数,以至于应用可以从WSK子系统上卸载作为WSK子系统反注册流程的一部分。
NMR调用WSK应用的ClientDetachProvider回调函数仅一次。如果WSK应用和WSK子系统都使用NMR进行反注册,NMR在第一个反注册被初始化以后,调用WSK应用的ClientDetachProvider回调函数。
如果在NMR调用WSK应用的ClientDetachProvider回调函数的时候,没有任何关于WSK_PROVIDER_DISPATCH结构中的WSK函数的调用,WSK应用应该在其ClientDetachProvider函数中返回STATUS_SUCCESS。否则,WSK应用应该在其ClientDetachProvider回调函数中返回STATUS_PENDING。在所有的WSK_PROVIDER_DISPATCH中的WSK函数调用返回以后,必须调用NmrClientDetachProviderComplete函数。WSK应用调用NmrClientDetachProviderComplete函数通知NMR,应用已经从WSK子系统卸载了。然而,WSK子系统不允许执行任何的分离操作,指定所有打开的套接字被WSK应用关闭以后。
在WSK应用已经通知NMR,分离操作已经完成以后,这个可以通过在ClientDetachProvider回调函数中返回STATUS_SUCCESS,或调用NmrClientDetachProviderComplete函数实现,应用程序不应该再调用WSK_PROVIDER_DISPATCH中的WSK函数。
如果WSK应用实现了ClientCleanupBindingContext回调函数,NMR在WSK应用和WSK子系统都已经完成互相的分离操作以后调用应用的ClientCleanupBindingContext回调函数。WSK应用的ClientCleanupBindingContext回调函数应该执行任何在应用绑定上下文的结构中的数据的清除操作。如果应用动态为结构分配了内存,
它应该为绑定上下文结构释放内存。
// ClientDetachProvider callback function
NTSTATUS
ClientDetachProvider(
IN PVOID ClientBindingContext
)
{
PWSK_APP_BINDING_CONTEXT BindingContext;
// Get a pointer to the binding context
BindingContext =
(PWSK_APP_BINDING_CONTEXT)ClientBindingContext;
// Check if there are no calls in progress to any WSK functions
// in WSK_PROVIDER_DISPATCH and that there are no open sockets
if (...)
{
// Return success status indicating that detachment is complete
return STATUS_SUCCESS;
}
// There are calls in progress to one or more of the WSK functions
// in WSK_PROVIDER_DISPATCH and/or one or more open sockets
else
{
// Return pending status, indicating that detachment is pending
// completion of the calls in progress to the WSK functions in
// WSK_PROVIDER_DISPATCH and/or closing of the open sockets
return STATUS_PENDING;
// When all of the calls in progress to the WSK functions
// in WSK_PROVIDER_DISPATCH are completed, the WSK application
// must close all open sockets.
//
// After all sockets have been closed, the WSK application must
// call the NmrClientDetachProviderComplete function with the
// binding handle for the attachment to the WSK subsystem.
}
}
// ClientCleanupBindingContext callback function
VOID
ClientCleanupBindingContext(
IN PVOID ClientBindingContext
)
{
PWSK_APP_BINDING_CONTEXT BindingContext;
// Get a pointer to the binding context
BindingContext =
(PWSK_APP_BINDING_CONTEXT)ClientBindingContext;
// Clean up the binding context structure
...
// Free the memory for client's binding context structure
ExFreePoolWithTag(
BindingContext,
BINDING_CONTEXT_POOL_TAG
);
}
WSK应用的Unload函数必须确保在应用从系统内存卸载之前,应用已经从NMR中反注册。WSK应用禁止在Unload函数中返回直到它已经从NRM中反注册完成。如果调用NmrDeregisterClient返回STATUS_PENDING,WSK应用必须在其Unload函数返回之前调用NmrWaitForClientDeregisterComplete函数等待反注册操作的完成。
// Variable containing the handle for registration with the NMR
HANDLE RegistrationHandle;
// Unload function
VOID
Unload(
IN PDRIVER_OBJECT DriverObject
)
{
NTSTATUS Status;
// Unregister the WSK application from the NMR
Status =
NmrDeregisterClient(
RegistrationHandle
);
// Check if pending
if (Status == STATUS_PENDING)
{
// Wait for the unregistration to be completed
NmrWaitForClientDeregisterComplete(
RegistrationHandle
);
}
}
WSK应用不需要在其Unload函数中调用NmrDeregisterClient函数。举例来说,如果WSK应用是一个复杂驱动的子部件,WSK的反注册可能在WSK应用的子部件不激活的时候发生。然而,在这样的情况下,驱动必须确保WSK应用在其Unload函数返回前已经完成了从NMR的反注册操作。
Windows驱动_WSK驱动之三WSK编程注意事项相关推荐
- Windows驱动_WSK驱动之二WSK的操作
现在还真是有点犹豫,有太多的牵绊,毕竟现在这个年纪,不能就这样随随便便,不是说,我不够自信,只是,目前的条件是这样,这里真的是没有太多的机会.创业没有足够的人脉,和行业,客户,目前,天时,地利,人和, ...
- Windows驱动_WSK驱动之一WSK是什么
感觉自己还是不够成熟,才过了一天,就开始全盘否定自己,否定Windows内核编程,否定自己之前所做的一切努力.自己还是太容易受环境的影响了,在这全是Android的时代,在这APP满天飞的年代,在这物 ...
- Windows驱动_WSK驱动之四WSK例程
最近看了好多文章,也写了好多博客,但是,最近少了很多实践的关系,这一部分是项目的问题,其实大部分还是自己的问题,今天,竟然,知道,随便修改一点微软的例子还可以赚钱,之前自己还真是没有想到的.后续,自己 ...
- 连接LilyPad之Windows平台的驱动
连接LilyPad之Windows平台的驱动 LilyPad和其他的Arduino控制板的不同之处是它是为电子织物和可穿戴设计的.那么,它的大小就必须要紧凑.所以,它并没有板载其他大多数板子都具有的U ...
- Windows CE设备驱动开发之电源管理
4.7电源管理 电源管理模块管理设备电源,从而全面改进操作系统的电源使用效率:它所有设备的电源使用,同时能与不支持电源管理的应用程序及驱动程序共存. 使用电源管理可以有效的减少目标设备的电源消耗,同时 ...
- Windows的设备驱动框架
Windows的设备驱动框架 Windows内核管理层的部件之一是I/O管理模块,有时候也称为I/O子系统.I/O管理模块所管理的对象与活动纵向贯穿管理层.核心层乃至HAL层,所以称之为子系统其实也有 ...
- 如何正确入门Windows系统下驱动开发领域?
[作者] 猪头三 作者网站: http://www.x86asm.com 原文链接: http://blog.csdn.net/Code_GodFather/...0/5975901.aspx [贡献 ...
- Windows 文件系统过滤驱动开发教程 (第二版)
Windows 文件系统过滤驱动开发教程 (第二版) 楚狂人-2007-上海 (MSN:walled_river@hotmail.com) -1. 改版序....... ...
- 微软视窗驱动模型(WDM)编程指南
第一章 开始一个驱动项目 在本章中我将对驱动开发的历史作一个简要的回顾.从80年代中期起,我开始涉足个人计算领域,那时也正是IBM刚刚开始出售搭配着MS-DOS操作系统的个人电脑. ...
最新文章
- Vim 快捷键整理【转】
- 分屏显示_王者做图显示器,戴尔(DELL)U2417全面介绍
- 创业公司做数据分析(三)用户行为数据采集系统 (转)
- 自己写一个实现ApplicationListener​接口并且把该组件加入到容器中
- 【CodeForces - 523C】Name Quest (模拟)
- 天池 在线编程 布尔表达式求值(栈)
- python shell运行当前程序、可以按下_Python下调用Linux的Shell命令的方法
- win7 能下node什么版本_微软从未公开的win10版本,3GB+极度精简,老爷机有救了
- linux系统监控和进程管理
- 安装JDK,如何配置PATH,如何配置CLASSPATH
- 四川省盐业学校九五计算机,2020年四川省盐业学校招生录取分数线
- 鸽笼原理 c语言,抽屉原理的三个公式,抽屉问题经典例题10道
- 铸博皇御:黄金现货交易究竟适不适合上班族?
- 数据结构 ADT例子
- 智加助力解放完成“自动变道”国标验证,唯一量产自动驾驶重卡过考
- click和touchmove vue_移动端touch事件影响click事件以及在touchmove添加preventDefault导致页面无法滚动的解决方法...
- 一年内经验前端面试题记录
- order by 空值排在最后_ZSBL高中组晋级赛圆满结束!汤溪中学杀出重围,顺利夺下最后一张总决赛门票!...
- Android存储之SharedPreferences源码解析
- 微服务容器部署与持续集成(Jenkins)
热门文章
- HTML5期末大作业:体育足球网站设计——足球(6页) HTML+CSS+JavaScript 大学生体育运动网页设计模板代码 校园足球网页作业成品 学校足球网页制作模板 学生简单体育运动网站设计成
- 蓝桥杯练习----数字三角形,Cowboys,Beaver's Calculator
- C---calloc
- springboot/vue前后端分离后台管理系统增删改查
- 笔记本计算机忘记密码,Windows笔记本电脑忘记开机登录密码忘记怎么办 最新win7/8/10开机密码重置教程...
- 修复linux bash破壳漏洞,Linux下bash破壳漏洞检测及修复的方法
- 小罗与卡卡辞别世界杯
- Linux服务器搭建相关教程链接整理
- jack -学习颜色的调配
- xcopy、rd、COPY、MD、DEL、REN 命令祥解