Winsock Kernel's WskSocket function fails with STATUS_ACCESS_DENIED on raw socket

1

I am using Winsock Kernel in my driver to send raw socket packets to localhost. I found g_WskProvider.Dispatch->WskSocket method failed with STATUS_ACCESS_DENIED (0xC0000022).

00000807    17.18302345 --> NPF_WSKStartup  
00000808    17.18303871 <-- NPF_WSKStartup  
00000809    17.18304253 --> NPF_WSKInitSockets  
00000810    17.18304443 --> WSKCreateSocket 
00000811    17.18304825 --> InitWskData 
00000812    17.18305397 <-- InitWskData 
00000813    17.18307495 --> CompletionRoutine   
00000814    17.18307877 <-- CompletionRoutine   
00000815    17.18308640     WSKCreateSocket: WSKCreateSocket()::Dispatch::WskSocket() failed with status 0xC0000022 
00000816    17.18309021 <-- WSKCreateSocket 
00000817    17.18309593     NPF_WSKInitSockets: NPF_WSKInitSockets()::WSKCreateSocket() failed with status 0xC0000001   
00000818    17.18309975 <-- NPF_WSKInitSockets  

But I didn't specify any Security Descriptor things. Moreover, I have found this article: https://msdn.microsoft.com/en-us/library/windows/hardware/ff570806(v=vs.85).aspx, but it seems to be related to the TCP or UDP port is not available problem. However, what I used is raw socket, so no port issue I think. Additional, I used WSK_FLAG_DATAGRAM_SOCKET in the 5th parameter of the g_WskProvider.Dispatch->WskSocket call, I know this flag is for UDP, but I didn't find something like WSK_FLAG_RAW_SOCKET. So I have to use a UDP flag. I don't know whether this has any relationship with my error.

This error is found only on a portion of Windows 10 machines. On other Win10 and Win8 machines this problem didn't exist. There's no much difference between these machines. So it's hard to tell what's going wrong with this.

The entire code base is: https://github.com/nmap/npcap/blob/master/packetWin7/npf/npf/Lo_send.c

I pasted part of it here:

#ifdef HAVE_WFP_LOOPBACK_SUPPORT

#include "stdafx.h"

#include "Loopback.h"
#include "Lo_send.h"
#include "debug.h"

#define NPF_LOOPBACK_SEND_TYPE_IPV4     1
#define NPF_LOOPBACK_SEND_TYPE_IPV6     0

#define LOG_PORT                        3000
#define HTON_SHORT(n)                   (((((unsigned short)(n) & 0xFFu  )) << 8) | \
                                        (((unsigned short)(n) & 0xFF00u) >> 8))
#define HTON_LONG(x)                    (((((x)& 0xff)<<24) | ((x)>>24) & 0xff) | \
                                        (((x) & 0xff0000)>>8) | (((x) & 0xff00)<<8))

static WSK_REGISTRATION         g_WskRegistration;
static WSK_PROVIDER_NPI         g_WskProvider;
static WSK_CLIENT_DISPATCH      g_WskDispatch = { MAKE_WSK_VERSION(1, 0), 0, NULL };

PWSK_SOCKET                     g_IPv4Socket = NULL;
SOCKADDR_IN                     g_IPv4LocalAddress = { 0, };
SOCKADDR_IN                     g_IPv4RemoteAddress = { 0, };
PWSK_SOCKET                     g_IPv6Socket = NULL;
SOCKADDR_IN6                    g_IPv6LocalAddress = { 0, };
SOCKADDR_IN6                    g_IPv6RemoteAddress = { 0, };

enum
{
    DEINITIALIZED,
    DEINITIALIZING,
    INITIALIZING,
    INITIALIZED
};

static LONG g_SocketsState = DEINITIALIZED;


