Registrando um aplicativo de kernel Winsock

Registro de objeto do cliente WSK

Um aplicativo WSK (Winsock Kernel) deve se registrar como um cliente WSK chamando a função WskRegister . O WskRegister exige que o aplicativo WSK inicialize e passe um ponteiro para a NPI (Interface de Programação de Rede) do cliente WSK (uma estrutura WSK_CLIENT_NPI ) e um objeto de registro do WSK (uma estrutura WSK_REGISTRATION ) que será inicializado pelo WskRegister após o retorno bem-sucedido.

O exemplo de código a seguir mostra como um aplicativo WSK pode se registrar como um 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;
  }

  .
  . 
  .
}

Um aplicativo WSK não é necessário para chamar WskRegister de dentro de sua função DriverEntry . Por exemplo, se um aplicativo WSK for um subcomponente de um driver complexo, o registro do aplicativo poderá ocorrer somente quando o subcomponente do aplicativo WSK for ativado.

Um aplicativo WSK deve manter a estrutura WSK_CLIENT_DISPATCH passada para WskRegister válida e residente na memória até que WskDeregister seja chamado e o registro não seja mais válido. A estrutura WSK_REGISTRATION também deve ser mantida válida e residente na memória até que o aplicativo WSK pare de fazer chamadas para as outras funções de registro do WSK. O exemplo de código anterior mantém essas duas estruturas na seção de dados global do driver, mantendo assim os dados da estrutura residentes na memória até que o driver seja descarregado.

Captura de NPI do provedor WSK

Depois que um aplicativo WSK tiver se registrado como um cliente WSK com WskRegister, ele deverá usar a função WskCaptureProviderNPI para capturar o NPI do provedor WSK do subsistema WSK para começar a usar a interface WSK.

Como o subsistema WSK pode ainda não estar pronto quando um aplicativo WSK tenta capturar o NPI do provedor WSK, a função WskCaptureProviderNPI permite que o aplicativo WSK pesquise ou aguarde até que o subsistema WSK fique pronto da seguinte maneira:

  • Se o parâmetro WaitTimeout for WSK_NO_WAIT, a função sempre retornará imediatamente sem esperar.

  • Se WaitTimeout for WSK_INFINITE_WAIT, a função aguardará até que o subsistema WSK fique pronto.

  • Se WaitTimeout for qualquer outro valor, a função retornará quando o subsistema WSK ficar pronto ou quando o tempo de espera, em milissegundos, atingir o valor de WaitTimeout, o que ocorrer primeiro.

Importante Para evitar afetar negativamente o início de outros drivers e serviços, um aplicativo WSK que chama WskCaptureProviderNPI de sua função DriverEntry não deve definir o parâmetro WaitTimeout como WSK_INFINITE_WAIT ou um tempo de espera excessivo. Além disso, se um aplicativo WSK for iniciado muito cedo na fase de inicialização do sistema, ele deverá aguardar até que o subsistema WSK fique pronto em um thread de trabalho diferente do em que o DriverEntry é executado.

Se a chamada para WskCaptureProviderNPI falhar com STATUS_NOINTERFACE, o aplicativo WSK poderá usar a função WskQueryProviderCharacteristics para descobrir o intervalo de versões de NPI do WSK compatíveis com o subsistema WSK. O aplicativo WSK pode chamar WskDeregister para cancelar o registro de sua instância de registro atual e registrar-se novamente usando uma instância de WSK_CLIENT_DISPATCH diferente que usa uma versão de NPI do WSK com suporte.

Quando WskCaptureProviderNPI retorna com êxito, seu parâmetro WskProviderNpi aponta para um NPI do provedor WSK ( WSK_PROVIDER_NPI) pronto para uso pelo aplicativo WSK. A estrutura WSK_PROVIDER_NPI contém ponteiros para o objeto cliente WSK ( WSK_CLIENT) e a tabela de expedição WSK_PROVIDER_DISPATCH de funções WSK que o aplicativo WSK pode usar para criar soquetes WSK e executar outras operações no objeto cliente WSK. Depois que o aplicativo WSK for concluído usando as funções WSK_PROVIDER_DISPATCH, ele deverá liberar o NPI do provedor WSK chamando WskReleaseProviderNPI.

O exemplo de código a seguir mostra como um aplicativo WSK pode capturar o NPI do provedor WSK, usá-lo para criar um soquete e, em seguida, liberá-lo.

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

}

Um aplicativo WSK pode chamar WskCaptureProviderNPI mais de uma vez. Para cada chamada para WskCaptureProviderNPI que retorna com êxito, deve haver uma chamada correspondente para WskReleaseProviderNPI. Um aplicativo WSK não deve fazer mais chamadas para as funções em WSK_PROVIDER_DISPATCH depois de chamar WskReleaseProviderNPI.