aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2022-08-31 01:17:10 +0200
committerToni Uhlig <matzeton@googlemail.com>2022-08-31 01:17:10 +0200
commit7b42d7f3415149005b05b7b5ea14fca6cb01a261 (patch)
tree0e3ffae3c4bdbe731c199ebff31c3482ace7f722
initial commit
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r--Makefile48
-rw-r--r--README.md14
-rw-r--r--berkeley.c580
-rw-r--r--berkeley.h38
-rw-r--r--driver.bat27
-rw-r--r--driver.cpp116
-rw-r--r--ksocket.c700
-rw-r--r--ksocket.h165
-rw-r--r--userspace_client.cpp78
-rw-r--r--wsk.h456
10 files changed, 2222 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..08126f7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,48 @@
+ifndef DPP_ROOT
+$(error DPP_ROOT is undefined)
+endif
+
+include $(DPP_ROOT)/Makefile.inc
+
+DRIVER_NAME = driver
+DRIVER_OBJECTS = $(DRIVER_NAME).o ksocket.o berkeley.o
+DRIVER_TARGET = $(DRIVER_NAME).sys
+DRIVER_CFLAGS = -I. -Wl,--exclude-all-symbols
+
+USERSPACE_NAME = userspace_client
+USERSPACE_OBJECTS = $(USERSPACE_NAME).o
+USERSPACE_TARGET = $(USERSPACE_NAME).exe
+
+# mingw-w64-ddk-template related
+CFLAGS += $(DRIVER_CFLAGS)
+DRIVER_LIBS += -lnetio
+USER_LIBS += -lws2_32
+
+all: $(DRIVER_TARGET) $(USERSPACE_TARGET)
+
+%.o: %.cpp
+ $(call BUILD_CPP_OBJECT,$<,$@)
+
+%.o: %.c
+ $(call BUILD_C_OBJECT,$<,$@)
+
+$(DRIVER_TARGET): $(DRIVER_OBJECTS)
+ $(call LINK_CPP_KERNEL_TARGET,$(DRIVER_OBJECTS),$@)
+
+$(USERSPACE_TARGET): $(USERSPACE_OBJECTS)
+ $(call LINK_CPP_USER_TARGET,$(USERSPACE_OBJECTS),$@)
+
+install: $(DRIVER_TARGET) $(USERSPACE_TARGET)
+ $(call INSTALL_EXEC_SIGN,$(DRIVER_TARGET))
+ $(call INSTALL_EXEC,$(USERSPACE_TARGET))
+ $(INSTALL) '$(DRIVER_NAME).bat' '$(DESTDIR)/'
+
+clean:
+ rm -f $(DRIVER_OBJECTS)
+ rm -f $(DRIVER_TARGET) $(DRIVER_TARGET).map
+ rm -f $(USERSPACE_OBJECTS)
+ rm -f $(USERSPACE_TARGET)
+
+.NOTPARALLEL: clean
+.PHONY: all install clean
+.DEFAULT_GOAL := all
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..26f2bbd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+# Mingw64 C++ Kernel Sockets
+
+Requires [mingw-w64-dpp](https://github.com/utoni/mingw-w64-dpp).
+
+Did you ever ask yourself the question: how-the-hell can I open a socket in kernel mode with a Mingw-w64 compiled driver?
+Well, this is the solution. `mingw-w64-ksocket` simplifies the use of stream/datagram client/server sockets.
+The API is similiar to the BSD socket API.
+Greetings to [KSOCKET](https://github.com/wbenny/KSOCKET) for this sweet approach.
+
+# HowTo
+
+```shell
+make -C . DPP_ROOT="[path-to-mingw-w64-ddk-template-dir]" clean all
+```
diff --git a/berkeley.c b/berkeley.c
new file mode 100644
index 0000000..e72f92e
--- /dev/null
+++ b/berkeley.c
@@ -0,0 +1,580 @@
+#include "berkeley.h"
+#include "ksocket.h"
+
+//////////////////////////////////////////////////////////////////////////
+// Definitions.
+//////////////////////////////////////////////////////////////////////////
+
+#define MEMORY_TAG ((ULONG)0x2e2e4242)
+#define SOCKETFD_MAX 128
+#define TO_SOCKETFD(index) ((index % SOCKETFD_MAX) + 0)
+#define FROM_SOCKETFD(sockfd) ((sockfd)-0)
+
+//////////////////////////////////////////////////////////////////////////
+// Function prototypes.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoToAddrInfoEx(_In_ PADDRINFOA AddrInfo,
+ _Out_ PADDRINFOEXW *AddrInfoEx);
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoExToAddrInfo(_In_ PADDRINFOEXW AddrInfoEx,
+ _Out_ PADDRINFOA *AddrInfo);
+
+VOID NTAPI KspUtilFreeAddrInfo(_In_ PADDRINFOA AddrInfo);
+
+VOID NTAPI KspUtilFreeAddrInfoEx(_In_ PADDRINFOEXW AddrInfo);
+
+//////////////////////////////////////////////////////////////////////////
+// Variables.
+//////////////////////////////////////////////////////////////////////////
+
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// This is complete bollocks and ideally it should be replaced with
+// something like RTL_AVL_TABLE.
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+
+PKSOCKET KsArray[SOCKETFD_MAX] = {0};
+ULONG KsIndex = 0;
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoToAddrInfoEx(_In_ PADDRINFOA AddrInfo,
+ _Out_ PADDRINFOEXW *AddrInfoEx) {
+ NTSTATUS Status;
+
+ //
+ // Convert NULL input into NULL output.
+ //
+
+ if (AddrInfo == NULL) {
+ *AddrInfoEx = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Allocate memory for the output structure.
+ //
+
+ PADDRINFOEXW Result =
+ ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOEXW), MEMORY_TAG);
+
+ if (Result == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error1;
+ }
+
+ //
+ // Copy numeric values.
+ //
+
+ RtlZeroMemory(Result, sizeof(ADDRINFOEXW));
+ Result->ai_flags = AddrInfo->ai_flags;
+ Result->ai_family = AddrInfo->ai_family;
+ Result->ai_socktype = AddrInfo->ai_socktype;
+ Result->ai_protocol = AddrInfo->ai_protocol;
+ Result->ai_addrlen = AddrInfo->ai_addrlen;
+
+ //
+ // Copy canonical name.
+ //
+
+ ANSI_STRING CanonicalNameAnsi;
+ UNICODE_STRING CanonicalNameUnicode;
+
+ if (AddrInfo->ai_canonname) {
+ RtlInitAnsiString(&CanonicalNameAnsi, AddrInfo->ai_canonname);
+
+ Status = RtlAnsiStringToUnicodeString(&CanonicalNameUnicode,
+ &CanonicalNameAnsi, TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error2;
+ }
+
+ Result->ai_canonname = CanonicalNameUnicode.Buffer;
+ }
+
+ //
+ // Copy address.
+ //
+
+ Result->ai_addr = AddrInfo->ai_addr;
+
+ //
+ // Copy the next structure (recursively).
+ //
+
+ PADDRINFOEXW NextAddrInfo;
+ Status = KspUtilAddrInfoToAddrInfoEx(AddrInfo->ai_next, &NextAddrInfo);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ Result->ai_next = NextAddrInfo;
+
+ //
+ // All done!
+ //
+
+ *AddrInfoEx = Result;
+
+ return Status;
+
+Error3:
+ RtlFreeAnsiString(&CanonicalNameAnsi);
+
+Error2:
+ ExFreePoolWithTag(Result, MEMORY_TAG);
+
+Error1:
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoExToAddrInfo(_In_ PADDRINFOEXW AddrInfoEx,
+ _Out_ PADDRINFOA *AddrInfo) {
+ NTSTATUS Status;
+
+ //
+ // Convert NULL input into NULL output.
+ //
+
+ if (AddrInfoEx == NULL) {
+ *AddrInfo = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Allocate memory for the output structure.
+ //
+
+ PADDRINFOA Result =
+ ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOA), MEMORY_TAG);
+
+ if (Result == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error1;
+ }
+
+ //
+ // Copy numeric values.
+ //
+
+ RtlZeroMemory(Result, sizeof(ADDRINFOA));
+ Result->ai_flags = AddrInfoEx->ai_flags;
+ Result->ai_family = AddrInfoEx->ai_family;
+ Result->ai_socktype = AddrInfoEx->ai_socktype;
+ Result->ai_protocol = AddrInfoEx->ai_protocol;
+ Result->ai_addrlen = AddrInfoEx->ai_addrlen;
+
+ //
+ // Copy canonical name.
+ //
+
+ UNICODE_STRING CanonicalNameUnicode;
+ ANSI_STRING CanonicalNameAnsi;
+
+ if (AddrInfoEx->ai_canonname) {
+ RtlInitUnicodeString(&CanonicalNameUnicode, AddrInfoEx->ai_canonname);
+ Status = RtlUnicodeStringToAnsiString(&CanonicalNameAnsi,
+ &CanonicalNameUnicode, TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error2;
+ }
+
+ Result->ai_canonname = CanonicalNameAnsi.Buffer;
+ }
+
+ //
+ // Copy address.
+ //
+
+ Result->ai_addr = AddrInfoEx->ai_addr;
+
+ //
+ // Copy the next structure (recursively).
+ //
+
+ PADDRINFOA NextAddrInfo;
+ Status = KspUtilAddrInfoExToAddrInfo(AddrInfoEx->ai_next, &NextAddrInfo);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ Result->ai_next = NextAddrInfo;
+
+ //
+ // All done!
+ //
+
+ *AddrInfo = Result;
+
+ return Status;
+
+Error3:
+ RtlFreeAnsiString(&CanonicalNameAnsi);
+
+Error2:
+ ExFreePoolWithTag(Result, MEMORY_TAG);
+
+Error1:
+ return Status;
+}
+
+VOID NTAPI KspUtilFreeAddrInfo(_In_ PADDRINFOA AddrInfo) {
+ //
+ // Free all structures recursively.
+ //
+
+ if (AddrInfo->ai_next) {
+ KspUtilFreeAddrInfo(AddrInfo->ai_next);
+ }
+
+ //
+ // Free the canonical name buffer.
+ //
+
+ if (AddrInfo->ai_canonname) {
+ ANSI_STRING CanonicalName;
+ RtlInitAnsiString(&CanonicalName, AddrInfo->ai_canonname);
+ RtlFreeAnsiString(&CanonicalName);
+ }
+
+ //
+ // Finally, free the structure itself.
+ //
+
+ ExFreePoolWithTag(AddrInfo, MEMORY_TAG);
+}
+
+VOID NTAPI KspUtilFreeAddrInfoEx(_In_ PADDRINFOEXW AddrInfo) {
+ //
+ // Free all structures recursively.
+ //
+
+ if (AddrInfo->ai_next) {
+ KspUtilFreeAddrInfoEx(AddrInfo->ai_next);
+ }
+
+ //
+ // Free the canonical name buffer.
+ //
+
+ if (AddrInfo->ai_canonname) {
+ UNICODE_STRING CanonicalName;
+ RtlInitUnicodeString(&CanonicalName, AddrInfo->ai_canonname);
+ RtlFreeUnicodeString(&CanonicalName);
+ }
+
+ //
+ // Finally, free the structure itself.
+ //
+
+ ExFreePoolWithTag(AddrInfo, MEMORY_TAG);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Public functions.
+//////////////////////////////////////////////////////////////////////////
+
+uint32_t htonl(uint32_t hostlong) { return __builtin_bswap32(hostlong); }
+
+uint16_t htons(uint16_t hostshort) { return __builtin_bswap16(hostshort); }
+
+uint32_t ntohl(uint32_t netlong) { return __builtin_bswap32(netlong); }
+
+uint16_t ntohs(uint16_t netshort) { return __builtin_bswap16(netshort); }
+
+int getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res) {
+ NTSTATUS Status;
+
+ //
+ // Convert node name to the UNICODE_STRING (if present).
+ //
+
+ ANSI_STRING NodeNameAnsi;
+ UNICODE_STRING NodeNameUnicode;
+ PUNICODE_STRING NodeName = NULL;
+
+ if (node) {
+ RtlInitAnsiString(&NodeNameAnsi, node);
+ Status =
+ RtlAnsiStringToUnicodeString(&NodeNameUnicode, &NodeNameAnsi, TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error1;
+ }
+
+ NodeName = &NodeNameUnicode;
+ }
+
+ //
+ // Convert service name to the UNICODE_STRING (if present).
+ //
+
+ ANSI_STRING ServiceNameAnsi;
+ UNICODE_STRING ServiceNameUnicode;
+ PUNICODE_STRING ServiceName = NULL;
+
+ if (service) {
+ RtlInitAnsiString(&ServiceNameAnsi, service);
+ Status = RtlAnsiStringToUnicodeString(&ServiceNameUnicode, &ServiceNameAnsi,
+ TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error2;
+ }
+
+ ServiceName = &ServiceNameUnicode;
+ }
+
+ //
+ // Convert "struct addrinfo" to the "ADDRINFOEXW".
+ //
+
+ PADDRINFOEXW Hints;
+ Status = KspUtilAddrInfoToAddrInfoEx((PADDRINFOA)hints, &Hints);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ //
+ // All data is prepared, call the underlying API.
+ //
+
+ PADDRINFOEXW Result;
+ Status = KsGetAddrInfo(NodeName, ServiceName, Hints, &Result);
+
+ //
+ // Free the memory of the converted "Hints".
+ //
+
+ KspUtilFreeAddrInfoEx(Hints);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ //
+ // Convert the result "ADDRINFOEXW" to the "struct addrinfo".
+ //
+
+ Status = KspUtilAddrInfoExToAddrInfo(Result, res);
+
+ //
+ // Free the original result.
+ //
+
+ KsFreeAddrInfo(Result);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ return STATUS_SUCCESS;
+
+Error3:
+ RtlFreeUnicodeString(&ServiceNameUnicode);
+
+Error2:
+ RtlFreeUnicodeString(&NodeNameUnicode);
+
+Error1:
+ return Status;
+}
+
+void freeaddrinfo(struct addrinfo *res) {
+ //
+ // Call our implementation.
+ //
+
+ KspUtilFreeAddrInfo(res);
+}
+
+int socket_connection(int domain, int type, int protocol) {
+ NTSTATUS Status;
+ PKSOCKET Socket;
+
+ Status = KsCreateConnectionSocket(&Socket, (ADDRESS_FAMILY)domain,
+ (USHORT)type, (ULONG)protocol);
+
+ if (NT_SUCCESS(Status)) {
+ int sockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = Socket;
+
+ return sockfd;
+ }
+
+ return -1;
+}
+
+int socket_listen(int domain, int type, int protocol) {
+ NTSTATUS Status;
+ PKSOCKET Socket;
+
+ //
+ // WskSocket() returns STATUS_PROTOCOL_UNREACHABLE (0xC000023E)
+ // when Protocol == 0, so coerce this value to IPPROTO_TCP here.
+ //
+
+ Status = KsCreateListenSocket(&Socket, (ADDRESS_FAMILY)domain, (USHORT)type,
+ protocol ? (ULONG)protocol : IPPROTO_TCP);
+
+ if (NT_SUCCESS(Status)) {
+ int sockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = Socket;
+
+ return sockfd;
+ }
+
+ return -1;
+}
+
+int socket_datagram(int domain, int type, int protocol) {
+ NTSTATUS Status;
+ PKSOCKET Socket;
+
+ Status = KsCreateDatagramSocket(&Socket, (ADDRESS_FAMILY)domain, (USHORT)type,
+ (ULONG)protocol);
+
+ if (NT_SUCCESS(Status)) {
+ int sockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = Socket;
+
+ return sockfd;
+ }
+
+ return -1;
+}
+
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ Status = KsConnect(Socket, (PSOCKADDR)addr);
+
+ return NT_SUCCESS(Status) ? 0 : -1;
+}
+
+int listen(int sockfd, int backlog) {
+ UNREFERENCED_PARAMETER(sockfd);
+ UNREFERENCED_PARAMETER(backlog);
+ return 0;
+}
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ Status = KsBind(Socket, (PSOCKADDR)addr);
+
+ return NT_SUCCESS(Status) ? 0 : -1;
+}
+
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ PKSOCKET NewSocket;
+ Status = KsAccept(Socket, &NewSocket, NULL, (PSOCKADDR)addr);
+ *addrlen = sizeof(SOCKADDR);
+
+ if (NT_SUCCESS(Status)) {
+ int newsockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(newsockfd)] = NewSocket;
+
+ return newsockfd;
+ }
+
+ return -1;
+}
+
+int send(int sockfd, const void *buf, size_t len, int flags) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status = KsSend(Socket, (PVOID)buf, &Length, (ULONG)flags);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int sendto(int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status =
+ KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)dest_addr);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int recv(int sockfd, void *buf, size_t len, int flags) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status = KsRecv(Socket, (PVOID)buf, &Length, (ULONG)flags);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int recvfrom(int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status =
+ KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)src_addr);
+ *addrlen = sizeof(SOCKADDR);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int closesocket(int sockfd) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ Status = KsCloseSocket(Socket);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = NULL;
+
+ return NT_SUCCESS(Status) ? 0 : -1;
+}
diff --git a/berkeley.h b/berkeley.h
new file mode 100644
index 0000000..75cdb0f
--- /dev/null
+++ b/berkeley.h
@@ -0,0 +1,38 @@
+#pragma once
+#include <ntddk.h>
+#include <wsk.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int socklen_t;
+typedef intptr_t ssize_t;
+
+uint32_t htonl(uint32_t hostlong);
+uint16_t htons(uint16_t hostshort);
+uint32_t ntohl(uint32_t netlong);
+uint16_t ntohs(uint16_t netshort);
+
+int getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res);
+void freeaddrinfo(struct addrinfo *res);
+
+int socket_connection(int domain, int type, int protocol);
+int socket_listen(int domain, int type, int protocol);
+int socket_datagram(int domain, int type, int protocol);
+int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
+int listen(int sockfd, int backlog);
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+int send(int sockfd, const void* buf, size_t len, int flags);
+int sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
+int recv(int sockfd, void* buf, size_t len, int flags);
+int recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
+int closesocket(int sockfd);
+
+#define socket socket_connection
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/driver.bat b/driver.bat
new file mode 100644
index 0000000..519d9e8
--- /dev/null
+++ b/driver.bat
@@ -0,0 +1,27 @@
+@echo off
+set SERVICE_NAME=ksocket
+set DRIVER="%~dp0\driver.sys"
+
+net session >nul 2>&1
+if NOT %ERRORLEVEL% EQU 0 (
+ echo ERROR: This script requires Administrator privileges!
+ pause
+ exit /b 1
+)
+
+echo ---------------------------------------
+echo -- Service Name: %SERVICE_NAME%
+echo -- Driver......: %DRIVER%
+echo ---------------------------------------
+
+sc create %SERVICE_NAME% binPath= %DRIVER% type= kernel
+echo ---------------------------------------
+sc start %SERVICE_NAME%
+echo ---------------------------------------
+sc query %SERVICE_NAME%
+echo [PRESS A KEY TO STOP THE DRIVER]
+pause
+sc stop %SERVICE_NAME%
+sc delete %SERVICE_NAME%
+echo Done.
+timeout /t 3
diff --git a/driver.cpp b/driver.cpp
new file mode 100644
index 0000000..005468d
--- /dev/null
+++ b/driver.cpp
@@ -0,0 +1,116 @@
+
+extern "C" {
+#include "berkeley.h"
+#include "ksocket.h"
+#include "wsk.h"
+
+DRIVER_INITIALIZE DriverEntry;
+DRIVER_UNLOAD DriverUnload;
+
+#define DebuggerPrint(...) \
+ DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__);
+
+NTSTATUS
+NTAPI
+DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath) {
+ UNREFERENCED_PARAMETER(DriverObject);
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ NTSTATUS Status;
+
+ //
+ // Initialize KSOCKET.
+ //
+
+ Status = KsInitialize();
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Client.
+ // Perform HTTP request to http://httpbin.org/uuid
+ //
+
+ {
+ int result;
+ UNREFERENCED_PARAMETER(result);
+
+ char send_buffer[] = "GET /uuid HTTP/1.1\r\n"
+ "Host: httpbin.org\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ char recv_buffer[1024] = {};
+
+ struct addrinfo hints = {};
+ hints.ai_flags |= AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ struct addrinfo *res;
+ result = getaddrinfo("httpbin.org", "80", &hints, &res);
+
+ int sockfd;
+ sockfd = socket_connection(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ result = connect(sockfd, res->ai_addr, (int)res->ai_addrlen);
+ result = send(sockfd, send_buffer, sizeof(send_buffer), 0);
+ result = recv(sockfd, recv_buffer, sizeof(recv_buffer), 0);
+ recv_buffer[sizeof(recv_buffer) - 1] = '\0';
+
+ DebuggerPrint("TCP client:\n%s\n", recv_buffer);
+
+ closesocket(sockfd);
+ }
+
+ //
+ // TCP server.
+ // Listen on port 9095, wait for some message,
+ // then send our buffer and close connection.
+ //
+
+ {
+ int result;
+ UNREFERENCED_PARAMETER(result);
+
+ char send_buffer[] = "Hello from WSK!";
+ char recv_buffer[1024] = {0};
+
+ int server_sockfd = socket_listen(AF_INET, SOCK_STREAM, 0);
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(9095);
+
+ result = bind(server_sockfd, (struct sockaddr *)&addr, sizeof(addr));
+ result = listen(server_sockfd, 1);
+
+ socklen_t addrlen = sizeof(addr);
+ int client_sockfd =
+ accept(server_sockfd, (struct sockaddr *)&addr, &addrlen);
+
+ result = recv(client_sockfd, recv_buffer, sizeof(recv_buffer) - 1, 0);
+ recv_buffer[sizeof(recv_buffer) - 1] = '\0';
+
+ DebuggerPrint("TCP server:\n%s\n", recv_buffer);
+
+ result = send(client_sockfd, send_buffer, sizeof(send_buffer), 0);
+
+ closesocket(client_sockfd);
+ closesocket(server_sockfd);
+ }
+
+ KsDestroy();
+
+ return STATUS_SUCCESS;
+}
+
+VOID DriverUnload(_In_ struct _DRIVER_OBJECT *DriverObject) {
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ DebuggerPrint("Bye.");
+}
+}
diff --git a/ksocket.c b/ksocket.c
new file mode 100644
index 0000000..5262333
--- /dev/null
+++ b/ksocket.c
@@ -0,0 +1,700 @@
+#include "ksocket.h"
+
+//////////////////////////////////////////////////////////////////////////
+// Definitions.
+//////////////////////////////////////////////////////////////////////////
+
+#define MEMORY_TAG ((ULONG)0x2e2e4142)
+
+//////////////////////////////////////////////////////////////////////////
+// Structures.
+//////////////////////////////////////////////////////////////////////////
+
+typedef struct _KSOCKET_ASYNC_CONTEXT {
+ KEVENT CompletionEvent;
+ PIRP Irp;
+} KSOCKET_ASYNC_CONTEXT, *PKSOCKET_ASYNC_CONTEXT;
+
+typedef struct _KSOCKET {
+ PWSK_SOCKET WskSocket;
+
+ union {
+ PVOID WskDispatch;
+
+ PWSK_PROVIDER_CONNECTION_DISPATCH WskConnectionDispatch;
+ PWSK_PROVIDER_LISTEN_DISPATCH WskListenDispatch;
+ PWSK_PROVIDER_DATAGRAM_DISPATCH WskDatagramDispatch;
+#if (NTDDI_VERSION >= NTDDI_WIN10_RS2)
+ PWSK_PROVIDER_STREAM_DISPATCH WskStreamDispatch;
+#endif
+ };
+
+ KSOCKET_ASYNC_CONTEXT AsyncContext;
+} KSOCKET, *PKSOCKET;
+
+//////////////////////////////////////////////////////////////////////////
+// Variables.
+//////////////////////////////////////////////////////////////////////////
+
+WSK_REGISTRATION WskRegistration;
+WSK_PROVIDER_NPI WskProvider;
+WSK_CLIENT_DISPATCH WskDispatch = {MAKE_WSK_VERSION(1, 0), 0, NULL};
+
+//////////////////////////////////////////////////////////////////////////
+// Function prototypes.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspAsyncContextAllocate(_Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext);
+
+VOID NTAPI KspAsyncContextFree(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext);
+
+VOID NTAPI KspAsyncContextReset(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext);
+
+static NTSTATUS
+KspAsyncContextCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp, _In_ PVOID CompletionEvent);
+
+NTSTATUS
+NTAPI
+KspAsyncContextWaitForCompletion(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext,
+ _Inout_ PNTSTATUS Status);
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspAsyncContextAllocate(_Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext) {
+ //
+ // Initialize the completion event.
+ //
+
+ KeInitializeEvent(&AsyncContext->CompletionEvent, SynchronizationEvent,
+ FALSE);
+
+ //
+ // Initialize the IRP.
+ //
+
+ AsyncContext->Irp = IoAllocateIrp(1, FALSE);
+
+ if (AsyncContext->Irp == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // KspAsyncContextCompletionRoutine will set
+ // the CompletionEvent.
+ //
+
+ IoSetCompletionRoutine(AsyncContext->Irp, &KspAsyncContextCompletionRoutine,
+ &AsyncContext->CompletionEvent, TRUE, TRUE, TRUE);
+
+ return STATUS_SUCCESS;
+}
+
+VOID NTAPI KspAsyncContextFree(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext) {
+ //
+ // Free the IRP.
+ //
+
+ IoFreeIrp(AsyncContext->Irp);
+}
+
+VOID NTAPI KspAsyncContextReset(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext) {
+ //
+ // If the WSK application allocated the IRP, or is reusing an IRP
+ // that it previously allocated, then it must set an IoCompletion
+ // routine for the IRP before calling a WSK function. In this
+ // situation, the WSK application must specify TRUE for the
+ // InvokeOnSuccess, InvokeOnError, and InvokeOnCancel parameters that
+ // are passed to the IoSetCompletionRoutine function to ensure that
+ // the IoCompletion routine is always called. Furthermore, the IoCompletion
+ // routine that is set for the IRP must always return
+ // STATUS_MORE_PROCESSING_REQUIRED to terminate the completion processing
+ // of the IRP. If the WSK application is done using the IRP after the
+ // IoCompletion routine has been called, then it should call the IoFreeIrp
+ // function to free the IRP before returning from the IoCompletion routine.
+ // If the WSK application does not free the IRP then it can reuse the IRP
+ // for a call to another WSK function.
+ //
+ // (ref:
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/network/using-irps-with-winsock-kernel-functions)
+ //
+
+ //
+ // Reset the completion event.
+ //
+
+ KeResetEvent(&AsyncContext->CompletionEvent);
+
+ //
+ // Reuse the IRP.
+ //
+
+ IoReuseIrp(AsyncContext->Irp, STATUS_UNSUCCESSFUL);
+
+ IoSetCompletionRoutine(AsyncContext->Irp, &KspAsyncContextCompletionRoutine,
+ &AsyncContext->CompletionEvent, TRUE, TRUE, TRUE);
+}
+
+static NTSTATUS
+KspAsyncContextCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp, _In_ PVOID CompletionEvent) {
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent((PKEVENT)CompletionEvent, IO_NO_INCREMENT, FALSE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+KspAsyncContextWaitForCompletion(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext,
+ _Inout_ PNTSTATUS Status) {
+ if (*Status == STATUS_PENDING) {
+ KeWaitForSingleObject(&AsyncContext->CompletionEvent, Executive, KernelMode,
+ FALSE, NULL);
+
+ *Status = AsyncContext->Irp->IoStatus.Status;
+ }
+
+ return *Status;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Public functions.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KsInitialize(VOID) {
+ NTSTATUS Status;
+
+ //
+ // Register as a WSK client.
+ //
+
+ WSK_CLIENT_NPI WskClient;
+ WskClient.ClientContext = NULL;
+ WskClient.Dispatch = &WskDispatch;
+
+ Status = WskRegister(&WskClient, &WskRegistration);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Capture the provider NPI.
+ //
+
+ return WskCaptureProviderNPI(&WskRegistration, WSK_INFINITE_WAIT,
+ &WskProvider);
+}
+
+VOID NTAPI KsDestroy(VOID) {
+ //
+ // Release the provider NPI instance.
+ //
+
+ WskReleaseProviderNPI(&WskRegistration);
+
+ //
+ // Deregister as a WSK client.
+ //
+
+ WskDeregister(&WskRegistration);
+}
+
+NTSTATUS
+NTAPI
+KsGetAddrInfo(_In_ PUNICODE_STRING NodeName, _In_ PUNICODE_STRING ServiceName,
+ _In_ PADDRINFOEXW Hints, _Out_ PADDRINFOEXW *Result) {
+ NTSTATUS Status;
+
+ //
+ // Allocate async context.
+ //
+
+ KSOCKET_ASYNC_CONTEXT AsyncContext;
+ Status = KspAsyncContextAllocate(&AsyncContext);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Call the WSK API.
+ //
+
+ Status = WskProvider.Dispatch->WskGetAddressInfo(WskProvider.Client, // Client
+ NodeName, // NodeName
+ ServiceName, // ServiceName
+ 0, // NameSpace
+ NULL, // Provider
+ Hints, // Hints
+ Result, // Result
+ NULL, // OwningProcess
+ NULL, // OwningThread
+ AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&AsyncContext, &Status);
+
+ //
+ // Free the async context.
+ //
+
+ KspAsyncContextFree(&AsyncContext);
+
+ return Status;
+}
+
+VOID NTAPI KsFreeAddrInfo(_In_ PADDRINFOEXW AddrInfo) {
+ WskProvider.Dispatch->WskFreeAddressInfo(WskProvider.Client, // Client
+ AddrInfo // AddrInfo
+ );
+}
+
+NTSTATUS
+NTAPI
+KsCreateSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags) {
+ NTSTATUS Status;
+
+ //
+ // Allocate memory for the socket structure.
+ //
+
+ PKSOCKET NewSocket =
+ (PKSOCKET)ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG);
+
+ if (!NewSocket) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Allocate async context for the socket.
+ //
+
+ Status = KspAsyncContextAllocate(&NewSocket->AsyncContext);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Create the WSK socket.
+ //
+
+ Status = WskProvider.Dispatch->WskSocket(WskProvider.Client, // Client
+ AddressFamily, // AddressFamily
+ SocketType, // SocketType
+ Protocol, // Protocol
+ Flags, // Flags
+ NULL, // SocketContext
+ NULL, // Dispatch
+ NULL, // OwningProcess
+ NULL, // OwningThread
+ NULL, // SecurityDescriptor
+ NewSocket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&NewSocket->AsyncContext, &Status);
+
+ //
+ // Save the socket instance and the socket dispatch table.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ NewSocket->WskSocket =
+ (PWSK_SOCKET)NewSocket->AsyncContext.Irp->IoStatus.Information;
+ NewSocket->WskDispatch = (PVOID)NewSocket->WskSocket->Dispatch;
+
+ *Socket = NewSocket;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsCreateConnectionSocket(_Out_ PKSOCKET *Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol) {
+ return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol,
+ WSK_FLAG_CONNECTION_SOCKET);
+}
+
+NTSTATUS
+NTAPI
+KsCreateListenSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol) {
+ return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol,
+ WSK_FLAG_LISTEN_SOCKET);
+}
+
+NTSTATUS
+NTAPI
+KsCreateDatagramSocket(_Out_ PKSOCKET *Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol) {
+ return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol,
+ WSK_FLAG_DATAGRAM_SOCKET);
+}
+
+NTSTATUS
+NTAPI
+KsCloseSocket(_In_ PKSOCKET Socket) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Close the WSK socket.
+ //
+
+ Status = Socket->WskConnectionDispatch->WskCloseSocket(
+ Socket->WskSocket, Socket->AsyncContext.Irp);
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Free the async context.
+ //
+
+ KspAsyncContextFree(&Socket->AsyncContext);
+
+ //
+ // Free memory for the socket structure.
+ //
+
+ ExFreePoolWithTag(Socket, MEMORY_TAG);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsBind(_In_ PKSOCKET Socket, _In_ PSOCKADDR LocalAddress) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Bind the socket.
+ //
+
+ Status = Socket->WskListenDispatch->WskBind(Socket->WskSocket, // Socket
+ LocalAddress, // LocalAddress
+ 0, // Flags (reserved)
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsAccept(_In_ PKSOCKET Socket, _Out_ PKSOCKET *NewSocket,
+ _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Accept the connection.
+ //
+
+ Status =
+ Socket->WskListenDispatch->WskAccept(Socket->WskSocket, // ListenSocket
+ 0, // Flags
+ NULL, // AcceptSocketContext
+ NULL, // AcceptSocketDispatch
+ LocalAddress, // LocalAddress
+ RemoteAddress, // RemoteAddress
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Save the socket instance and the socket dispatch table.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ PKSOCKET KNewSocket =
+ ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG);
+
+ if (!KNewSocket) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KNewSocket->WskSocket =
+ (PWSK_SOCKET)Socket->AsyncContext.Irp->IoStatus.Information;
+ KNewSocket->WskDispatch = (PVOID)KNewSocket->WskSocket->Dispatch;
+ KspAsyncContextAllocate(&KNewSocket->AsyncContext);
+
+ *NewSocket = KNewSocket;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsConnect(_In_ PKSOCKET Socket, _In_ PSOCKADDR RemoteAddress) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Bind the socket to the local address.
+ //
+
+ SOCKADDR_IN LocalAddress;
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_addr.s_addr = INADDR_ANY;
+ LocalAddress.sin_port = 0;
+
+ Status = Socket->WskConnectionDispatch->WskBind(
+ Socket->WskSocket, // Socket
+ (PSOCKADDR)&LocalAddress, // LocalAddress
+ 0, // Flags (reserved)
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Reset the async context (again).
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Connect to the remote host.
+ //
+ // N.B.: Instead of calling WskSocket(), WskBind() and WskConnect(),
+ // it is possible to just call WskSocketConnect().
+ //
+
+ Status =
+ Socket->WskConnectionDispatch->WskConnect(Socket->WskSocket, // Socket
+ RemoteAddress, // RemoteAddress
+ 0, // Flags (reserved)
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsSendRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ BOOLEAN Send) {
+ NTSTATUS Status;
+
+ //
+ // Wrap the buffer into the "WSK buffer".
+ //
+
+ WSK_BUF WskBuffer;
+ WskBuffer.Offset = 0;
+ WskBuffer.Length = *Length;
+ WskBuffer.Mdl =
+ IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL);
+
+ //__try
+ { MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); }
+#if 0
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = STATUS_ACCESS_VIOLATION;
+ goto Error;
+ }
+#endif
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Send / receive the data.
+ //
+
+ if (Send) {
+ Status =
+ Socket->WskConnectionDispatch->WskSend(Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags
+ Socket->AsyncContext.Irp // Irp
+ );
+ } else {
+ Status = Socket->WskConnectionDispatch->WskReceive(
+ Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags
+ Socket->AsyncContext.Irp // Irp
+ );
+ }
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Set the number of bytes sent / received.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information;
+ }
+
+ //
+ // Free the MDL.
+ //
+
+ MmUnlockPages(WskBuffer.Mdl);
+
+ // Error:
+ IoFreeMdl(WskBuffer.Mdl);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsSendRecvUdp(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress,
+ _In_ BOOLEAN Send) {
+ NTSTATUS Status;
+
+ //
+ // Wrap the buffer into the "WSK buffer".
+ //
+
+ WSK_BUF WskBuffer;
+ WskBuffer.Offset = 0;
+ WskBuffer.Length = *Length;
+ WskBuffer.Mdl =
+ IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL);
+
+ //__try
+ { MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); }
+#if 0
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = STATUS_ACCESS_VIOLATION;
+ goto Error;
+ }
+#endif
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Send / receive the data.
+ //
+
+ if (Send) {
+ Status =
+ Socket->WskDatagramDispatch->WskSendTo(Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags (reserved)
+ RemoteAddress, // RemoteAddress
+ 0, // ControlInfoLength
+ NULL, // ControlInfo
+ Socket->AsyncContext.Irp // Irp
+ );
+ } else {
+ Status = Socket->WskDatagramDispatch->WskReceiveFrom(
+ Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags (reserved)
+ RemoteAddress, // RemoteAddress
+ NULL, // ControlInfoLength
+ NULL, // ControlInfo
+ NULL, // ControlFlags
+ Socket->AsyncContext.Irp // Irp
+ );
+ }
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Set the number of bytes sent / received.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information;
+ }
+
+ //
+ // Free the MDL.
+ //
+
+ MmUnlockPages(WskBuffer.Mdl);
+
+ // Error:
+ IoFreeMdl(WskBuffer.Mdl);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsSend(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags) {
+ return KsSendRecv(Socket, Buffer, Length, Flags, TRUE);
+}
+
+NTSTATUS
+NTAPI
+KsRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags) {
+ return KsSendRecv(Socket, Buffer, Length, Flags, FALSE);
+}
+
+NTSTATUS
+NTAPI
+KsSendTo(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress) {
+ return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, TRUE);
+}
+
+NTSTATUS
+NTAPI
+KsRecvFrom(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress) {
+ return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, FALSE);
+}
diff --git a/ksocket.h b/ksocket.h
new file mode 100644
index 0000000..a4bd0f7
--- /dev/null
+++ b/ksocket.h
@@ -0,0 +1,165 @@
+#pragma once
+#include <ntddk.h>
+#include "wsk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _KSOCKET KSOCKET, *PKSOCKET;
+
+NTSTATUS
+NTAPI
+KsInitialize(
+ VOID
+ );
+
+VOID
+NTAPI
+KsDestroy(
+ VOID
+ );
+
+NTSTATUS
+NTAPI
+KsGetAddrInfo(
+ _In_ PUNICODE_STRING NodeName,
+ _In_ PUNICODE_STRING ServiceName,
+ _In_ PADDRINFOEXW Hints,
+ _Out_ PADDRINFOEXW* Result
+ );
+
+VOID
+NTAPI
+KsFreeAddrInfo(
+ _In_ PADDRINFOEXW AddrInfo
+ );
+
+NTSTATUS
+NTAPI
+KsCreateSocket(
+ _Out_ PKSOCKET* Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType,
+ _In_ ULONG Protocol,
+ _In_ ULONG Flags
+ );
+
+NTSTATUS
+NTAPI
+KsCreateConnectionSocket(
+ _Out_ PKSOCKET* Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType,
+ _In_ ULONG Protocol
+ );
+
+NTSTATUS
+NTAPI
+KsCreateListenSocket(
+ _Out_ PKSOCKET* Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType,
+ _In_ ULONG Protocol
+ );
+
+NTSTATUS
+NTAPI
+KsCreateDatagramSocket(
+ _Out_ PKSOCKET* Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType,
+ _In_ ULONG Protocol
+ );
+
+NTSTATUS
+NTAPI
+KsCloseSocket(
+ _In_ PKSOCKET Socket
+ );
+
+NTSTATUS
+NTAPI
+KsBind(
+ _In_ PKSOCKET Socket,
+ _In_ PSOCKADDR LocalAddress
+ );
+
+NTSTATUS
+NTAPI
+KsAccept(
+ _In_ PKSOCKET Socket,
+ _Out_ PKSOCKET* NewSocket,
+ _Out_opt_ PSOCKADDR LocalAddress,
+ _Out_opt_ PSOCKADDR RemoteAddress
+ );
+
+NTSTATUS
+NTAPI
+KsConnect(
+ _In_ PKSOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress
+ );
+
+NTSTATUS
+NTAPI
+KsSendRecv(
+ _In_ PKSOCKET Socket,
+ _In_ PVOID Buffer,
+ _Inout_ PULONG Length,
+ _In_ ULONG Flags,
+ _In_ BOOLEAN Send
+ );
+
+NTSTATUS
+NTAPI
+KsSendRecvUdp(
+ _In_ PKSOCKET Socket,
+ _In_ PVOID Buffer,
+ _Inout_ PULONG Length,
+ _In_ ULONG Flags,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_ BOOLEAN Send
+ );
+
+NTSTATUS
+NTAPI
+KsSend(
+ _In_ PKSOCKET Socket,
+ _In_ PVOID Buffer,
+ _Inout_ PULONG Length,
+ _In_ ULONG Flags
+ );
+
+NTSTATUS
+NTAPI
+KsRecv(
+ _In_ PKSOCKET Socket,
+ _In_ PVOID Buffer,
+ _Inout_ PULONG Length,
+ _In_ ULONG Flags
+ );
+
+NTSTATUS
+NTAPI
+KsSendTo(
+ _In_ PKSOCKET Socket,
+ _In_ PVOID Buffer,
+ _Inout_ PULONG Length,
+ _In_ ULONG Flags,
+ _In_ PSOCKADDR RemoteAddress
+ );
+
+NTSTATUS
+NTAPI
+KsRecvFrom(
+ _In_ PKSOCKET Socket,
+ _In_ PVOID Buffer,
+ _Inout_ PULONG Length,
+ _In_ ULONG Flags,
+ _In_ PSOCKADDR RemoteAddress
+ );
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/userspace_client.cpp b/userspace_client.cpp
new file mode 100644
index 0000000..efcd782
--- /dev/null
+++ b/userspace_client.cpp
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdlib.h> // Needed for _wtoi
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+int main(int argc, char **argv) {
+ WSADATA wsaData = {};
+ int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ if (iResult != 0) {
+ wprintf(L"WSAStartup failed: %d\n", iResult);
+ return 1;
+ }
+
+ SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sock == INVALID_SOCKET) {
+ wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
+ } else {
+ wprintf(L"socket function succeeded\n");
+ }
+
+ sockaddr_in clientService;
+ clientService.sin_family = AF_INET;
+ clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
+ clientService.sin_port = htons(9095);
+
+ do {
+ iResult = connect(sock, (SOCKADDR *)&clientService, sizeof(clientService));
+ if (iResult == SOCKET_ERROR) {
+ wprintf(L"connect function failed with error: %ld\n", WSAGetLastError());
+ Sleep(1000);
+ }
+ } while (iResult == SOCKET_ERROR);
+
+ wprintf(L"Connected to server.\n");
+
+ char sendbuf[] = "Hello Driver, greetings from userspace.";
+ iResult = send(sock, sendbuf, (int)strlen(sendbuf), 0);
+ if (iResult == SOCKET_ERROR) {
+ wprintf(L"send failed with error: %d\n", WSAGetLastError());
+ closesocket(sock);
+ WSACleanup();
+ return 1;
+ }
+
+ do {
+ char recvbuf[1024];
+
+ iResult = recv(sock, recvbuf, 1024, 0);
+ if (iResult > 0) {
+ wprintf(L"Bytes received: %d\n", iResult);
+ wprintf(L"Data received: %.*s\n", iResult, recvbuf);
+ } else if (iResult == 0) {
+ wprintf(L"Connection closed\n");
+ } else if (WSAGetLastError() != WSAECONNRESET) {
+ wprintf(L"recv failed: %d\n", WSAGetLastError());
+ }
+ } while (iResult > 0);
+ wprintf(L"connection closed by remote\n");
+
+ iResult = closesocket(sock);
+ if (iResult == SOCKET_ERROR) {
+ wprintf(L"closesocket function failed with error: %ld\n",
+ WSAGetLastError());
+ WSACleanup();
+ return 1;
+ }
+
+ WSACleanup();
+
+ system("pause");
+
+ return 0;
+}
diff --git a/wsk.h b/wsk.h
new file mode 100644
index 0000000..f7e5fb6
--- /dev/null
+++ b/wsk.h
@@ -0,0 +1,456 @@
+#ifndef WSK_H
+#define WSK_H 1
+
+#if !defined(__MINGW64__)
+#error "This was designed to work **only** with Mingw-w64! For MSVC, please check https://github.com/wbenny/KSOCKET out"
+#endif
+
+#if (NTDDI_VERSION < NTDDI_WIN10)
+#error \
+ "Your mingw-w64 toolchain is too old. Please use the one provided by https://github.com/utoni/mingw-w64-ddk-template"
+#endif
+
+#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error "This project requires a little endian system. Does Windows support any other?"
+#endif
+
+// ---------------------------------------------------------------
+// defines
+// ---------------------------------------------------------------
+
+#define WSKAPI NTAPI
+#define MAKE_WSK_VERSION(Mj, Mn) ((USHORT)((Mj) << 8) | (USHORT)((Mn)&0xff))
+#define WSK_NO_WAIT 0
+#define WSK_INFINITE_WAIT 0xffffffff
+
+#define WSK_FLAG_BASIC_SOCKET 0x00000000
+#define WSK_FLAG_LISTEN_SOCKET 0x00000001
+#define WSK_FLAG_CONNECTION_SOCKET 0x00000002
+#define WSK_FLAG_DATAGRAM_SOCKET 0x00000004
+#define WSK_FLAG_STREAM_SOCKET 0x00000008
+
+#define INADDR_ANY ((ULONG)0x00000000)
+
+// ---------------------------------------------------------------
+// forward decls / opaque structs
+// ---------------------------------------------------------------
+
+struct _WSK_CLIENT_CONNECTION_DISPATCH;
+typedef struct _WSK_CLIENT_CONNECTION_DISPATCH WSK_CLIENT_CONNECTION_DISPATCH;
+typedef WSK_CLIENT_CONNECTION_DISPATCH *PWSK_CLIENT_CONNECTION_DISPATCH;
+struct _WSK_CLIENT_NPI;
+typedef struct _WSK_CLIENT_NPI WSK_CLIENT_NPI;
+typedef struct _WSK_CLIENT_NPI *PWSK_CLIENT_NPI;
+struct _WSK_PROVIDER_NPI;
+typedef struct _WSK_PROVIDER_NPI WSK_PROVIDER_NPI;
+typedef struct _WSK_PROVIDER_NPI *PWSK_PROVIDER_NPI;
+
+typedef PVOID PWSK_CLIENT;
+
+// ---------------------------------------------------------------
+// enums
+// ---------------------------------------------------------------
+
+typedef enum {
+ WskSetOption, // set socket option
+ WskGetOption, // get socket option
+ WskIoctl, // socket IOCTL
+ WskControlMax
+} WSK_CONTROL_SOCKET_TYPE,
+ *PWSK_CONTROL_SOCKET_TYPE;
+
+enum {
+ AI_PASSIVE = 0x01,
+ AI_CANONNAME = 0x02,
+ AI_NUMERICHOST = 0x04,
+ AI_ALL = 0x0100,
+ AI_ADDRCONFIG = 0x0400,
+ AI_V4MAPPED = 0x0800,
+ AI_NON_AUTHORITATIVE = 0x4000,
+ AI_SECURE = 0x08000,
+ AI_RETURN_PREFERRED_NAMES = 0x10000,
+ AI_FQDN = 0x00020000,
+ AI_FILESERVER = 0x00040000
+};
+
+typedef enum ADDRESS_FAMILY {
+ AF_UNSPEC = 0,
+ AF_INET = 2,
+ AF_INET6 = 23
+} ADDRESS_FAMILY;
+
+enum {
+ IPPROTO_ICMP = 1,
+ IPPROTO_IGMP = 2,
+ BTHPROTO_RFCOMM = 3,
+ IPPROTO_TCP = 6,
+ IPPROTO_UDP = 17,
+ IPPROTO_ICMPV6 = 58,
+ IPPROTO_RM = 113
+};
+
+enum {
+ SOCK_STREAM = 1,
+ SOCK_DGRAM = 2,
+ SOCK_RAW = 3,
+ SOCK_RDM = 4,
+ SOCK_SEQPACKET = 5,
+};
+
+typedef enum {
+ WskInspectReject, // reject the connection request
+ WskInspectAccept, // proceed with accept
+ WskInspectPend, // delay the decision (use WskInspectComplete later)
+ WskInspectMax
+} WSK_INSPECT_ACTION,
+ *PWSK_INSPECT_ACTION;
+
+// ---------------------------------------------------------------
+// general structs
+// ---------------------------------------------------------------
+
+typedef struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
+} ADDRINFOA, *PADDRINFOA;
+
+typedef struct addrinfoexA {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ void *ai_blob;
+ size_t ai_bloblen;
+ LPGUID ai_provider;
+ struct addrinfoexA *ai_next;
+} ADDRINFOEXA, *PADDRINFOEXA, *LPADDRINFOEXA;
+
+typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ PWSTR ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfoW *ai_next;
+} ADDRINFOW, *PADDRINFOW;
+
+typedef struct addrinfoexW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ PWSTR ai_canonname;
+ struct sockaddr *ai_addr;
+ void *ai_blob;
+ size_t ai_bloblen;
+ LPGUID ai_provider;
+ struct addrinfoexW *ai_next;
+} ADDRINFOEXW, *PADDRINFOEXW, *LPADDRINFOEXW;
+
+typedef struct sockaddr {
+ ADDRESS_FAMILY sa_family;
+ CHAR sa_data[14];
+} SOCKADDR, *PSOCKADDR, *LPSOCKADDR;
+
+struct in_addr {
+ union {
+ struct {
+ UCHAR s_b1;
+ UCHAR s_b2;
+ UCHAR s_b3;
+ UCHAR s_b4;
+ } s_un_b;
+ struct {
+ USHORT s_w1;
+ USHORT s_w2;
+ } s_un_w;
+ ULONG s_addr;
+ };
+};
+
+typedef struct sockaddr_in {
+ short sin_family;
+ USHORT sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+} SOCKADDR_IN, *PSOCKADDR_IN, *LPSOCKADDR_IN;
+
+typedef struct _WSK_SOCKET {
+ const VOID *Dispatch;
+} WSK_SOCKET, *PWSK_SOCKET;
+
+typedef struct _WSK_BUF {
+ PMDL Mdl; // Locked MDL chain
+ ULONG Offset; // Offset into the "first" Mdl in the chain
+ SIZE_T Length; // Length of data starting from Offset
+} WSK_BUF, *PWSK_BUF;
+
+typedef struct _WSK_BUF_LIST {
+ struct _WSK_BUF_LIST *Next;
+ WSK_BUF Buffer;
+} WSK_BUF_LIST, *PWSK_BUF_LIST;
+
+typedef struct _WSK_DATA_INDICATION {
+ struct _WSK_DATA_INDICATION *Next;
+ WSK_BUF Buffer;
+} WSK_DATA_INDICATION, *PWSK_DATA_INDICATION;
+
+typedef struct _WSK_INSPECT_ID {
+ ULONG_PTR Key;
+ ULONG SerialNumber;
+} WSK_INSPECT_ID, *PWSK_INSPECT_ID;
+
+typedef struct _WSACMSGHDR {
+ SIZE_T cmsg_len;
+ INT cmsg_level;
+ INT cmsg_type;
+} WSACMSGHDR, *PWSACMSGHDR, *LPWSACMSGHDR, CMSGHDR, *PCMSGHDR;
+
+typedef struct _WSK_DATAGRAM_INDICATION {
+ struct _WSK_DATAGRAM_INDICATION *Next;
+ WSK_BUF Buffer;
+ _Field_size_bytes_(ControlInfoLength) PCMSGHDR ControlInfo;
+ ULONG ControlInfoLength;
+ PSOCKADDR RemoteAddress;
+} WSK_DATAGRAM_INDICATION, *PWSK_DATAGRAM_INDICATION;
+
+typedef struct _WSK_REGISTRATION {
+ ULONGLONG ReservedRegistrationState;
+ PVOID ReservedRegistrationContext;
+ KSPIN_LOCK ReservedRegistrationLock;
+} WSK_REGISTRATION, *PWSK_REGISTRATION;
+
+// ---------------------------------------------------------------
+// callback functions
+// ---------------------------------------------------------------
+
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONTROL_SOCKET)(
+ _In_ PWSK_SOCKET Socket, _In_ WSK_CONTROL_SOCKET_TYPE RequestType,
+ _In_ ULONG ControlCode, _In_ ULONG Level, _In_ SIZE_T InputSize,
+ _In_opt_ PVOID InputBuffer, _In_ SIZE_T OutputSize,
+ _Out_opt_ PVOID OutputBuffer, _Out_opt_ SIZE_T *OutputSizeReturned,
+ _In_ _Out_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CLOSE_SOCKET)(_In_ PWSK_SOCKET Socket,
+ _Inout_ PIRP Irp);
+
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress,
+ ULONG Flags, _In_ _Out_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_BIND)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR LocalAddress,
+ _Reserved_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_GET_LOCAL_ADDRESS)(
+ _In_ PWSK_SOCKET Socket, _Out_ PSOCKADDR LocalAddress, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_GET_REMOTE_ADDRESS)(
+ _In_ PWSK_SOCKET Socket, _Out_ PSOCKADDR RemoteAddress, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND)(_In_ PWSK_SOCKET Socket,
+ _In_ PWSK_BUF Buffer, _In_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RECEIVE)(_In_ PWSK_SOCKET Socket,
+ _In_ PWSK_BUF Buffer,
+ _In_ ULONG Flags, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_DISCONNECT)(_In_ PWSK_SOCKET Socket,
+ _In_opt_ PWSK_BUF Buffer,
+ _In_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RELEASE_DATA_INDICATION_LIST)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_DATA_INDICATION DataIndication);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT_EX)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_opt_ PWSK_BUF Buffer,
+ _Reserved_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT_EX)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_opt_ PWSK_BUF Buffer,
+ _Reserved_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef void *PFN_WSK_SEND_EX; // reserved for system use
+typedef void *PFN_WSK_RECEIVE_EX; // reserved for system use
+typedef _At_(Irp->IoStatus.Information, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_ACCEPT)(
+ _In_ PWSK_SOCKET ListenSocket, _Reserved_ ULONG Flags,
+ _In_opt_ PVOID AcceptSocketContext,
+ _In_opt_ CONST WSK_CLIENT_CONNECTION_DISPATCH *AcceptSocketDispatch,
+ _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress,
+ _Inout_ PIRP Irp);
+typedef _Must_inspect_result_ NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_EVENT)(
+ _In_opt_ PVOID SocketContext, _In_ ULONG Flags,
+ _In_opt_ PWSK_DATA_INDICATION DataIndication, _In_ SIZE_T BytesIndicated,
+ _Inout_ SIZE_T *BytesAccepted);
+typedef NTSTATUS(WSKAPI *PFN_WSK_DISCONNECT_EVENT)(_In_opt_ PVOID SocketContext,
+ _In_ ULONG Flags);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_BACKLOG_EVENT)(
+ _In_opt_ PVOID SocketContext, _In_ SIZE_T IdealBacklogSize);
+typedef NTSTATUS(WSKAPI *PFN_WSK_INSPECT_COMPLETE)(
+ _In_ PWSK_SOCKET ListenSocket, _In_ PWSK_INSPECT_ID InspectID,
+ _In_ WSK_INSPECT_ACTION Action, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_TO)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF Buffer, _Reserved_ ULONG Flags,
+ _In_opt_ PSOCKADDR RemoteAddress, _In_ ULONG ControlInfoLength,
+ _In_reads_bytes_opt_(ControlInfoLength) PCMSGHDR ControlInfo,
+ _Inout_ PIRP Irp);
+typedef _Must_inspect_result_ NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_FROM_EVENT)(
+ _In_opt_ PVOID SocketContext, _In_ ULONG Flags,
+ _In_opt_ PWSK_DATAGRAM_INDICATION DataIndication);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_FROM)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF Buffer, _Reserved_ ULONG Flags,
+ _Out_opt_ PSOCKADDR RemoteAddress, _Inout_ PULONG ControlLength,
+ _Out_writes_bytes_opt_(*ControlLength) PCMSGHDR ControlInfo,
+ _Out_opt_ PULONG ControlFlags, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RELEASE_DATAGRAM_INDICATION_LIST)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_DATAGRAM_INDICATION DatagramIndication);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_MESSAGES)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF_LIST BufferList,
+ _Reserved_ ULONG Flags, _In_opt_ PSOCKADDR RemoteAddress,
+ _In_ ULONG ControlInfoLength,
+ _In_reads_bytes_opt_(ControlInfoLength) PCMSGHDR ControlInfo,
+ _Inout_ PIRP Irp);
+typedef _At_((void *)Irp->IoStatus.Information, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_SOCKET)(
+ _In_ PWSK_CLIENT Client, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags,
+ _In_opt_ PVOID SocketContext, _In_opt_ CONST VOID *Dispatch,
+ _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, _Inout_ PIRP Irp);
+typedef _At_(Irp->IoStatus.Information, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_SOCKET_CONNECT)(
+ _In_ PWSK_CLIENT Client, _In_ USHORT SocketType, _In_ ULONG Protocol,
+ _In_ PSOCKADDR LocalAddress, _In_ PSOCKADDR RemoteAddress,
+ _Reserved_ ULONG Flags, _In_opt_ PVOID SocketContext,
+ _In_opt_ CONST WSK_CLIENT_CONNECTION_DISPATCH *Dispatch,
+ _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONTROL_CLIENT)(
+ _In_ PWSK_CLIENT Client, _In_ ULONG ControlCode, _In_ SIZE_T InputSize,
+ _In_reads_bytes_opt_(InputSize) PVOID InputBuffer, _In_ SIZE_T OutputSize,
+ _Out_writes_bytes_opt_(OutputSize) PVOID OutputBuffer,
+ _Out_opt_ SIZE_T *OutputSizeReturned, _Inout_opt_ PIRP Irp);
+typedef _At_(*Result, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO)(
+ _In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName,
+ _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace,
+ _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints,
+ _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess,
+ _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp);
+typedef _At_(AddrInfo, __drv_freesMem(Mem))
+ VOID(WSKAPI *PFN_WSK_FREE_ADDRESS_INFO)(_In_ PWSK_CLIENT Client,
+ _In_ PADDRINFOEXW AddrInfo);
+typedef NTSTATUS(WSKAPI *PFN_WSK_GET_NAME_INFO)(
+ _In_ PWSK_CLIENT Client, _In_ PSOCKADDR SockAddr, _In_ ULONG SockAddrLength,
+ _Out_opt_ PUNICODE_STRING NodeName, _Out_opt_ PUNICODE_STRING ServiceName,
+ _In_ ULONG Flags, _In_opt_ PEPROCESS OwningProcess,
+ _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CLIENT_EVENT)(
+ _In_opt_ PVOID ClientContext, _In_ ULONG EventType,
+ _In_reads_bytes_opt_(InformationLength) PVOID Information,
+ _In_ SIZE_T InformationLength);
+_Must_inspect_result_ NTSTATUS WskRegister(
+ _In_ PWSK_CLIENT_NPI WskClientNpi, _Out_ PWSK_REGISTRATION WskRegistration);
+_Must_inspect_result_ NTSTATUS WskCaptureProviderNPI(
+ _In_ PWSK_REGISTRATION WskRegistration, _In_ ULONG WaitTimeout,
+ _Out_ PWSK_PROVIDER_NPI WskProviderNpi);
+VOID WskReleaseProviderNPI(_In_ PWSK_REGISTRATION WskRegistration);
+VOID WskDeregister(_In_ PWSK_REGISTRATION WskRegistration);
+
+// ---------------------------------------------------------------
+// function pointer structs
+// ---------------------------------------------------------------
+
+typedef struct _WSK_CLIENT_CONNECTION_DISPATCH {
+ PFN_WSK_RECEIVE_EVENT WskReceiveEvent;
+ PFN_WSK_DISCONNECT_EVENT WskDisconnectEvent;
+ PFN_WSK_SEND_BACKLOG_EVENT WskSendBacklogEvent;
+} WSK_CLIENT_CONNECTION_DISPATCH, *PWSK_CLIENT_CONNECTION_DISPATCH;
+
+typedef struct _WSK_PROVIDER_BASIC_DISPATCH {
+ PFN_WSK_CONTROL_SOCKET WskControlSocket;
+ PFN_WSK_CLOSE_SOCKET WskCloseSocket;
+} WSK_PROVIDER_BASIC_DISPATCH, *PWSK_PROVIDER_BASIC_DISPATCH;
+
+typedef struct _WSK_PROVIDER_CONNECTION_DISPATCH {
+#ifdef __cplusplus
+ WSK_PROVIDER_BASIC_DISPATCH Basic;
+#else
+ WSK_PROVIDER_BASIC_DISPATCH;
+#endif
+ PFN_WSK_BIND WskBind;
+ PFN_WSK_CONNECT WskConnect;
+ PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress;
+ PFN_WSK_GET_REMOTE_ADDRESS WskGetRemoteAddress;
+ PFN_WSK_SEND WskSend;
+ PFN_WSK_RECEIVE WskReceive;
+ PFN_WSK_DISCONNECT WskDisconnect;
+ PFN_WSK_RELEASE_DATA_INDICATION_LIST WskRelease;
+ PFN_WSK_CONNECT_EX WskConnectEx;
+ PFN_WSK_SEND_EX WskSendEx;
+ PFN_WSK_RECEIVE_EX WskReceiveEx;
+} WSK_PROVIDER_CONNECTION_DISPATCH, *PWSK_PROVIDER_CONNECTION_DISPATCH;
+
+typedef struct _WSK_PROVIDER_LISTEN_DISPATCH {
+#ifdef __cplusplus
+ WSK_PROVIDER_BASIC_DISPATCH Basic;
+#else
+ WSK_PROVIDER_BASIC_DISPATCH;
+#endif
+ PFN_WSK_BIND WskBind;
+ PFN_WSK_ACCEPT WskAccept;
+ PFN_WSK_INSPECT_COMPLETE WskInspectComplete;
+ PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress;
+} WSK_PROVIDER_LISTEN_DISPATCH, *PWSK_PROVIDER_LISTEN_DISPATCH;
+
+typedef struct _WSK_PROVIDER_DATAGRAM_DISPATCH {
+#ifdef __cplusplus
+ WSK_PROVIDER_BASIC_DISPATCH Basic;
+#else
+ WSK_PROVIDER_BASIC_DISPATCH;
+#endif
+ PFN_WSK_BIND WskBind;
+ PFN_WSK_SEND_TO WskSendTo;
+ PFN_WSK_RECEIVE_FROM WskReceiveFrom;
+ PFN_WSK_RELEASE_DATAGRAM_INDICATION_LIST WskRelease;
+ PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress;
+ PFN_WSK_SEND_MESSAGES WskSendMessages;
+} WSK_PROVIDER_DATAGRAM_DISPATCH, *PWSK_PROVIDER_DATAGRAM_DISPATCH;
+
+typedef struct _WSK_PROVIDER_DISPATCH {
+ USHORT Version;
+ USHORT Reserved;
+ PFN_WSK_SOCKET WskSocket;
+ PFN_WSK_SOCKET_CONNECT WskSocketConnect;
+ PFN_WSK_CONTROL_CLIENT WskControlClient;
+ PFN_WSK_GET_ADDRESS_INFO WskGetAddressInfo;
+ PFN_WSK_FREE_ADDRESS_INFO WskFreeAddressInfo;
+ PFN_WSK_GET_NAME_INFO WskGetNameInfo;
+} WSK_PROVIDER_DISPATCH, *PWSK_PROVIDER_DISPATCH;
+
+typedef struct _WSK_CLIENT_DISPATCH {
+ USHORT Version;
+ USHORT Reserved;
+ PFN_WSK_CLIENT_EVENT WskClientEvent;
+} WSK_CLIENT_DISPATCH, *PWSK_CLIENT_DISPATCH;
+
+typedef struct _WSK_CLIENT_NPI {
+ PVOID ClientContext;
+ CONST WSK_CLIENT_DISPATCH *Dispatch;
+} WSK_CLIENT_NPI, *PWSK_CLIENT_NPI;
+
+typedef struct _WSK_PROVIDER_NPI {
+ PWSK_CLIENT Client;
+ CONST WSK_PROVIDER_DISPATCH *Dispatch;
+} WSK_PROVIDER_NPI, *PWSK_PROVIDER_NPI;
+
+#endif