NTSTATUS
NTAPI
NPF_WSKInitSockets(
    )
{
    NTSTATUS        status = STATUS_SUCCESS;

    TRACE_ENTER();

    // IPv4 Socket Initialization
    g_IPv4Socket = WSKCreateSocket(AF_INET, SOCK_RAW, IPPROTO_NPCAP_LOOPBACK, WSK_FLAG_DATAGRAM_SOCKET);
    if (g_IPv4Socket == NULL)
    {
        status = STATUS_UNSUCCESSFUL;
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKCreateSocket() failed with status 0x%08X\n", status);
        TRACE_EXIT();
        return status;
    }

    g_IPv4LocalAddress.sin_family = AF_INET;
    g_IPv4LocalAddress.sin_addr.s_addr = INADDR_ANY;
    // g_IPv4LocalAddress.sin_port = INADDR_PORT;

    // Bind Required
    status = WSKBind(g_IPv4Socket, (PSOCKADDR) &g_IPv4LocalAddress);
    if (!NT_SUCCESS(status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKBind() failed with status 0x%08X\n", status);
        WSKCloseSocket(g_IPv4Socket);
        TRACE_EXIT();
        return status;
    }

    g_IPv4RemoteAddress.sin_family = AF_INET;
    g_IPv4RemoteAddress.sin_addr.s_addr = HTON_LONG(INADDR_LOOPBACK);
    // g_IPv4RemoteAddress.sin_port = HTON_SHORT(LOG_PORT);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // IPv6 Socket Initialization
    g_IPv6Socket = WSKCreateSocket(AF_INET6, SOCK_RAW, IPPROTO_NPCAP_LOOPBACK, WSK_FLAG_DATAGRAM_SOCKET);
    if (g_IPv6Socket == NULL)
    {
        status = STATUS_UNSUCCESSFUL;
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKCreateSocket() failed with status 0x%08X\n", status);
        TRACE_EXIT();
        return status;
    }

    g_IPv6LocalAddress.sin6_family = AF_INET6;
    struct in6_addr in6AnyAddr = IN6ADDR_ANY_INIT;
    g_IPv6LocalAddress.sin6_addr = in6AnyAddr;
    // g_IPv6LocalAddress.sin_port = INADDR_PORT;

    // Bind Required
    status = WSKBind(g_IPv6Socket, (PSOCKADDR) &g_IPv6LocalAddress);
    if (!NT_SUCCESS(status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKBind() failed with status 0x%08X\n", status);
        WSKCloseSocket(g_IPv6Socket);
        TRACE_EXIT();
        return status;
    }

    g_IPv6RemoteAddress.sin6_family = AF_INET6;
    struct in6_addr in6LoopbackAddr = IN6ADDR_LOOPBACK_INIT;
    g_IPv6RemoteAddress.sin6_addr = in6LoopbackAddr;
    // g_IPv6RemoteAddress.sin_port = HTON_SHORT(LOG_PORT);

    TRACE_EXIT();
    return status;
}

VOID
NTAPI
NPF_WSKFreeSockets(
    )
{
    TRACE_ENTER();

    if (g_IPv4Socket)
    {
        WSKCloseSocket(g_IPv4Socket);
        g_IPv4Socket = NULL;
    }

    if (g_IPv6Socket)
    {
        WSKCloseSocket(g_IPv6Socket);
        g_IPv6Socket = NULL;
    }

    TRACE_EXIT();
}

//
// Library initialization routine
//

NTSTATUS
NTAPI
NPF_WSKStartup(
    )
{
    WSK_CLIENT_NPI  WskClient = {0};
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (InterlockedCompareExchange(&g_SocketsState, INITIALIZING, DEINITIALIZED) != DEINITIALIZED)
        return STATUS_ALREADY_REGISTERED;

    WskClient.ClientContext = NULL;
    WskClient.Dispatch = &g_WskDispatch;

    Status = WskRegister(&WskClient, &g_WskRegistration);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKStartup()::WskRegister() failed with status 0x%08X\n", Status);
        InterlockedExchange(&g_SocketsState, DEINITIALIZED);
        TRACE_EXIT();
        return Status;
    }

    Status = WskCaptureProviderNPI(&g_WskRegistration, WSK_NO_WAIT, &g_WskProvider);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKStartup()::WskCaptureProviderNPI() failed with status 0x%08X\n", Status);
        WskDeregister(&g_WskRegistration);
        InterlockedExchange(&g_SocketsState, DEINITIALIZED);
        TRACE_EXIT();
        return Status;
    }

    InterlockedExchange(&g_SocketsState, INITIALIZED);
    TRACE_EXIT();
    return STATUS_SUCCESS;
}

