Windows驱动_WSK驱动之二WSK的操作

               现在还真是有点犹豫,有太多的牵绊,毕竟现在这个年纪,不能就这样随随便便,不是说,我不够自信,只是,目前的条件是这样,这里真的是没有太多的机会。创业没有足够的人脉,和行业,客户,目前,天时,地利,人和,都没有,暂时也就不考虑了。就算是有企业,真的就放弃这些去吗?那不是又回到老路上去了。所以,目前,应该积极的扩展自己的人脉。还有,就是最好有一些现实的东西,自己可以做出来。用之前的经验。 


               Registering a Winsock Kernel Application

 

               WSK Client Object Registration

 

               WSK应用必须通过调用WskRegister函数注册作为一个WSK客户端。WskRegister需要WSK应用初始化并传递一个指向WSK客户的NPI(WSK_CLIENT_NPI结构)一个WSK注册对象(WSK_REGISTRATION结构)被WskRegister初始化并返回。

 

             下面的代码演示了WSK应用镇压个去注册一个WSK客户端。
 
 
  // Include the WSK header file
  #include "wsk.h"

  // WSK Client Dispatch table that denotes the WSK version
  // that the WSK application wants to use and optionally a pointer
  // to the WskClientEvent callback function
  const WSK_CLIENT_DISPATCH WskAppDispatch = {
   MAKE_WSK_VERSION(1,0), // Use WSK version 1.0
   0,    // Reserved
   NULL  // WskClientEvent callback not required for WSK version 1.0
  };

  // WSK Registration object
  WSK_REGISTRATION WskRegistration;

  // DriverEntry function
  NTSTATUS
  DriverEntry(
   PDRIVER_OBJECT DriverObject,
   PUNICODE_STRING RegistryPath
  )
  {
   NTSTATUS Status;
   WSK_CLIENT_NPI wskClientNpi;

   .
   .
   .

   // Register the WSK application
   wskClientNpi.ClientContext = NULL;
   wskClientNpi.Dispatch = &WskAppDispatch;
   Status = WskRegister(&wskClientNpi, &WskRegistration);

   if(!NT_SUCCESS(Status)) {
   .
   .
   .
    return Status;
   }

   .
   .
   .
  }
 
              WSK应用不需要在其DriverEntry函数中,调用WskRegister。举例来说,如果WSK应用只是一个复杂驱动的一个子部件,注册应用的操作可能发生在WSK应用子部件激活的时候。

 

              WSK应用必须保证传递给WskRegister的参数WSK_CLIENT_DISPATCH结构体的有效和一直驻留在内存中,直到WskDeregister被调用,注册不再有效。WSK_REGISTRATION结构体也必须保持其有效和一直驻留在内存中直到WSK应用停止调用其他的WSK注册函数。预前的代码将这两个结构体放在驱动的全局变量中,从而保证结构体一直驻留在内存中直到驱动被卸载。

 

              WSK Provider NPI Capture

 

              在WSK应用使用WskRegister已经注册为WSK客户端后,它为了使用WSK接口必须调WskCaptureProvideNPI函数去捕获WSK从WSK子系统提供的NPI.
 
             因为WSK子系统在WSK应用试图去捕获WSK提供的NPI的时候可能还没有准备好。WskCaptureProvideNPI函数允许WSK应用投票或等待WSK子系统准备好。
 
            如果WaitTimeout参数是WSK_NO_WAIT,这个函数不等待总是直接返回。
  
            如果WaitTimeout是WSK_INFINITE_WAIT,函数将等待直到WSK子系统准备好。
   
            如果WaitTimeout是其他值,这个函数将在WSK变成准备好以后返回,或在等待了时间到了之后返回。
   
            为了避免影响到其他的驱动的服务的启动,WSK 应用在DriverEntry函数中调用WskCaptureProviderNPI的时候,不应该设置WaitTimeout参数为WSK_INFINITE,或一个有限的等待时间。如果,WSK应用在系统的启动很早的阶段开启,它应该在不同于DriverEntry的工作线程中等待WSK子系统准备好。

 

            如果调用WskCaptureProviderNPI 失败返回STATUS_NOINTERFACE,WSK应用应该使用WskQueryProviderCharacteristics函数去发现WSK子系统支持的WSK NPI的范围。WSK应用可以调用WskDeregister去卸载当前注册过的实例,然后使用不同的WSK NPI版本支持的WSK_CLIENT_DISPATCH实例重新注册。

 

             当WskCaptureProviderNPI返回成功,它的WskProviderNpi参数指向WSK提供的NPI(WSK_PROVIDER_NPI)准备好给WSK应用使用的接口。WSK_RPOVIDER_NPI结构包含一个指向WSK客户对象的指针(WSK_CLIENT)和WSK_PROVIDER_DISPATCH派遣函数指针列表的指针,可以在WSK客户对象上使用这些函数创建WSK的套接字并执行一些操作。WSK应用在结束使用WSK_PROVIDER_DISPATCH函数以后,它必须调用WskReleaseProviderNPI去释放WSK提供的NPI.

 

            如下的例子展示了WSK应用怎样去捕获WSK提供的NPI,使用它去创建套接字,然后将其释放。
 
  // WSK application routine that waits for WSK subsystem
  // to become ready and captures the WSK Provider NPI
  NTSTATUS
  WskAppWorkerRoutine(
  )
  {
   NTSTATUS Status;
   WSK_PROVIDER_NPI wskProviderNpi;
 
   // Capture the WSK Provider NPI. If WSK subsystem is not ready yet,
   // wait until it becomes ready.
   Status = WskCaptureProviderNPI(
     &WskRegistration, // must have been initialized with WskRegister
     WSK_INFINITE_WAIT,
     &wskProviderNpi
   );

   if(!NT_SUCCESS(Status))
   {
    // The WSK Provider NPI could not be captured.
    if( Status == STATUS_NOINTERFACE ) {
    // WSK application's requested version is not supported
   }
   else if( status == STATUS_DEVICE_NOT_READY ) {
    // WskDeregister was invoked in another thread thereby causing
    // WskCaptureProviderNPI to be canceled.
   }
   else {
    // Some other unexpected failure has occurred
   }

   return Status;
  }

   // The WSK Provider NPI has been captured.
   // Create and set up a listening socket that accepts
   // incoming connections.
   Status = CreateListeningSocket(&wskProviderNpi, ...);

   // The WSK Provider NPI will not be used any more.
   // So, release it here immediately.
   WskReleaseProviderNPI(&WskRegistration);

   // Return result of socket creation routine
   return Status;

  }
 
              WSK应用可以调用WskCaptureProviderNPI多次,每一次的成功调用WskCaptureProviderNPI,都需要相应的调用WskReleaseProviderNPI.WSK应用在调用WskReleaseProviderNPI以后不应该调用任何在WSK_PROVIDER_DISPATCH的函数。

 

              Performing Control Operations on a Client Object

 

             WSK应用在已经成功附加在WSK子系统以后,它可以在其往WSK子系统附加操作中返回的客户对象(WSK_CLIENT)上执行一些控制操作。这些控制操作不需要指定特定的套接字,但是有很多通用的功能。

 

              执行客户对象的控制操作可以通过调用WSK_PROVIDER_DISPATCH结构体中的WskControlClient成员,它是一个指向WskControlClient函数的指针。
 
              如下的代码演示了WSK应用如何使用WSK_TRANSPORT_LIST_QUERY客户控制操作在创建一个新的套接字的时候得到一组可用的指定的网络传输列表。
 
  // Function to retrieve a list of available network transports
  NTSTATUS
  GetTransportList(
   PWSK_PROVIDER_NPI WskProviderNpi,
   PWSK_TRANSPORT TransportList,
   ULONG MaxTransports,
   PULONG TransportsRetrieved
  )
  {
   SIZE_T BytesRetrieved;
   NTSTATUS Status;

   // Perform client control operation
   Status =
    WskProviderNpi->Dispatch->
     WskControlClient(
     WskProviderNpi->Client,
     WSK_TRANSPORT_LIST_QUERY,
     0,
     NULL,
     MaxTransports * sizeof(WSK_TRANSPORT),
     TransportList,
     &BytesRetrieved,
     NULL  // No IRP for this control operation
    );

   // Convert bytes retrieved to transports retrieved
   TransportsRetrieved = BytesRetrieved / sizeof(WSK_TRANSPORT);

   // Return status of client control operation
   return Status;
  }
 
              Creating Sockets

 

              在WSK已经成功附加在WSK子系统上以后,它可以创建套接字来完成网络IO操作。WSK应用通过调用WskSocket函数来创建套接字。这个函数指针通过WSK_PROVIDER_DISPATCH结构的WskSocket成员得到。

 

              WSK应用应该在其创建一个新的套接字的时候,指定套接字的类型。
  
             WSK应用在其创建新的套接字前也应该指定其地址,套接字种类,协议等。
 
             当创建一个新的套接字的时候,如果应用需要在套接字上使能事件回调函数,它必须提供一个套接字上下文和一个客户分发列表结构。
 
             如果套接字创建成功,IRP的IoStatus.Information域包含一个指向新套接字对象结构(WSK_SOCKET)的指针。
 
             如下的代码演示了WSK应用如何创建一个监听套接字。
 
  // Context structure for each socket
  typedef struct _WSK_APP_SOCKET_CONTEXT {
       PWSK_SOCKET Socket;
       .
       .  // Other application-specific members
       .
  } WSK_APP_SOCKET_CONTEXT, *PWSK_APP_SOCKET_CONTEXT;

  // Prototype for the socket creation IoCompletion routine
  NTSTATUS
  CreateListeningSocketComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
  );

  // Function to create a new listening socket
  NTSTATUS
  CreateListeningSocket(
   PWSK_PROVIDER_NPI WskProviderNpi,
   PWSK_APP_SOCKET_CONTEXT SocketContext,
   PWSK_CLIENT_LISTEN_DISPATCH Dispatch,
  )
  {
   PIRP Irp;
   NTSTATUS Status;

   // Allocate an IRP
   Irp =
    IoAllocateIrp(
     1,
     FALSE
    );

   // Check result
   if (!Irp)
   {
    // Return error
    return STATUS_INSUFFICIENT_RESOURCES;
   }

   // Set the completion routine for the IRP
   IoSetCompletionRoutine(
     Irp,
     CreateListeningSocketComplete,
     SocketContext,
     TRUE,
     TRUE,
     TRUE
   );

   // Initiate the creation of the socket
   Status =
   WskProviderNpi->Dispatch->
     WskSocket(
     WskProviderNpi->Client,
     AF_INET,
     SOCK_STREAM,
     IPPROTO_TCP,
     WSK_FLAG_LISTEN_SOCKET,
     SocketContext,
     Dispatch,
     NULL,
     NULL,
     NULL,
     Irp
    );

   // Return the status of the call to WskSocket()
   return Status;
  }

  // Socket creation IoCompletion routine
  NTSTATUS
  CreateListeningSocketComplete(
   PDEVICE_OBJECT DeviceObject,
   PIRP Irp,
   PVOID Context
  )
  {
   UNREFERENCED_PARAMETER(DeviceObject);

   PWSK_APP_SOCKET_CONTEXT SocketContext;

   // Check the result of the socket creation
   if (Irp->IoStatus.Status == STATUS_SUCCESS)
   {
    // Get the pointer to the socket context
    SocketContext =
    (PWSK_APP_SOCKET_CONTEXT)Context;

   // Save the socket object for the new socket
   SocketContext->Socket =
    (PWSK_SOCKET)(Irp->IoStatus.Information);

   // Set any socket options for the new socket
   ...

   // Enable any event callback functions on the new socket
   ...

   // Perform any other initializations
   ...
   }

   // Error status
   else
   {
    // Handle error
    ...
   }

   // Free the IRP
   IoFreeIrp(Irp);

   // Always return STATUS_MORE_PROCESSING_REQUIRED to
   // terminate the completion processing of the IRP.
    return STATUS_MORE_PROCESSING_REQUIRED;
  }
  
              对于面向连接的套接字,WSK应用可以调用WskSocketConnect函数去创建,绑定,连接套接字在一个单独函数的调用中。
 
             Performing Control Operations on a Socket

 

            WSK应用在成功创建套接字以后,它就可以在套接上进行一些控制操作。这些操作包括设置并得到套接字的设定和执行一些套接字IOCTL操作。
 
            WSK应用通过调用WskControlSocket函数来在套接字上执行一些控制操作。这个函数由套接字提供的派遣函数列表结构的成员WskControlSocket指定。派遣函数列表结构通过套接字对象结构(WSK_SOCKET)的成员Dispatch指定,WSK_SOCKET在创建套接字的操作中由WSK子系统返回。

 

            下面的代码演示了WSK应用如何在数据报套接字上设置SO_EXCLUSIVEADDRUSE套接字设定。
 
  // Prototype for the control socket IoCompletion routine
  NTSTATUS
  ControlSocketComplete(
   PDEVICE_OBJECT DeviceObject,
   PIRP Irp,
   PVOID Context
  );

  // Function to set the SO_EXCLUSIVEADDRUSE socket option
  // on a datagram socket
  NTSTATUS
  SetExclusiveAddrUse(
   PWSK_SOCKET Socket
  )
  {
   PWSK_PROVIDER_DATAGRAM_DISPATCH Dispatch;
   PIRP Irp;
   ULONG SocketOptionState;
   NTSTATUS Status;

   // Get pointer to the socket's provider dispatch structure
   Dispatch =
    (PWSK_PROVIDER_DATAGRAM_DISPATCH)(Socket->Dispatch);

   // Allocate an IRP
   Irp =
    IoAllocateIrp(
       1,
       FALSE
    );

   // Check result
   if (!Irp)
   {
    // Return error
    return STATUS_INSUFFICIENT_RESOURCES;
   }

   // Set the completion routine for the IRP
   IoSetCompletionRoutine(
    Irp,
    ControlSocketComplete,
    Socket,  // Use the socket object for the context
    TRUE,
    TRUE,
    TRUE
   );

   // Set the socket option state to 1 to set the socket option
   SocketOptionState = 1;

   // Initiate the control operation on the socket
   Status =
    Dispatch->WskControlSocket(
       Socket,
       WskSetOption,
       SO_EXCLUSIVEADDRUSE,
       SOL_SOCKET,
       sizeof(ULONG),
       &SocketOptionState,
       0,
       NULL,
       NULL,
       Irp
    );

   // Return the status of the call to WskControlSocket()
    return Status;
  }

  // Control socket IoCompletion routine
  NTSTATUS
  ControlSocketComplete(
   PDEVICE_OBJECT DeviceObject,
   PIRP Irp,
   PVOID Context
  )
  {
   UNREFERENCED_PARAMETER(DeviceObject);

   PWSK_SOCKET Socket;

   // Check the result of the control operation
   if (Irp->IoStatus.Status == STATUS_SUCCESS)
   {
    // Get the socket object from the context
    Socket = (PWSK_SOCKET)Context;

    // Perform the next operation on the socket
    ...
   }

   // Error status
   else
   {
    // Handle error
    ...
   }

   // Free the IRP
   IoFreeIrp(Irp);

   // Always return STATUS_MORE_PROCESSING_REQUIRED to

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值