implement generic I/O async request object to replace file-specific async requests, refactor lwIP network stack to dispatch requests through IRPs with cancellation support, add cancellation polling to lwIP accept and receive operations using LwipSocketWaitRecvNetbuf and LwipSocketWaitAccept, introduce NetSubmitSocketIrp for routing socket operations via device IRPs, track network IRP statistics with SYS_NET_IRP_STATS, add process module lock spinlock and reference counting for process modules, implement dynamic module loading and unloading via user module handles, add POSIX dynamic loader APIs including dlopen, dlsym, dlerror, and dlclose, introduce PosixStart entry point for posix applications, add new native smoke tests for net IRPs.

This commit is contained in:
maksw committed 2026-06-27 10:37:53 +02:00
1 parent ed3d065abd
commit 1f5477cf66
32 files changed
+3713 -551

No files matched your search

+320 -37
View File
@@ -7,6 +7,7 @@
#include <ntlite/ddi/hal_api.h>
#include <ntlite/status.h>
#include <ntlite/ddi/io_driver.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_settings.h>
@@ -38,6 +39,7 @@
#define LWIP_PROVIDER_SOCKET_IO_MAX_BYTES (1024u * 1024u)
#define LWIP_PROVIDER_SOCKET_UDP_MAX_BYTES 65507u
#define LWIP_PROVIDER_SOCKET_RAW_MAX_BYTES 65535u
#define LWIP_PROVIDER_CANCEL_POLL_MS 25u
#define LWIP_SETTINGS_DEFAULT_SECTION "network.default"
#define LWIP_SETTINGS_SECTION_PREFIX "network."
@@ -105,38 +107,28 @@ static KSTATUS LwipProviderSocketCreate(uint32_t domain, uint32_t type, uint32_t
static void LwipProviderSocketClose(void* socket);
static KSTATUS LwipProviderBind(void* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize);
static KSTATUS LwipProviderListen(void* socket, uint32_t backlog);
static KSTATUS LwipProviderAccept(void* socket, void** acceptedOut, SYS_SOCKET_ADDRESS_K* remoteOut);
static KSTATUS LwipProviderConnect(void* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize);
static KSTATUS LwipProviderAccept(void* socket, void** acceptedOut, SYS_SOCKET_ADDRESS_K* remoteOut, volatile uint8_t* cancelRequested);
static KSTATUS LwipProviderConnect(void* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize, volatile uint8_t* cancelRequested);
static KSTATUS LwipProviderSend(void* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut);
static KSTATUS LwipProviderReceive(void* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut);
static KSTATUS LwipProviderReceive(void* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut, volatile uint8_t* cancelRequested);
static KSTATUS LwipProviderSendTo(void* socket, const void* buffer, size_t length, uint32_t flags, const SYS_SOCKET_ADDRESS_K* remote, size_t remoteSize, size_t* sentOut);
static KSTATUS LwipProviderReceiveFrom(void* socket, void* buffer, size_t length, uint32_t flags, SYS_SOCKET_ADDRESS_K* remoteOut, size_t* receivedOut);
static KSTATUS LwipProviderReceiveFrom(void* socket, void* buffer, size_t length, uint32_t flags, SYS_SOCKET_ADDRESS_K* remoteOut, size_t* receivedOut, volatile uint8_t* cancelRequested);
static KSTATUS LwipProviderShutdown(void* socket, uint32_t how);
static KSTATUS LwipProviderSetOption(void* socket, uint32_t option, const void* value, size_t valueSize);
static KSTATUS LwipProviderGetOption(void* socket, uint32_t option, void* value, size_t valueSize, size_t* actualSizeOut);
static KSTATUS LwipProviderPoll(void* socket, uint32_t events, uint32_t* returnedEventsOut);
static KSTATUS LwipProviderResolveHost(const char* name, uint32_t family, SYS_SOCKET_ADDRESS_K* addressOut);
static KSTATUS LwipDispatchInternalDeviceControl(DEVICE_OBJECT* device, IRP* irp);
static const NET_STACK_PROVIDER gLwipProvider = {
static DRIVER_OBJECT gLwipDriver;
static DEVICE_OBJECT* gLwipDevice;
static NET_STACK_PROVIDER gLwipProvider = {
NET_STACK_PROVIDER_VERSION,
"lwIP",
NULL,
LwipProviderAttachDevice,
LwipProviderReceiveFrame,
LwipProviderSocketCreate,
LwipProviderSocketClose,
LwipProviderBind,
LwipProviderListen,
LwipProviderAccept,
LwipProviderConnect,
LwipProviderSend,
LwipProviderReceive,
LwipProviderSendTo,
LwipProviderReceiveFrom,
LwipProviderShutdown,
LwipProviderSetOption,
LwipProviderGetOption,
LwipProviderPoll,
LwipProviderResolveHost,
};
// Implements the err To Status operation.
@@ -377,10 +369,18 @@ static void LwipSocketCallback(struct netconn* conn, enum netconn_evt evt, u16_t
if (!conn)
return;
LWIP_PROVIDER_SOCKET* socket = (LWIP_PROVIDER_SOCKET*)netconn_get_callback_arg(conn);
if (!socket)
void* callbackArg = netconn_get_callback_arg(conn);
uintptr_t rawArg = (uintptr_t)callbackArg;
if (!callbackArg)
return;
// Accepted netconns inherit the listener callback before the wrapper can
// replace lwIP's internal negative socket sentinel with our socket object.
if (rawArg >= 0x80000000ull && rawArg <= 0xffffffffull)
return;
LWIP_PROVIDER_SOCKET* socket = (LWIP_PROVIDER_SOCKET*)callbackArg;
switch (evt) {
case NETCONN_EVT_RCVPLUS:
socket->PollReadEvents++;
@@ -426,12 +426,118 @@ static KSTATUS LwipSocketAllocateWithConn(uint32_t domain, uint32_t type, uint32
s->Type = type;
s->Protocol = protocol;
netconn_set_callback_arg(conn, s);
conn->callback = LwipSocketCallback;
netconn_set_recvtimeout(conn, 0);
netconn_set_sendtimeout(conn, 0);
*out = s;
return STATUS_SUCCESS;
}
// Returns whether the IRP cancel token has been set by SysCancelIo.
static int LwipSocketCancelRequested(volatile uint8_t* cancelRequested) {
return cancelRequested && *cancelRequested;
}
// Computes the bounded wait slice used by cancel-aware receive and accept loops.
static uint32_t LwipSocketCancelWaitSlice(uint32_t remainingMs) {
if (remainingMs != 0 && remainingMs < LWIP_PROVIDER_CANCEL_POLL_MS)
return remainingMs;
return LWIP_PROVIDER_CANCEL_POLL_MS;
}
// Waits for a receive-style netconn mailbox while periodically observing cancellation.
static KSTATUS LwipSocketWaitRecvNetbuf(LWIP_PROVIDER_SOCKET* s,
struct netbuf** bufferOut,
volatile uint8_t* cancelRequested,
err_t* errOut) {
if (!s || !s->Conn || !bufferOut || !errOut)
return STATUS_INVALID_PARAMETER;
*bufferOut = NULL;
*errOut = ERR_OK;
if (!cancelRequested || s->NonBlocking) {
*errOut = netconn_recv(s->Conn, bufferOut);
return STATUS_SUCCESS;
}
uint32_t originalTimeout = s->ReceiveTimeoutMs;
uint32_t elapsed = 0;
for (;;) {
if (LwipSocketCancelRequested(cancelRequested)) {
netconn_set_recvtimeout(s->Conn, originalTimeout);
return STATUS_CANCELLED;
}
uint32_t remaining = 0;
if (originalTimeout != 0) {
if (elapsed >= originalTimeout) {
netconn_set_recvtimeout(s->Conn, originalTimeout);
*errOut = ERR_TIMEOUT;
return STATUS_SUCCESS;
}
remaining = originalTimeout - elapsed;
}
uint32_t slice = LwipSocketCancelWaitSlice(remaining);
netconn_set_recvtimeout(s->Conn, slice);
err_t err = netconn_recv(s->Conn, bufferOut);
if (err != ERR_TIMEOUT) {
netconn_set_recvtimeout(s->Conn, originalTimeout);
*errOut = err;
return STATUS_SUCCESS;
}
elapsed += slice;
}
}
// Waits for accept while preserving the caller's receive timeout model.
static KSTATUS LwipSocketWaitAccept(LWIP_PROVIDER_SOCKET* s,
struct netconn** acceptedOut,
volatile uint8_t* cancelRequested,
err_t* errOut) {
if (!s || !s->Conn || !acceptedOut || !errOut)
return STATUS_INVALID_PARAMETER;
*acceptedOut = NULL;
*errOut = ERR_OK;
if (!cancelRequested || s->NonBlocking) {
*errOut = netconn_accept(s->Conn, acceptedOut);
return STATUS_SUCCESS;
}
uint32_t originalTimeout = s->ReceiveTimeoutMs;
uint32_t elapsed = 0;
for (;;) {
if (LwipSocketCancelRequested(cancelRequested)) {
netconn_set_recvtimeout(s->Conn, originalTimeout);
return STATUS_CANCELLED;
}
uint32_t remaining = 0;
if (originalTimeout != 0) {
if (elapsed >= originalTimeout) {
netconn_set_recvtimeout(s->Conn, originalTimeout);
*errOut = ERR_TIMEOUT;
return STATUS_SUCCESS;
}
remaining = originalTimeout - elapsed;
}
uint32_t slice = LwipSocketCancelWaitSlice(remaining);
netconn_set_recvtimeout(s->Conn, slice);
err_t err = netconn_accept(s->Conn, acceptedOut);
if (err != ERR_TIMEOUT) {
netconn_set_recvtimeout(s->Conn, originalTimeout);
*errOut = err;
return STATUS_SUCCESS;
}
elapsed += slice;
}
}
static int LwipSocketAddressValid(const SYS_SOCKET_ADDRESS_K* address, size_t addressSize) {
if (!address || addressSize < sizeof(SYS_SOCKET_ADDRESS_K))
return 0;
@@ -798,7 +904,7 @@ static KSTATUS LwipProviderSocketCreate(uint32_t domain, uint32_t type, uint32_t
return STATUS_NOT_SUPPORTED;
}
struct netconn* conn = netconn_new_with_proto_and_callback(netconnType, rawProtocol, LwipSocketCallback);
struct netconn* conn = netconn_new_with_proto_and_callback(netconnType, rawProtocol, NULL);
if (!conn)
return STATUS_NO_MEMORY;
@@ -905,7 +1011,7 @@ static KSTATUS LwipProviderListen(void* socket, uint32_t backlog) {
}
// Implements the provider Accept operation.
static KSTATUS LwipProviderAccept(void* socket, void** acceptedOut, SYS_SOCKET_ADDRESS_K* remoteOut) {
static KSTATUS LwipProviderAccept(void* socket, void** acceptedOut, SYS_SOCKET_ADDRESS_K* remoteOut, volatile uint8_t* cancelRequested) {
LWIP_PROVIDER_SOCKET* s = (LWIP_PROVIDER_SOCKET*)socket;
if (!s || !acceptedOut)
return STATUS_INVALID_PARAMETER;
@@ -926,16 +1032,17 @@ static KSTATUS LwipProviderAccept(void* socket, void** acceptedOut, SYS_SOCKET_A
}
struct netconn* acceptedConn = NULL;
err_t err = netconn_accept(s->Conn, &acceptedConn);
err_t err = ERR_OK;
st = LwipSocketWaitAccept(s, &acceptedConn, cancelRequested, &err);
LwipSocketUnlock(s);
if (!KSUCCESS(st))
return st;
if (err != ERR_OK)
return LwipErrToStatus(err);
if (!acceptedConn)
return STATUS_FAILURE;
acceptedConn->callback = LwipSocketCallback;
LWIP_PROVIDER_SOCKET* accepted = NULL;
st = LwipSocketAllocateWithConn(s->Domain, s->Type, s->Protocol, acceptedConn, &accepted);
if (!KSUCCESS(st)) {
@@ -963,7 +1070,7 @@ static KSTATUS LwipProviderAccept(void* socket, void** acceptedOut, SYS_SOCKET_A
}
// Implements the provider Connect operation.
static KSTATUS LwipProviderConnect(void* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize) {
static KSTATUS LwipProviderConnect(void* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize, volatile uint8_t* cancelRequested) {
LWIP_PROVIDER_SOCKET* s = (LWIP_PROVIDER_SOCKET*)socket;
if (!s || !address)
return STATUS_INVALID_PARAMETER;
@@ -994,12 +1101,58 @@ static KSTATUS LwipProviderConnect(void* socket, const SYS_SOCKET_ADDRESS_K* add
return st;
}
err_t err = netconn_connect(s->Conn, &ip, address->Port);
if (err == ERR_OK)
s->Connected = 1;
if (!cancelRequested || s->Type != SYS_SOCK_STREAM) {
err_t err = netconn_connect(s->Conn, &ip, address->Port);
if (err == ERR_OK)
s->Connected = 1;
LwipSocketUnlock(s);
return LwipErrToStatus(err);
LwipSocketUnlock(s);
return LwipErrToStatus(err);
}
u8_t wasNonBlocking = netconn_is_nonblocking(s->Conn) ? 1 : 0;
netconn_set_nonblocking(s->Conn, 1);
err_t err = netconn_connect(s->Conn, &ip, address->Port);
if (err == ERR_OK) {
netconn_set_nonblocking(s->Conn, wasNonBlocking || s->NonBlocking);
s->Connected = 1;
LwipSocketUnlock(s);
return STATUS_SUCCESS;
}
if (err != ERR_INPROGRESS) {
netconn_set_nonblocking(s->Conn, wasNonBlocking || s->NonBlocking);
LwipSocketUnlock(s);
return LwipErrToStatus(err);
}
for (;;) {
if (LwipSocketCancelRequested(cancelRequested)) {
(void)netconn_close(s->Conn);
s->ShutdownRead = 1;
s->ShutdownWrite = 1;
netconn_set_nonblocking(s->Conn, wasNonBlocking || s->NonBlocking);
LwipSocketUnlock(s);
return STATUS_CANCELLED;
}
if (s->Conn->state != NETCONN_CONNECT) {
err = netconn_err(s->Conn);
netconn_set_nonblocking(s->Conn, wasNonBlocking || s->NonBlocking);
if (err == ERR_OK) {
s->Connected = 1;
LwipSocketUnlock(s);
return STATUS_SUCCESS;
}
LwipSocketUnlock(s);
return LwipErrToStatus(err);
}
LwipSocketUnlock(s);
(void)KeDelayThread(LWIP_PROVIDER_CANCEL_POLL_MS);
st = LwipSocketLock(s);
if (!KSUCCESS(st))
return st;
}
}
// Implements the provider Send operation.
@@ -1087,7 +1240,7 @@ static KSTATUS LwipReceiveFromBuffered(LWIP_PROVIDER_SOCKET* s, uint8_t* out,
}
// Implements the provider Receive operation.
static KSTATUS LwipProviderReceive(void* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut) {
static KSTATUS LwipProviderReceive(void* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut, volatile uint8_t* cancelRequested) {
LWIP_PROVIDER_SOCKET* s = (LWIP_PROVIDER_SOCKET*)socket;
if (receivedOut)
*receivedOut = 0;
@@ -1124,7 +1277,12 @@ static KSTATUS LwipProviderReceive(void* socket, void* buffer, size_t length, ui
if (copied == 0 && !s->ReceiveBuffer) {
struct netbuf* nb = NULL;
err_t err = netconn_recv(s->Conn, &nb);
err_t err = ERR_OK;
st = LwipSocketWaitRecvNetbuf(s, &nb, cancelRequested, &err);
if (!KSUCCESS(st)) {
LwipSocketUnlock(s);
return st;
}
if (err == ERR_CLSD) {
s->ShutdownRead = 1;
if (receivedOut)
@@ -1209,7 +1367,7 @@ static KSTATUS LwipProviderSendTo(void* socket, const void* buffer, size_t lengt
}
static KSTATUS LwipProviderReceiveFrom(void* socket, void* buffer, size_t length, uint32_t flags,
SYS_SOCKET_ADDRESS_K* remoteOut, size_t* receivedOut) {
SYS_SOCKET_ADDRESS_K* remoteOut, size_t* receivedOut, volatile uint8_t* cancelRequested) {
LWIP_PROVIDER_SOCKET* s = (LWIP_PROVIDER_SOCKET*)socket;
if (receivedOut)
*receivedOut = 0;
@@ -1236,7 +1394,12 @@ static KSTATUS LwipProviderReceiveFrom(void* socket, void* buffer, size_t length
}
struct netbuf* nb = NULL;
err_t err = netconn_recv(s->Conn, &nb);
err_t err = ERR_OK;
st = LwipSocketWaitRecvNetbuf(s, &nb, cancelRequested, &err);
if (!KSUCCESS(st)) {
LwipSocketUnlock(s);
return st;
}
if (err != ERR_OK) {
LwipSocketUnlock(s);
return LwipErrToStatus(err);
@@ -1449,6 +1612,109 @@ static KSTATUS LwipProviderResolveHost(const char* name, uint32_t family, SYS_SO
return STATUS_SUCCESS;
}
// Dispatches a provider-private socket request carried by an IRP.
static KSTATUS LwipDispatchSocketRequest(NET_SOCKET_IRP_REQUEST* request) {
if (!request || request->Size != sizeof(*request))
return STATUS_INVALID_PARAMETER;
switch (request->Operation) {
case NetSocketIrpCreate:
return LwipProviderSocketCreate(request->u.Create.Domain,
request->u.Create.Type,
request->u.Create.Protocol,
request->u.Create.ProviderSocketOut);
case NetSocketIrpClose:
LwipProviderSocketClose(request->u.Close.Socket);
return STATUS_SUCCESS;
case NetSocketIrpBind:
return LwipProviderBind(request->u.Bind.Socket,
request->u.Bind.Address,
request->u.Bind.AddressSize);
case NetSocketIrpListen:
return LwipProviderListen(request->u.Listen.Socket,
request->u.Listen.Backlog);
case NetSocketIrpAccept:
return LwipProviderAccept(request->u.Accept.Socket,
request->u.Accept.AcceptedOut,
request->u.Accept.RemoteOut,
request->CancelRequested);
case NetSocketIrpConnect:
return LwipProviderConnect(request->u.Connect.Socket,
request->u.Connect.Address,
request->u.Connect.AddressSize,
request->CancelRequested);
case NetSocketIrpSend:
return LwipProviderSend(request->u.Send.Socket,
request->u.Send.Buffer,
request->u.Send.Length,
request->u.Send.Flags,
request->u.Send.SentOut);
case NetSocketIrpReceive:
return LwipProviderReceive(request->u.Receive.Socket,
request->u.Receive.Buffer,
request->u.Receive.Length,
request->u.Receive.Flags,
request->u.Receive.ReceivedOut,
request->CancelRequested);
case NetSocketIrpSendTo:
return LwipProviderSendTo(request->u.SendTo.Socket,
request->u.SendTo.Buffer,
request->u.SendTo.Length,
request->u.SendTo.Flags,
request->u.SendTo.Remote,
request->u.SendTo.RemoteSize,
request->u.SendTo.SentOut);
case NetSocketIrpReceiveFrom:
return LwipProviderReceiveFrom(request->u.ReceiveFrom.Socket,
request->u.ReceiveFrom.Buffer,
request->u.ReceiveFrom.Length,
request->u.ReceiveFrom.Flags,
request->u.ReceiveFrom.RemoteOut,
request->u.ReceiveFrom.ReceivedOut,
request->CancelRequested);
case NetSocketIrpShutdown:
return LwipProviderShutdown(request->u.Shutdown.Socket,
request->u.Shutdown.How);
case NetSocketIrpSetOption:
return LwipProviderSetOption(request->u.SetOption.Socket,
request->u.SetOption.Option,
request->u.SetOption.Value,
request->u.SetOption.ValueSize);
case NetSocketIrpGetOption:
return LwipProviderGetOption(request->u.GetOption.Socket,
request->u.GetOption.Option,
request->u.GetOption.Value,
request->u.GetOption.ValueSize,
request->u.GetOption.ActualSizeOut);
case NetSocketIrpPoll:
return LwipProviderPoll(request->u.Poll.Socket,
request->u.Poll.Events,
request->u.Poll.ReturnedEventsOut);
case NetSocketIrpResolveHost:
return LwipProviderResolveHost(request->u.ResolveHost.Name,
request->u.ResolveHost.Family,
request->u.ResolveHost.AddressOut);
default:
return STATUS_INVALID_PARAMETER;
}
}
// Dispatches socket internal device controls for the lwIP stack device.
static KSTATUS LwipDispatchInternalDeviceControl(DEVICE_OBJECT* device, IRP* irp) {
(void)device;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios)
return STATUS_INVALID_PARAMETER;
if (ios->Parameters.DeviceIoControl.IoControlCode != NET_IOCTL_SOCKET)
return STATUS_NOT_SUPPORTED;
if (ios->Parameters.DeviceIoControl.InputLength < sizeof(NET_SOCKET_IRP_REQUEST))
return STATUS_BUFFER_TOO_SMALL;
NET_SOCKET_IRP_REQUEST* request = (NET_SOCKET_IRP_REQUEST*)ios->Parameters.DeviceIoControl.InputBuffer;
return LwipDispatchSocketRequest(request);
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const HAL_API* hal) {
DbgPrint("lwIP: driver loading...\n");
@@ -1467,6 +1733,23 @@ KSTATUS DriverEntry(const HAL_API* hal) {
return st;
}
IoInitializeDriverObject(&gLwipDriver, SYS_SV_LITERAL("lwip-stack"));
gLwipDriver.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = LwipDispatchInternalDeviceControl;
st = IoRegisterDriverObject(&gLwipDriver);
if (!KSUCCESS(st)) {
DbgPrint("lwIP: driver object registration failed: 0x%x\n", st);
return st;
}
st = IoCreateDevice(&gLwipDriver, 0, &gLwipDevice);
if (!KSUCCESS(st)) {
DbgPrint("lwIP: stack device creation failed: 0x%x\n", st);
return st;
}
(void)IoSetDeviceName(gLwipDevice, SYS_SV_LITERAL("lwip-stack"));
gLwipProvider.StackDevice = gLwipDevice;
st = NetRegisterStackProvider(&gLwipProvider);
if (!KSUCCESS(st)) {
DbgPrint("lwIP: provider registration failed: 0x%x\n", st);