//
// Library deinitialization routine
//

VOID
NTAPI
NPF_WSKCleanup(
    )
{
    TRACE_ENTER();
    if (InterlockedCompareExchange(&g_SocketsState, INITIALIZED, DEINITIALIZING) != INITIALIZED)
    {
        TRACE_EXIT();
        return;
    }

    WskReleaseProviderNPI(&g_WskRegistration);
    WskDeregister(&g_WskRegistration);

    InterlockedExchange(&g_SocketsState, DEINITIALIZED);
    TRACE_EXIT();
}

NTSTATUS
NTAPI
NPF_WSKSendPacket(
    IN PCHAR PacketBuff,
    IN ULONG BuffSize
    )
{
    PETHER_HEADER   pEthernetHdr = (PETHER_HEADER) PacketBuff;
    NTSTATUS        status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    PacketBuff = PacketBuff + ETHER_HDR_LEN;
    BuffSize = BuffSize - ETHER_HDR_LEN;

    if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IP))
    {
        status = WSKSendPacketInternal(NPF_LOOPBACK_SEND_TYPE_IPV4, PacketBuff, BuffSize);
    }
    else if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IPV6))
    {
        status = WSKSendPacketInternal(NPF_LOOPBACK_SEND_TYPE_IPV6, PacketBuff, BuffSize);
    }
    else
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket() failed with status 0x%08X, not valid loopback IPv4 or IPv6 packet\n", status);
    }

    TRACE_EXIT();
    return status;
}

NTSTATUS
NTAPI
WSKSendPacketInternal(
    IN BOOLEAN bIPv4,
    IN PCHAR PacketBuff,
    IN ULONG BuffSize
    )
{
    NTSTATUS        status = STATUS_SUCCESS;
    ULONG           SentBytes;

    TRACE_ENTER();

    SentBytes = bIPv4 ?
        WSKSendTo(g_IPv4Socket, PacketBuff, BuffSize, (PSOCKADDR)& g_IPv4RemoteAddress) :
        WSKSendTo(g_IPv6Socket, PacketBuff, BuffSize, (PSOCKADDR)& g_IPv6RemoteAddress);

    if (SentBytes != BuffSize)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendPacketInternal()::WSKSendTo() failed with SentBytes 0x%08X\n", SentBytes);
    }

    TRACE_EXIT();
    return status;
}

NTSTATUS
NTAPI
NPF_WSKSendPacket_NBL(
    IN PNET_BUFFER_LIST NetBufferList
    )
{
    PMDL            pMdl = NULL;
    ULONG           BuffSize;
    PETHER_HEADER   pEthernetHdr;
    NTSTATUS        status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    pMdl = NetBufferList->FirstNetBuffer->CurrentMdl;
    if (pMdl)
    {
        NdisQueryMdl(
            pMdl,
            &pEthernetHdr,
            &BuffSize,
            NormalPagePriority);
    }
    else
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL()::NetBufferList->FirstNetBuffer->CurrentMdl failed with pMdl 0x%08X\n", pMdl);

        TRACE_EXIT();
        return status;
    }

    if (pEthernetHdr == NULL)
    {
        //
        //  The system is low on resources. Set up to handle failure
        //  below.
        //
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL()::NdisQueryMdl() failed with pEthernetHdr 0x%08X\n", pEthernetHdr);

        TRACE_EXIT();
        return status;
    }

    if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IP))
    {
        status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV4, NetBufferList);
    }
    else if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IPV6))
    {
        status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV6, NetBufferList);
    }
    else
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL() failed with status 0x%08X, not valid loopback IPv4 or IPv6 packet\n", status);
    }

    TRACE_EXIT();
    return status;
}

