Registro de una aplicación kernel de Winsock

Registro de objetos de cliente de WSK

Una aplicación winsock Kernel (WSK) debe registrarse como un cliente WSK llamando a la función WskRegister . WskRegister requiere que la aplicación WSK inicialice y pase un puntero a la interfaz de programación de red (NPI) de su cliente WSK (NPI) (una estructura de WSK_CLIENT_NPI ) y un objeto de registro WSK (una estructura de WSK_REGISTRATION ) que WskRegister inicializará tras la devolución correcta.

En el ejemplo de código siguiente se muestra cómo una aplicación WSK puede registrarse como un cliente 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;
  }

  .
  . 
  .
}

No se requiere una aplicación WSK para llamar a WskRegister desde su función DriverEntry . Por ejemplo, si una aplicación WSK es un subcomponente de un controlador complejo, el registro de la aplicación puede producirse solo cuando se activa el subcomponente de la aplicación WSK.

Una aplicación WSK debe mantener la estructura de WSK_CLIENT_DISPATCH pasada a WskRegister válida y residente en memoria hasta que se llame a WskDeregister y el registro ya no sea válido. La estructura WSK_REGISTRATION también debe mantenerse válida y residir en la memoria hasta que la aplicación WSK deje de realizar llamadas a las otras funciones de registro de WSK. En el ejemplo de código anterior se mantienen estas dos estructuras en la sección de datos globales del controlador, lo que mantiene los datos de estructura residentes en memoria hasta que se descarga el controlador.

Captura de NPI del proveedor WSK

Después de que una aplicación WSK se haya registrado como un cliente WSK con WskRegister, debe usar la función WskCaptureProviderNPI para capturar el proveedor de WSK NPI desde el subsistema WSK para empezar a usar la interfaz WSK.

Dado que es posible que el subsistema WSK aún no esté listo cuando una aplicación WSK intenta capturar el NPI del proveedor WSK, la función WskCaptureProviderNPI permite que la aplicación WSK sondee o espere a que el subsistema WSK esté listo de la siguiente manera:

  • Si el parámetro WaitTimeout es WSK_NO_WAIT, la función siempre devolverá inmediatamente sin esperar.

  • Si WaitTimeout está WSK_INFINITE_WAIT, la función esperará hasta que el subsistema de WSK esté listo.

  • Si WaitTimeout es cualquier otro valor, la función devolverá cuando el subsistema WSK esté listo o cuando el tiempo de espera, en milisegundos, alcance el valor de WaitTimeout, lo que ocurra primero.

Importante Para evitar que afecte negativamente al inicio de otros controladores y servicios, una aplicación WSK que llama a WskCaptureProviderNPI desde su función DriverEntry no debe establecer el parámetro WaitTimeout en WSK_INFINITE_WAIT o un tiempo de espera excesivo. Además, si una aplicación WSK se inicia muy pronto en la fase de inicio del sistema, debe esperar a que el subsistema de WSK esté listo en un subproceso de trabajo diferente al del que se ejecuta DriverEntry .

Si se produce un error en la llamada a WskCaptureProviderNPI con STATUS_NOINTERFACE, la aplicación WSK puede usar la función WskQueryProviderCharacteristics para detectar el intervalo de versiones NPI de WSK compatibles con el subsistema WSK. La aplicación WSK puede llamar a WskDeregister para anular el registro de su instancia de registro actual y, a continuación, volver a registrarse mediante una instancia de WSK_CLIENT_DISPATCH diferente que use una versión de NPI de WSK compatible.

Cuando WskCaptureProviderNPI vuelve correctamente, su parámetro WskProviderNpi apunta a un proveedor de WSK NPI ( WSK_PROVIDER_NPI) listo para su uso por parte de la aplicación WSK. La estructura de WSK_PROVIDER_NPI contiene punteros al objeto de cliente WSK ( WSK_CLIENT) y la tabla de distribución WSK_PROVIDER_DISPATCH de funciones WSK que la aplicación WSK puede usar para crear sockets WSK y realizar otras operaciones en el objeto de cliente WSK. Una vez finalizada la aplicación WSK mediante las funciones de WSK_PROVIDER_DISPATCH, debe liberar el proveedor de WSK NPI llamando a WskReleaseProviderNPI.

En el ejemplo de código siguiente se muestra cómo una aplicación WSK puede capturar el NPI del proveedor WSK, usarla para crear un socket y, a continuación, liberarla.

// 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;

}

Una aplicación WSK puede llamar a WskCaptureProviderNPI más de una vez. Para cada llamada a WskCaptureProviderNPI que devuelve correctamente, debe haber una llamada correspondiente a WskReleaseProviderNPI. Una aplicación WSK no debe realizar más llamadas a las funciones de WSK_PROVIDER_DISPATCH después de llamar a WskReleaseProviderNPI.