NTSTATUS
NTAPI
WSKSendPacketInternal_NBL(
    IN BOOLEAN bIPv4,
    IN PNET_BUFFER_LIST NetBufferList
    )
{
    NTSTATUS        status = STATUS_SUCCESS;
    ULONG           SentBytes;

    TRACE_ENTER();

    SentBytes = bIPv4 ?
        WSKSendTo_NBL(g_IPv4Socket, NetBufferList, ETHER_HDR_LEN, (PSOCKADDR)& g_IPv4RemoteAddress) :
        WSKSendTo_NBL(g_IPv6Socket, NetBufferList, ETHER_HDR_LEN, (PSOCKADDR)& g_IPv6RemoteAddress);

    if (SentBytes != NetBufferList->FirstNetBuffer->DataLength - ETHER_HDR_LEN)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendPacketInternal_NBL()::WSKSendTo_NBL() failed with SentBytes 0x%08X\n", SentBytes);
    }

    TRACE_EXIT();
    return status;
}

static
NTSTATUS
NTAPI
CompletionRoutine(
IN PDEVICE_OBJECT       DeviceObject,
IN PIRP                   Irp,
IN PKEVENT                CompletionEvent
)
{
    ASSERT(CompletionEvent);

    UNREFERENCED_PARAMETER(Irp);
    UNREFERENCED_PARAMETER(DeviceObject);

    TRACE_ENTER();

    KeSetEvent(CompletionEvent, IO_NO_INCREMENT, FALSE);
    TRACE_EXIT();
    return STATUS_MORE_PROCESSING_REQUIRED;
}

static
NTSTATUS
InitWskData(
    OUT PIRP* pIrp,
    OUT PKEVENT CompletionEvent
    )
{
    ASSERT(pIrp);
    ASSERT(CompletionEvent);

    TRACE_ENTER();

    *pIrp = IoAllocateIrp(1, FALSE);
    if (!*pIrp)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "InitWskData()::IoAllocateIrp() failed with status 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    KeInitializeEvent(CompletionEvent, SynchronizationEvent, FALSE);
    IoSetCompletionRoutine(*pIrp, CompletionRoutine, CompletionEvent, TRUE, TRUE, TRUE);
    TRACE_EXIT();
    return STATUS_SUCCESS;
}

static
NTSTATUS
InitWskBuffer(
    IN PVOID Buffer,
    IN ULONG BufferSize,
    OUT PWSK_BUF WskBuffer
    )
{
    NTSTATUS Status = STATUS_SUCCESS;

    TRACE_ENTER();

    ASSERT(Buffer);
    ASSERT(BufferSize);
    ASSERT(WskBuffer);

    WskBuffer->Offset = 0;
    WskBuffer->Length = BufferSize;

    WskBuffer->Mdl = IoAllocateMdl(Buffer, BufferSize, FALSE, FALSE, NULL);
    if (!WskBuffer->Mdl)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "InitWskBuffer()::IoAllocateMdl() failed with status 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
        TRACE_EXIT();
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    __try
    {
        MmProbeAndLockPages(WskBuffer->Mdl, KernelMode, IoWriteAccess);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "InitWskBuffer()::MmProbeAndLockPages(%p) failed with status 0x%08X\n", Buffer, STATUS_ACCESS_VIOLATION);
        IoFreeMdl(WskBuffer->Mdl);
        Status = STATUS_ACCESS_VIOLATION;
    }

    TRACE_EXIT();
    return Status;
}

static
VOID
FreeWskBuffer(
    IN PWSK_BUF WskBuffer
    )
{
    ASSERT(WskBuffer);

    TRACE_ENTER();

    MmUnlockPages(WskBuffer->Mdl);
    IoFreeMdl(WskBuffer->Mdl);
    TRACE_EXIT();
}

static
NTSTATUS
InitWskBuffer_NBL(
    IN PNET_BUFFER_LIST NetBufferList,
    IN ULONG BufferOffset,
    OUT PWSK_BUF WskBuffer
    )
{
    NTSTATUS Status = STATUS_SUCCESS;

    TRACE_ENTER();

    ASSERT(NetBufferList);
    ASSERT(WskBuffer);

    WskBuffer->Offset = BufferOffset;
    WskBuffer->Length = NetBufferList->FirstNetBuffer->DataLength - BufferOffset;

    WskBuffer->Mdl = NetBufferList->FirstNetBuffer->CurrentMdl;
    if (!WskBuffer->Mdl)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "InitWskBuffer_NBL()::NetBufferList->FirstNetBuffer->CurrentMdl failed with status 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
        TRACE_EXIT();
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    __try
    {
        MmProbeAndLockPages(WskBuffer->Mdl, KernelMode, IoWriteAccess);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "InitWskBuffer_NBL()::MmProbeAndLockPages(%p) failed with status 0x%08X\n", WskBuffer->Mdl, STATUS_ACCESS_VIOLATION);
        Status = STATUS_ACCESS_VIOLATION;
    }

    TRACE_EXIT();
    return Status;
}

static
VOID
FreeWskBuffer_NBL(
    IN PWSK_BUF WskBuffer
    )
{
    ASSERT(WskBuffer);

    TRACE_ENTER();

    MmUnlockPages(WskBuffer->Mdl);
    TRACE_EXIT();
}

PWSK_SOCKET
NTAPI
WSKCreateSocket(
    IN ADDRESS_FAMILY AddressFamily,
    IN USHORT SocketType,
    IN ULONG Protocol,
    IN ULONG Flags
    )
{
    KEVENT                  CompletionEvent = { 0 };
    PIRP                    Irp = NULL;
    PWSK_SOCKET             WskSocket = NULL;
    NTSTATUS                Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (g_SocketsState != INITIALIZED)
    {
        TRACE_EXIT();
        return NULL;
    }

    Status = InitWskData(&Irp, &CompletionEvent);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCreateSocket()::InitWskData() failed with status 0x%08X\n", Status);
        TRACE_EXIT();
        return NULL;
    }

    Status = g_WskProvider.Dispatch->WskSocket(
        g_WskProvider.Client,
        AddressFamily,
        SocketType,
        Protocol,
        Flags,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }

    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCreateSocket()::Dispatch::WskSocket() failed with status 0x%08X\n", Status);
    }

    WskSocket = NT_SUCCESS(Status) ? (PWSK_SOCKET)Irp->IoStatus.Information : NULL;

    IoFreeIrp(Irp);
    TRACE_EXIT();
    return (PWSK_SOCKET)WskSocket;
}

NTSTATUS
NTAPI
WSKCloseSocket(
    IN PWSK_SOCKET WskSocket
    )
{
    KEVENT          CompletionEvent = { 0 };
    PIRP            Irp = NULL;
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (g_SocketsState != INITIALIZED || !WskSocket)
    {
        TRACE_EXIT();
        return STATUS_INVALID_PARAMETER;
    }

    Status = InitWskData(&Irp, &CompletionEvent);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCloseSocket()::InitWskData() failed with status 0x%08X\n", Status);
        TRACE_EXIT();
        return Status;
    }

    Status = ((PWSK_PROVIDER_BASIC_DISPATCH)WskSocket->Dispatch)->WskCloseSocket(WskSocket, Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }
    else if (Status != STATUS_SUCCESS)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCloseSocket()::Dispatch::WskSocket() failed with status 0x%08X\n", Status);
    }

    IoFreeIrp(Irp);
    TRACE_EXIT();
    return Status;
}

LONG
NTAPI
WSKSend(
    IN PWSK_SOCKET WskSocket,
    IN PVOID Buffer,
    IN ULONG BufferSize,
    IN ULONG Flags
    )
{
    KEVENT          CompletionEvent = { 0 };
    PIRP            Irp = NULL;
    WSK_BUF         WskBuffer = { 0 };
    LONG            BytesSent = SOCKET_ERROR;
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize)
    {
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSend()::InitWskBuffer() failed with status 0x%08X\n", Status);
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = InitWskData(&Irp, &CompletionEvent);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSend()::InitWskData() failed with status 0x%08X\n", Status);
        FreeWskBuffer(&WskBuffer);
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch)->WskSend(
        WskSocket,
        &WskBuffer,
        Flags,
        Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }
    else if (Status != STATUS_SUCCESS)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSend()::Dispatch::WskSend() failed with status 0x%08X\n", Status);
    }

    BytesSent = NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;

    IoFreeIrp(Irp);
    FreeWskBuffer(&WskBuffer);
    TRACE_EXIT();
    return BytesSent;
}

LONG
NTAPI
WSKSendTo(
    IN PWSK_SOCKET WskSocket,
    IN PVOID Buffer,
    IN ULONG BufferSize,
    __in_opt PSOCKADDR RemoteAddress
    )
{
    KEVENT          CompletionEvent = { 0 };
    PIRP            Irp = NULL;
    WSK_BUF         WskBuffer = { 0 };
    LONG            BytesSent = SOCKET_ERROR;
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize)
    {
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo()::InitWskBuffer() failed with status 0x%08X\n", Status);
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = InitWskData(&Irp, &CompletionEvent);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo()::InitWskData() failed with status 0x%08X\n", Status);
        FreeWskBuffer(&WskBuffer);
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = ((PWSK_PROVIDER_DATAGRAM_DISPATCH)WskSocket->Dispatch)->WskSendTo(
        WskSocket,
        &WskBuffer,
        0,
        RemoteAddress,
        0,
        NULL,
        Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }
    else if (Status != STATUS_SUCCESS)
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo()::Dispatch::WskSendTo() failed with status 0x%08X\n", Status);
    }

    BytesSent = NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;

    IoFreeIrp(Irp);
    FreeWskBuffer(&WskBuffer);
    TRACE_EXIT();
    return BytesSent;
}

LONG
NTAPI
WSKSendTo_NBL(
    IN PWSK_SOCKET WskSocket,
    IN PNET_BUFFER_LIST NetBufferList,
    IN ULONG BufferOffset,
    __in_opt PSOCKADDR RemoteAddress
    )
{
    KEVENT          CompletionEvent = { 0 };
    PIRP            Irp = NULL;
    WSK_BUF         WskBuffer = { 0 };
    LONG            BytesSent = SOCKET_ERROR;
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (g_SocketsState != INITIALIZED || !WskSocket || !NetBufferList)
    {
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = InitWskBuffer_NBL(NetBufferList, BufferOffset, &WskBuffer);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo_NBL()::InitWskBuffer_NBL() failed with status 0x%08X\n", Status);
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = InitWskData(&Irp, &CompletionEvent);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo_NBL()::InitWskData() failed with status 0x%08X\n", Status);
        FreeWskBuffer_NBL(&WskBuffer);
        TRACE_EXIT();
        return SOCKET_ERROR;
    }

    Status = ((PWSK_PROVIDER_DATAGRAM_DISPATCH)WskSocket->Dispatch)->WskSendTo(
        WskSocket,
        &WskBuffer,
        0,
        RemoteAddress,
        0,
        NULL,
        Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }

    BytesSent = NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;

    IoFreeIrp(Irp);
    FreeWskBuffer_NBL(&WskBuffer);
    TRACE_EXIT();
    return BytesSent;
}

NTSTATUS
NTAPI
WSKBind(
    IN PWSK_SOCKET WskSocket,
    IN PSOCKADDR LocalAddress
    )
{
    KEVENT          CompletionEvent = { 0 };
    PIRP            Irp = NULL;
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    TRACE_ENTER();

    if (g_SocketsState != INITIALIZED || !WskSocket || !LocalAddress)
    {
        TRACE_EXIT();
        return STATUS_INVALID_PARAMETER;
    }

    Status = InitWskData(&Irp, &CompletionEvent);
    if (!NT_SUCCESS(Status))
    {
        TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKBind()::InitWskData() failed with status 0x%08X\n", Status);
        TRACE_EXIT();
        return Status;
    }

    Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch)->WskBind(
        WskSocket,
        LocalAddress,
        0,
        Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }

    IoFreeIrp(Irp);
    TRACE_EXIT();
    return Status;
}

#endif // HAVE_WFP_LOOPBACK_SUPPORT
c
windows
sockets
driver
winsock
asked on Stack Overflow Aug 18, 2015 by Yang Luo

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0