Author: zhu
Date: Wed Aug 3 19:57:20 2016
New Revision: 72104
URL:
http://svn.reactos.org/svn/reactos?rev=72104&view=rev
Log:
Added global KMUTEX serializing all threads that access lwIP. Added global arrays to debug
IRPs. Implemented TDI_LISTEN handler. Made the Context mutex recursive within a thread.
Modified the way listening connection contexts are handled. Now creates a new TCP_CONTEXT
struct on a TDI_LISTEN, which dies on the TDI_LISTEN's cancellation.
Minor modifications to make some functions work better with the large changes. Removed the
majority of debug printout statements.
Modified:
branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.c
branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.h
branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/interface.c
branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/main.c
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/arch/sys_arch.h
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcp.h
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcpip.h
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/sys_arch.c
Modified: branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/drivers/ne…
==============================================================================
--- branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.c [iso-8859-1] (original)
+++ branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.c [iso-8859-1] Wed Aug 3
19:57:20 2016
@@ -13,7 +13,7 @@
#ifndef NDEBUG
/* Debug global variables, for convenience */
volatile long int AddrFileCount;
-volatile long int ContextCount;
+volatile long int GlContextCount;
volatile long int PcbCount;
PADDRESS_FILE AddrFileArray[16];
@@ -23,6 +23,20 @@
KSPIN_LOCK AddrFileArrayLock;
KSPIN_LOCK ContextArrayLock;
KSPIN_LOCK PCBArrayLock;
+
+#define _KeAcquireSpinLock(Lock,Irql) \
+ if (KeGetCurrentIrql() != 0) \
+ { \
+ DPRINT("\n Acquiring %p %s at IRQL %u\n", Lock, #Lock,
KeGetCurrentIrql()); \
+ }; \
+ KeAcquireSpinLock(Lock, Irql)
+
+#define _KeReleaseSpinLock(Lock,Irql) \
+ if (KeGetCurrentIrql() != 2) \
+ { \
+ DPRINT("\n Releasing %p %s at IRQL %u\n", Lock, #Lock,
KeGetCurrentIrql()); \
+ }; \
+ KeReleaseSpinLock(Lock, Irql)
#define ADD_ADDR_FILE(AddrFile) \
DPRINT("Adding Address File %p\n", AddrFile); \
@@ -77,21 +91,21 @@
#define ADD_CONTEXT(Context) \
DPRINT("Adding Context %p\n", Context); \
KeAcquireSpinLock(&ContextArrayLock, &OldIrql); \
- ContextArray[ContextCount] = Context; \
- ContextCount++; \
+ ContextArray[GlContextCount] = Context; \
+ GlContextCount++; \
KeReleaseSpinLock(&ContextArrayLock, OldIrql)
#define ADD_CONTEXT_DPC(Context) \
DPRINT("Adding Context %p\n", Context); \
KeAcquireSpinLockAtDpcLevel(&ContextArrayLock); \
- ContextArray[ContextCount] = Context; \
- ContextCount++; \
+ ContextArray[GlContextCount] = Context; \
+ GlContextCount++; \
KeReleaseSpinLockFromDpcLevel(&ContextArrayLock)
#define REMOVE_CONTEXT(Context) \
DPRINT("Removing Context %p\n", Context); \
KeAcquireSpinLock(&ContextArrayLock, &OldIrql); \
- for (i = 0; i < ContextCount; i++) \
+ for (i = 0; i < GlContextCount; i++) \
{ \
if (Context == ContextArray[i]) \
{ \
@@ -103,13 +117,13 @@
ContextArray[i+1] = NULL; \
} \
} \
- ContextCount--; \
+ GlContextCount--; \
KeReleaseSpinLock(&ContextArrayLock, OldIrql)
#define REMOVE_CONTEXT_DPC(Context) \
DPRINT("Removing Context %p\n", Context); \
KeAcquireSpinLockAtDpcLevel(&ContextArrayLock); \
- for (i = 0; i < ContextCount; i++) \
+ for (i = 0; i < GlContextCount; i++) \
{ \
if (Context == ContextArray[i]) \
{ \
@@ -121,7 +135,7 @@
ContextArray[i+1] = NULL; \
} \
} \
- ContextCount--; \
+ GlContextCount--; \
KeReleaseSpinLockFromDpcLevel(&ContextArrayLock)
#define ADD_PCB(pcb) \
@@ -202,6 +216,10 @@
static err_t lwip_tcp_receive_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,
err_t err);
static err_t lwip_tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len);
+/* Forward-declare helper function */
+VOID CloseAddress(PADDRESS_FILE AddressFile);
+NTSTATUS DisassociateAddress(PTCP_CONTEXT Context);
+
#define AddrIsUnspecified(Address) ((Address->in_addr == 0) || (Address->in_addr ==
0xFFFFFFFF))
#define TCP_SET_STATE(State,Context) \
@@ -214,6 +232,21 @@
DPRINT("Removing State %s from Context %p\n", #State, Context); \
Context->TcpState &= ~State
+/**
+ * Recursive mutex guarding a TCP_CONTEXT using a KSPIN_LOCK residing in the
Context's associated
+ * ADDRESS_FILE. This mutex guards against concurrent access from multiple execution
contexts if and
+ * only if the Context is associated with an Address File. If TcpIpAssociateAddress has
been called
+ * on a TCP_CONTEXT struct, this mutex should be held when reading from or writing to any
and all
+ * fields in the struct until TcpIpDisassociateAddress is call on the same struct.
+ *
+ * Mutex acquisition returns TRUE if the mutex has been acquired. Returns FALSE if the
mutex could
+ * not be acquired due to the Context having no association to any Address File.
+ *
+ * A disassociated context should be inherently safe from concurrent access because the
only
+ * remaining reference to it should reside in an lwIP Protocol Control Block as the
callback
+ * argument. Thus, lwIP callback functions can safely ignore the return value while all
other
+ * functions should treat a return value of FALSE as a non-recoverable error.
+ **/
VOID
InitializeContextMutex(
PTCP_CONTEXT Context
@@ -230,9 +263,14 @@
{
HANDLE Thread;
KIRQL OldIrql;
-
+
PADDRESS_FILE AddressFile;
PKSPIN_LOCK Lock;
+
+#ifndef NDEBUG
+ Thread = PsGetCurrentThreadId();
+ DPRINT("Thread %p acquiring lock on Context %p\n", Thread, Context);
+#endif
AddressFile = Context->AddressFile;
if (AddressFile == NULL)
@@ -242,9 +280,9 @@
return FALSE;
}
Lock = &AddressFile->AssociatedContextsLock;
-
+
Thread = PsGetCurrentThreadId();
-
+
AGAIN:
/* Start mutex acquisition */
KeAcquireSpinLock(Lock, &OldIrql);
@@ -261,12 +299,12 @@
KeReleaseSpinLock(Lock, OldIrql);
goto AGAIN;
}
-
+
/* We passed all tests, we have exclusive access to this Context. */
Context->MutexOwner = Thread;
KeReleaseSpinLock(Lock, OldIrql);
InterlockedIncrement(&Context->MutexDepth);
-
+
return TRUE;
}
@@ -275,9 +313,22 @@
PTCP_CONTEXT Context
)
{
- if (InterlockedDecrement(&Context->MutexDepth) == 0)
- {
- Context->MutexOwner = NULL;
+ HANDLE Thread;
+
+ Thread = PsGetCurrentThreadId();
+ DPRINT("Thread %p releasing lock on Context %p\n", Thread, Context);
+
+ /* If the releasing call came from the mutex owner, do release. Otherwise, do
nothing. */
+ if (Context->MutexOwner == Thread)
+ {
+ if (InterlockedDecrement(&Context->MutexDepth) == 0)
+ {
+ Context->MutexOwner = NULL;
+ }
+ }
+ else
+ {
+ DPRINT1("Release mutex from non-owner\n");
}
}
@@ -297,17 +348,17 @@
Request = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Request), TAG_TCP_REQUEST);
if (Request == NULL)
{
- DPRINT("Not enough resources\n");
+ DPRINT1("Not enough resources\n");
return STATUS_NO_MEMORY;
}
Request->Payload.PendingIrp = Payload;
Request->CancelMode = CancelMode;
Request->PendingMode = PendingMode;
Request->PayloadType = PayloadType;
-
+
/* Enqueue request into Context's request list */
InsertTailList(&Context->RequestListHead, &Request->ListEntry);
-
+
return STATUS_PENDING;
}
@@ -315,16 +366,14 @@
NTSTATUS
PrepareIrpForCancel(
PIRP Irp,
+ PTCP_CONTEXT Context,
PDRIVER_CANCEL CancelRoutine,
UCHAR CancelMode,
UCHAR PendingMode
)
{
NTSTATUS Status;
-
- PIO_STACK_LOCATION IrpSp;
- PTCP_CONTEXT Context;
-
+
/* Check that the IRP was not already cancelled */
if (Irp->Cancel)
{
@@ -333,17 +382,13 @@
Irp->IoStatus.Information = 0;
return STATUS_CANCELLED;
}
-
- /* Get TCP Context */
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
- Context = IrpSp->FileObject->FsContext;
-
+
/* Create and enqueue TCP Request */
Status = EnqueueRequest(Irp, Context, CancelMode, PendingMode,
TCP_REQUEST_PAYLOAD_IRP);
-
+
/* Set the IRP's Cancel routine */
IoSetCancelRoutine(Irp, CancelRoutine);
-
+
return Status;
}
@@ -361,17 +406,20 @@
#ifndef NDEBUG
KIRQL OldIrql;
INT i;
-#endif
+ PIO_STACK_LOCATION IrpSp;
+#endif
+ LONG ContextCount;
+
PIRP Irp;
PTCP_CONTEXT AcceptingContext;
-
+
/* If this was just a request completion, skip lwIP PCB cleanup and go straight to
IRP
* completion */
if (Status == STATUS_SUCCESS)
{
goto COMPLETE_IRP;
}
-
+
/* This is not a simple completion. Perform cleanup depending on Request payload
type. */
switch (Request->PayloadType)
{
@@ -379,29 +427,40 @@
/* The Request holds a pending IRP */
goto CLEANUP_PCB;
case TCP_REQUEST_PAYLOAD_CONTEXT :
- /* The Request holds a dummy Context meant incomming newly accepted
connections */
+ /* The Request holds a dummy Context meant for incomming newly accepted
connections */
AcceptingContext = Request->Payload.Context;
-
+
/* If an incomming connection has already been accepted, terminate it. */
if (Request->PendingMode == TCP_REQUEST_PENDING_ACCEPTED_CONNECTION)
{
#ifndef NDEBUG
REMOVE_PCB(AcceptingContext->lwip_tcp_pcb);
#endif
+ ACQUIRE_SERIAL_MUTEX();
tcp_close(AcceptingContext->lwip_tcp_pcb);
+ RELEASE_SERIAL_MUTEX();
}
-
- /* If we created the Context without a TDI_CREATE, deallocate it. */
- if (AcceptingContext->CreatedWithoutRequest == TRUE)
+
+ /* If the Context does not have an upper-level reference, deallocate it. */
+ if (AcceptingContext->ReferencedByUpperLayer == FALSE)
{
-
InterlockedDecrement(&AcceptingContext->AddressFile->ContextCount);
+ /* If removing this Context removes the last reference to its Address
File, also
+ * deallocate the Address File. */
+ ContextCount =
InterlockedDecrement(&AcceptingContext->AddressFile->ContextCount);
+ if (ContextCount < 1)
+ {
+ CloseAddress(AcceptingContext->AddressFile);
+ }
+#ifndef NDEBUG
+ REMOVE_CONTEXT(AcceptingContext);
+#endif
ExFreePoolWithTag(AcceptingContext, TAG_TCP_CONTEXT);
}
-
+
/* Skip IRP completion, because there is no IRP to complete. */
goto FINISH;
default :
- DPRINT("We should never reach here. Something is wrong.\n");
+ DPRINT1("We should never reach here. Something is wrong.\n");
goto FINISH;
}
@@ -416,10 +475,12 @@
#ifndef NDEBUG
REMOVE_PCB(Context->lwip_tcp_pcb);
#endif
+ ACQUIRE_SERIAL_MUTEX();
tcp_close(Context->lwip_tcp_pcb);
+ RELEASE_SERIAL_MUTEX();
Context->lwip_tcp_pcb = NULL;
}
- break;
+ goto COMPLETE_IRP;
case TCP_REQUEST_CANCEL_MODE_ABORT :
TCP_SET_STATE(TCP_STATE_ABORTED, Context);
if (Context->lwip_tcp_pcb != NULL)
@@ -427,10 +488,12 @@
#ifndef NDEBUG
REMOVE_PCB(Context->lwip_tcp_pcb);
#endif
+ ACQUIRE_SERIAL_MUTEX();
tcp_abort(Context->lwip_tcp_pcb);
+ RELEASE_SERIAL_MUTEX();
Context->lwip_tcp_pcb = NULL;
}
- break;
+ goto COMPLETE_IRP;
case TCP_REQUEST_CANCEL_MODE_PRESERVE :
/* For requests that do not deallocate the PCB when cancelled, determine and
clear the
* appropriate TCP State bit */
@@ -443,21 +506,26 @@
TCP_RMV_STATE(TCP_STATE_RECEIVING, Context);
break;
default :
- DPRINT("We should never reach here. Something is
wrong.\n");
+ DPRINT1("We should never reach here. Something is
wrong.\n");
goto FINISH;
}
- break;
+ goto COMPLETE_IRP;
default :
- DPRINT("We should never reach here. Something is wrong.\n");
+ DPRINT1("We should never reach here. Something is wrong.\n");
goto FINISH;
}
-
+
COMPLETE_IRP:
/* Complete the IRP */
Irp = Request->Payload.PendingIrp;
Irp->IoStatus.Status = Status;
+#ifndef NDEBUG
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
-
+
FINISH:
/* Deallocate the TCP Request */
ExFreePoolWithTag(Request, TAG_TCP_REQUEST);
@@ -470,18 +538,23 @@
_Inout_ _IRQL_uses_cancel_ struct _IRP *Irp
)
{
+#ifndef NDEBUG
+ INT i;
+ KIRQL OldIrql;
+#endif
+
PIO_STACK_LOCATION IrpSp;
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PTCP_CONTEXT Context;
PTCP_REQUEST Request;
-
+
/* Block potential repeated cancellations */
IoSetCancelRoutine(Irp, NULL);
-
+
/* This function is always called with the Cancel lock held */
IoReleaseCancelSpinLock(Irp->CancelIrql);
-
+
/* The file types distinguishes between some protocols */
IrpSp = IoGetCurrentIrpStackLocation(Irp);
switch ((ULONG)IrpSp->FileObject->FsContext2)
@@ -491,46 +564,79 @@
case TDI_CONNECTION_FILE :
goto TCP_CANCEL;
default :
- DPRINT("IRP does not contain a valid FileObject\n");
+ DPRINT1("IRP does not contain a valid FileObject\n");
goto FINISH;
}
-
+
DGRAM_CANCEL:
- DPRINT("Datagram cancel not yet implemented\n");
+ DPRINT1("Datagram cancel not yet implemented\n");
goto FINISH;
-
+
TCP_CANCEL:
Context = IrpSp->FileObject->FsContext;
GetExclusiveContextAccess(Context);
+ /* If this is a cancellation on a TDI_LISTEN request, we need to disassociate and
close the
+ * Context. AFD does not know about the extra Context we keep for listening sockets.
AFD only
+ * cares about actual connection endpoints. */
+ if (IrpSp->MinorFunction == TDI_LISTEN)
+ {
+ /* Disassociate the listening Context, which we grab from the AddressFile. */
+ Context = Context->AddressFile->Listener;
+ DisassociateAddress(Context);
+
+ /* If the lwIP PCB still exists, close it. Since we are deallocating the
PCB's associated
+ * Context, we also need to clear the Context pointer in the PCB. */
+ if (Context->lwip_tcp_pcb)
+ {
+#ifndef NDEBUG
+ REMOVE_PCB(Context->lwip_tcp_pcb);
+#endif
+ ACQUIRE_SERIAL_MUTEX();
+ tcp_arg(Context->lwip_tcp_pcb, NULL);
+ tcp_close(Context->lwip_tcp_pcb);
+ RELEASE_SERIAL_MUTEX();
+ }
+
+ /* Deallocate the Context. The corresponding Address File's ContextCount
should have been
+ * decremented when the Context was disassociated. */
+#ifndef NDEBUG
+ REMOVE_CONTEXT(Context);
+#endif
+ ExFreePoolWithTag(Context, TAG_TCP_CONTEXT);
+
+ return;
+ }
+
/* Walk the TCP Context's list of requests to find one with this IRP */
Head = &Context->RequestListHead;
Entry = Head->Flink;
while (Entry != Head)
{
Request = CONTAINING_RECORD(Entry, TCP_REQUEST, ListEntry);
-
- /* Finding a matching request and entering this IF statement releases the list
lock and
- * returns */
+
if (Request->Payload.PendingIrp == Irp)
{
/* Immediately remove the request from the queue before processing */
- DPRINT("Dequeueing Pending Request from %p\n", Context);
RemoveEntryList(&Request->ListEntry);
Irp->IoStatus.Information = 0;
CleanupRequest(Request, STATUS_CANCELLED, Context);
ReleaseExclusiveContextAccess(Context);
return;
}
-
+
Entry = Entry->Flink;
}
-
+
ReleaseExclusiveContextAccess(Context);
-
- DPRINT("Did not find a matching TCP Request, we may leave a dead IRP pointer
somewhere\n");
+
+ DPRINT1("Did not find a matching TCP Request, we may leave a dead IRP pointer
somewhere\n");
FINISH:
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return;
}
@@ -543,7 +649,7 @@
#ifndef NDEBUG
AddrFileCount = 0;
- ContextCount = 0;
+ GlContextCount = 0;
PcbCount = 0;
KeInitializeSpinLock(&AddrFileArrayLock);
@@ -564,7 +670,7 @@
{
PADDRESS_FILE AddressFile;
PLIST_ENTRY Entry;
-
+
/* If a netif is specified, check for AddressFile with matching netif and port in
order to
* detect duplicates */
if (lwip_netif != NULL)
@@ -600,7 +706,7 @@
AddressFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*AddressFile),
TAG_ADDRESS_FILE);
if (AddressFile == NULL)
{
- DPRINT("Not enough resources\n");
+ DPRINT1("Not enough resources\n");
return STATUS_NO_MEMORY;
}
#ifndef NDEBUG
@@ -632,7 +738,7 @@
/* TCP variables */
AddressFile->HasListener = FALSE;
KeInitializeSpinLock(&AddressFile->AssociatedContextsLock);
-
+
/* UDP and RAW variables */
KeInitializeSpinLock(&AddressFile->RequestLock);
InitializeListHead(&AddressFile->RequestListHead);
@@ -644,7 +750,7 @@
FINISH:
/* Output the Address File */
*_AddressFile = AddressFile;
-
+
return STATUS_SUCCESS;
}
@@ -662,8 +768,6 @@
struct netif *lwip_netif;
ip_addr_t IpAddr;
-
- DPRINT("TcpIpcreateAddress(PIRP %p, PTDI_ADDRESS %p, IPPROTO %d)\n", Irp,
Address, Protocol);
/* For a specified address, find a matching netif and, if needed, a free port. For
unspecified
* addresses, the lwip_netif is set to NULL. */
@@ -684,14 +788,16 @@
Status = STATUS_INVALID_ADDRESS;
goto FAIL;
}
-
+
/* If port is unspecified, grab a free port from lwIP */
if (Address->sin_port == 0)
{
switch (Protocol)
{
case IPPROTO_TCP :
+ ACQUIRE_SERIAL_MUTEX();
Address->sin_port = (USHORT)tcp_new_port();
+ RELEASE_SERIAL_MUTEX();
break;
case IPPROTO_UDP :
Address->sin_port = (USHORT)udp_new_port();
@@ -741,7 +847,7 @@
IrpSp->FileObject->FsContext = AddressFile;
IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
}
-
+
return Status;
}
@@ -754,13 +860,13 @@
INT i;
#endif
KIRQL OldIrql;
-
+
/* Remove the Address File from global lists before further processing */
KeAcquireSpinLock(&AddressListLock, &OldIrql);
RemoveEntryList(&AddressFile->ListEntry);
KeReleaseSpinLock(&AddressListLock, OldIrql);
RemoveEntityInstance(&AddressFile->Instance);
-
+
/* For ICMP, RAW, UDP addresses, we need to deallocate the lwIP PCB */
switch (AddressFile->Protocol)
{
@@ -776,11 +882,11 @@
goto NO_REQUESTS;
default :
/* We should never reach here */
- DPRINT("Closing Address File with unknown protocol, %d. This should
never happen.\n",
+ DPRINT1("Closing Address File with unknown protocol, %d. This should
never happen.\n",
AddressFile->Protocol);
break;
}
-
+
/* Finish pending requests for RAW and UDP addresses */
NO_REQUESTS:
@@ -796,8 +902,6 @@
_In_ PADDRESS_FILE AddressFile
)
{
- DPRINT("TcpIpCloseAddress(PADDRESS_FILE %p)\n", AddressFile);
-
/* Check if there are still references to this Address File */
if (InterlockedDecrement(&AddressFile->RefCount) > 0)
{
@@ -813,7 +917,7 @@
}
CloseAddress(AddressFile);
-
+
return STATUS_SUCCESS;
}
@@ -829,13 +933,11 @@
#endif
PIO_STACK_LOCATION IrpSp;
PTCP_CONTEXT Context;
-
- DPRINT("TcpIpCreateContext(PIRP %p, PTDI_ADDRESS_IP %p, IPPROTO %d)\n",
Irp, Address, Protocol);
/* Do not support anything other than TCP right now */
if (Protocol != IPPROTO_TCP)
{
- DPRINT("Creating connection context for non-TCP protocol: %d\n",
Protocol);
+ DPRINT1("Creating connection context for non-TCP protocol: %d\n",
Protocol);
return STATUS_INVALID_PARAMETER;
}
@@ -843,7 +945,7 @@
Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Context), TAG_TCP_CONTEXT);
if (Context == NULL)
{
- DPRINT("Not enough resources\n");
+ DPRINT1("Not enough resources\n");
return STATUS_NO_MEMORY;
}
#ifndef NDEBUG
@@ -854,9 +956,9 @@
TCP_SET_STATE(TCP_STATE_CREATED, Context);
Context->AddressFile = NULL;
InitializeListHead(&Context->RequestListHead);
- Context->CreatedWithoutRequest = FALSE;
+ Context->ReferencedByUpperLayer = TRUE;
InitializeContextMutex(Context);
-
+
/* We defer PCB creation until TcpIpAssociateAddress(), since this Context could be a
dummy
* connection endpoint used to poll/wait for new accepted connections */
Context->lwip_tcp_pcb = NULL;
@@ -879,15 +981,13 @@
KIRQL OldIrql;
#endif
- DPRINT("TcpIpCloseContext(PTCP_CONTEXT %p)\n", Context);
-
/* Sanity check */
if (Context->AddressFile != NULL)
{
- DPRINT("Context retains address association\n");
+ DPRINT1("Context retains address association\n");
return STATUS_INVALID_PARAMETER;
}
-
+
/* If the lwIP PCB still exists, close it. Since we are deallocating the PCB's
associated
* Context, we also need to clear the Context pointer in the PCB. */
if (Context->lwip_tcp_pcb)
@@ -895,17 +995,19 @@
#ifndef NDEBUG
REMOVE_PCB(Context->lwip_tcp_pcb);
#endif
+ ACQUIRE_SERIAL_MUTEX();
tcp_arg(Context->lwip_tcp_pcb, NULL);
tcp_close(Context->lwip_tcp_pcb);
- }
-
+ RELEASE_SERIAL_MUTEX();
+ }
+
/* Deallocate the Context. The corresponding Address File's ContextCount should
have been
* decremented when the Context was disassociated. */
#ifndef NDEBUG
REMOVE_CONTEXT(Context);
#endif
ExFreePoolWithTag(Context, TAG_TCP_CONTEXT);
-
+
return STATUS_SUCCESS;
}
@@ -916,16 +1018,14 @@
{
KIRQL OldIrql;
NTSTATUS Status;
-
+
PADDRESS_FILE AddressFile;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION IrpSp;
PTCP_CONTEXT Context;
PTDI_REQUEST_KERNEL_ASSOCIATE RequestInfo;
-
+
err_t lwip_err;
-
- DPRINT("TcpIpAssociateAddress(PIRP %p)\n", Irp);
IrpSp = IoGetCurrentIrpStackLocation(Irp);
@@ -940,12 +1040,12 @@
NULL);
if (Status != STATUS_SUCCESS)
{
- DPRINT("Failed to dereference FileObject: 0x%08x\n", Status);
+ DPRINT1("Failed to dereference FileObject: 0x%08x\n", Status);
return Status;
}
if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
{
- DPRINT("File object should be an Address File\n");
+ DPRINT1("File object should be an Address File\n");
ObDereferenceObject(FileObject);
return STATUS_INVALID_PARAMETER;
}
@@ -954,7 +1054,7 @@
/* Get the TCP Context we are associating */
if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
{
- DPRINT("File object should be a TCP Context\n");
+ DPRINT1("File object should be a TCP Context\n");
ObDereferenceObject(FileObject);
return STATUS_INVALID_PARAMETER;
}
@@ -963,11 +1063,11 @@
/* Sanity checks */
if ((AddressFile->Protocol != IPPROTO_TCP) || (Context->TcpState !=
TCP_STATE_CREATED))
{
- DPRINT("We should be associating a new TCP Context with a TCP Address
File\n");
+ DPRINT1("We should be associating a new TCP Context with a TCP Address
File\n");
ObDereferenceObject(FileObject);
return STATUS_INVALID_PARAMETER;
}
-
+
/* If there is already a listener listening on the address, then this is a dummy
connection
* endpoint used to poll/wait for new accepted connections. In this case, we skip
creating and
* binding a new PCB. */
@@ -975,15 +1075,16 @@
{
goto NO_PCB;
}
-
+
/* Create a new lwIP PCB and initialize callback data */
Context->lwip_tcp_pcb = tcp_new();
#ifndef NDEBUG
ADD_PCB(Context->lwip_tcp_pcb);
#endif
+ ACQUIRE_SERIAL_MUTEX();
tcp_arg(Context->lwip_tcp_pcb, Context);
tcp_err(Context->lwip_tcp_pcb, lwip_tcp_err_callback);
-
+
/* Attempt to bind the PCB. lwIP internally handles INADDR_ANY. */
lwip_err = tcp_bind(
Context->lwip_tcp_pcb,
@@ -997,70 +1098,63 @@
}
case (ERR_BUF) :
{
- DPRINT("lwIP ERR_BUFF\n");
+ RELEASE_SERIAL_MUTEX();
+ DPRINT1("lwIP ERR_BUFF\n");
Status = STATUS_NO_MEMORY;
goto FINISH;
}
case (ERR_VAL) :
{
- DPRINT("lwIP ERR_VAL\n");
+ RELEASE_SERIAL_MUTEX();
+ DPRINT1("lwIP ERR_VAL\n");
Status = STATUS_INVALID_PARAMETER;
goto FINISH;
}
case (ERR_USE) :
{
- DPRINT("lwIP ERR_USE\n");
+ RELEASE_SERIAL_MUTEX();
+ DPRINT1("lwIP ERR_USE\n");
Status = STATUS_ADDRESS_ALREADY_EXISTS;
goto FINISH;
}
default :
{
- DPRINT("lwIP unexpected error\n");
+ RELEASE_SERIAL_MUTEX();
+ DPRINT1("lwIP unexpected error\n");
// TODO: better return code
Status = STATUS_UNSUCCESSFUL;
goto FINISH;
}
}
ip_set_option(Context->lwip_tcp_pcb, SOF_BROADCAST);
+ RELEASE_SERIAL_MUTEX();
NO_PCB:
/* Failure would jump us beyond here, so being here means we succeeded in binding */
TCP_SET_STATE(TCP_STATE_BOUND, Context);
Context->AddressFile = AddressFile;
InterlockedIncrement(&AddressFile->ContextCount);
-
+
Status = STATUS_SUCCESS;
-
+
FINISH:
return Status;
}
+/* This function does not require the Context mutex to be held. Holding the mutex while
calling will
+ * succeed but will decrease performance, since the mutex will be acquired recursively.
*/
NTSTATUS
-TcpIpDisassociateAddress(
- _Inout_ PIRP Irp
+DisassociateAddress(
+ PTCP_CONTEXT Context
)
{
- INT ContextCount;
-
+ LONG ContextCount;
+
PADDRESS_FILE AddressFile;
- PIO_STACK_LOCATION IrpSp;
PIRP PendingIrp;
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
- PTCP_CONTEXT Context;
PTCP_REQUEST Request;
-
- DPRINT("TcpIpDisassociateAddress(PIRP %p)\n", Irp);
-
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
- /* Sanity checks */
- if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
- {
- DPRINT("Disassociating something that is not a TCP Context\n");
- return STATUS_INVALID_PARAMETER;
- }
- Context = IrpSp->FileObject->FsContext;
/* Immediately remove the Context's association with its Address File */
if (GetExclusiveContextAccess(Context) == FALSE)
@@ -1081,19 +1175,18 @@
Request = CONTAINING_RECORD(Entry, TCP_REQUEST, ListEntry);
Entry = Entry->Flink;
RemoveEntryList(&Request->ListEntry);
-
+
/* If this is an IRP, block potential cancellations. */
if (Request->PayloadType == TCP_REQUEST_PAYLOAD_IRP)
{
PendingIrp = Request->Payload.PendingIrp;
- DPRINT("Disassociating Context %p with outstanding IRP %p\n",
Context, PendingIrp);
IoSetCancelRoutine(PendingIrp, NULL);
}
-
+
/* Clean up the Request */
CleanupRequest(Request, STATUS_CANCELLED, Context);
}
-
+
/* Decrement the corresponding Address File's ContextCount, remove the Address
File if needed */
if (AddressFile != NULL)
{
@@ -1103,8 +1196,29 @@
CloseAddress(AddressFile);
}
}
-
+
return STATUS_SUCCESS;
+}
+
+NTSTATUS
+TcpIpDisassociateAddress(
+ _Inout_ PIRP Irp
+)
+{
+ PIO_STACK_LOCATION IrpSp;
+ PTCP_CONTEXT Context;
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* Sanity checks */
+ if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
+ {
+ DPRINT1("Disassociating something that is not a TCP Context\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+ Context = IrpSp->FileObject->FsContext;
+
+ return DisassociateAddress(Context);
}
NTSTATUS
@@ -1117,6 +1231,7 @@
KIRQL OldIrql;
#endif
NTSTATUS Status;
+ LONG ContextCount;
PADDRESS_FILE AddressFile;
PLIST_ENTRY Entry;
@@ -1125,15 +1240,13 @@
PTCP_CONTEXT Context;
PTCP_CONTEXT ListenContext;
PTCP_REQUEST Request;
-
- DPRINT("TcpIpListen(PIRP %p)\n", Irp);
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
+
/* Grab TCP Context from IRP */
if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
{
- DPRINT("Not a connection context\n");
+ DPRINT1("Not a connection context\n");
return STATUS_INVALID_PARAMETER;
}
Context = IrpSp->FileObject->FsContext;
@@ -1145,11 +1258,11 @@
}
if (Context->TcpState != TCP_STATE_BOUND)
{
- DPRINT("Context is not a bound context\n");
+ DPRINT1("Context is not a bound context\n");
ReleaseExclusiveContextAccess(Context);
return STATUS_INVALID_PARAMETER;
}
-
+
AddressFile = Context->AddressFile;
/* If there is already a listener on the address, this context is a dummy connection
endpoint
* used to poll/wait for new accepted connections. Check for queued accepted
connections. If
@@ -1157,7 +1270,14 @@
if (AddressFile->HasListener == TRUE)
{
ListenContext = AddressFile->Listener;
-
+ if (GetExclusiveContextAccess(ListenContext) == FALSE)
+ {
+ DPRINT1("TDI_LISTEN on disassociated Listen Context? SNAFU.\n");
+ ReleaseExclusiveContextAccess(ListenContext);
+ ReleaseExclusiveContextAccess(Context);
+ return STATUS_ADDRESS_CLOSED;
+ }
+
/* Check for queued accepted connections in the listener's Request queue */
Head = &ListenContext->RequestListHead;
Entry = Head->Flink;
@@ -1167,10 +1287,11 @@
if (Request->PendingMode == TCP_REQUEST_PENDING_ACCEPTED_CONNECTION)
{
RemoveEntryList(&Request->ListEntry);
+ ReleaseExclusiveContextAccess(ListenContext);
goto CONNECTION_AVAILABLE;
}
}
-
+
/* If there is no queued accepted connection, enqueue a Request with the new
Context as the
* payload, then enqueue the IRP. Finding a queued accepted connection jumps
beyond here. */
EnqueueRequest(
@@ -1179,76 +1300,120 @@
TCP_REQUEST_CANCEL_MODE_PRESERVE,
TCP_REQUEST_PENDING_LISTEN_POLL,
TCP_REQUEST_PAYLOAD_CONTEXT);
-
- /* Enqueue the IRP. First set the FsContext, since that is where
PrepareIrpForCancel() gets
- * the reference to the owning Context. */
- IrpSp->FileObject->FsContext = ListenContext;
+
+ /* Enqueue the IRP */
Status = PrepareIrpForCancel(
Irp,
+ ListenContext,
CancelRequestRoutine,
TCP_REQUEST_CANCEL_MODE_CLOSE,
TCP_REQUEST_PENDING_LISTEN);
-
+
+ ReleaseExclusiveContextAccess(ListenContext);
ReleaseExclusiveContextAccess(Context);
return Status;
-
+
CONNECTION_AVAILABLE:
/* If there is a queued accepted connection, deallocate the Context that came
with the IRP
* and return the Context that is in the queue with IRP. */
#ifndef NDEBUG
REMOVE_CONTEXT(Context);
#endif
- InterlockedDecrement(&Context->AddressFile->ContextCount);
+ ContextCount =
InterlockedDecrement(&Context->AddressFile->ContextCount);
+ if (ContextCount < 1)
+ {
+ CloseAddress(Context->AddressFile);
+ }
+ Context->AddressFile = NULL;
+ ReleaseExclusiveContextAccess(Context);
ExFreePoolWithTag(Context, TAG_TCP_CONTEXT);
-
+
/* Set the IRP's FileObject to point to the queued Context. We also need to
mark this
* Context as created through a request by an upper level driver, since it
replaces one that
* actually was created that way. */
Context = Request->Payload.Context;
TCP_SET_STATE(TCP_STATE_CONNECTED, Context);
IrpSp->FileObject->FsContext = Context;
- Context->CreatedWithoutRequest = TRUE;
-
+ Context->ReferencedByUpperLayer = TRUE;
+
/* Inform lwIP that we accepted the connection */
+ ACQUIRE_SERIAL_MUTEX();
tcp_accepted(ListenContext->lwip_tcp_pcb);
-
+ RELEASE_SERIAL_MUTEX();
+
ExFreePoolWithTag(Request, TAG_TCP_REQUEST);
-
+
+ /* main.c will call IoCompleteRequest() on this IRP */
+ return STATUS_SUCCESS;
+ }
+
+ /* If there is not already a listener on the address, create a Listen Context and
enqueue the
+ * existing Context as a dummy Context. We will later perform our own disassociation
and closure
+ * on the Listen Context. */
+ /* Create context */
+ ListenContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ListenContext),
TAG_TCP_CONTEXT);
+ if (ListenContext == NULL)
+ {
+ DPRINT1("Not enough resources\n");
ReleaseExclusiveContextAccess(Context);
- return STATUS_SUCCESS;
- }
+ return STATUS_NO_MEMORY;
+ }
+#ifndef NDEBUG
+ ADD_CONTEXT(ListenContext);
+#endif
+
+ /* Set initial values */
+ ListenContext->AddressFile = AddressFile;
+ InitializeListHead(&ListenContext->RequestListHead);
+ ListenContext->ReferencedByUpperLayer = FALSE;
+ InitializeContextMutex(ListenContext);
+ InterlockedIncrement(&AddressFile->ContextCount);
- /* If there is not already a listener on the address, call into lwIP to initiate
Listen */
+ /* Call into lwIP to initiate Listen */
#ifndef NDEBUG
REMOVE_PCB(Context->lwip_tcp_pcb);
#endif
- Context->lwip_tcp_pcb = tcp_listen(Context->lwip_tcp_pcb);
- if (Context->lwip_tcp_pcb == NULL)
+ ACQUIRE_SERIAL_MUTEX();
+ ListenContext->lwip_tcp_pcb = tcp_listen(Context->lwip_tcp_pcb);
+ RELEASE_SERIAL_MUTEX();
+ if (ListenContext->lwip_tcp_pcb == NULL)
{
DPRINT("Bind failed\n");
ReleaseExclusiveContextAccess(Context);
return STATUS_INVALID_ADDRESS;
}
-#ifndef NDEBUG
- ADD_PCB(Context->lwip_tcp_pcb);
-#endif
-
+ Context->lwip_tcp_pcb = NULL;
+#ifndef NDEBUG
+ ADD_PCB(ListenContext->lwip_tcp_pcb);
+#endif
+
/* Set lwIP callback information for new PCB */
- tcp_accept(Context->lwip_tcp_pcb, lwip_tcp_accept_callback);
+ ACQUIRE_SERIAL_MUTEX();
+ tcp_arg(ListenContext->lwip_tcp_pcb, ListenContext);
+ tcp_accept(ListenContext->lwip_tcp_pcb, lwip_tcp_accept_callback);
+ RELEASE_SERIAL_MUTEX();
/* Mark the Address File as having a listener */
AddressFile->HasListener = TRUE;
- AddressFile->Listener = Context;
+ AddressFile->Listener = ListenContext;
- /* Mark IRP as pending and enqueue the Listen Request */
- DPRINT("Queueing TDI_LISTEN\n");
+ /* Enqueue the dummy Context to receive new connections */
+ EnqueueRequest(
+ Context,
+ ListenContext,
+ TCP_REQUEST_CANCEL_MODE_PRESERVE,
+ TCP_REQUEST_PENDING_LISTEN_POLL,
+ TCP_REQUEST_PAYLOAD_CONTEXT);
+
+ /* Mark IRP as pending and enqueue the Listen Request on the Listen Context */
Status = PrepareIrpForCancel(
Irp,
+ ListenContext,
CancelRequestRoutine,
TCP_REQUEST_CANCEL_MODE_CLOSE,
TCP_REQUEST_PENDING_LISTEN);
- TCP_SET_STATE(TCP_STATE_LISTENING, Context);
-
+ TCP_SET_STATE(TCP_STATE_LISTENING, ListenContext);
+
ReleaseExclusiveContextAccess(Context);
return Status;
}
@@ -1259,103 +1424,131 @@
)
{
NTSTATUS Status;
-
+
PIO_STACK_LOCATION IrpSp;
PTCP_CONTEXT Context;
PTDI_REQUEST_KERNEL_CONNECT RequestInfo;
PTRANSPORT_ADDRESS RemoteTransportAddress;
-
+
struct sockaddr *SocketAddressRemote;
struct sockaddr_in * SocketAddressInRemote;
-
+
err_t lwip_err;
-
- DPRINT("TcpIpConnect(PIRP %p)\n", Irp);
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
- DPRINT("Sanity checks\n");
+
/* Sanity checks */
if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
{
- DPRINT("File object is not a connection context\n");
+ DPRINT1("File object is not a connection context\n");
return STATUS_INVALID_PARAMETER;
}
Context = IrpSp->FileObject->FsContext;
if (GetExclusiveContextAccess(Context) == FALSE)
{
- DPRINT("Context has been disassociated\n");
+ DPRINT1("Context has been disassociated\n");
ReleaseExclusiveContextAccess(Context);
return STATUS_ADDRESS_CLOSED;
}
if (Context->TcpState != TCP_STATE_BOUND)
{
- DPRINT("Connecting from unbound socket\n");
+ DPRINT1("Connecting from unbound socket\n");
ReleaseExclusiveContextAccess(Context);
return STATUS_INVALID_PARAMETER;
}
-
- DPRINT("Extract remote address\n");
+
/* Extract remote address to connect to */
RequestInfo = (PTDI_REQUEST_KERNEL_CONNECT)&IrpSp->Parameters;
RemoteTransportAddress =
RequestInfo->RequestConnectionInformation->RemoteAddress;
SocketAddressRemote = (struct sockaddr *)&RemoteTransportAddress->Address[0];
SocketAddressInRemote = (struct sockaddr_in *)&SocketAddressRemote->sa_data;
-
- DPRINT("lwIP tcp_connect()\n");
+
/* Call into lwIP to initiate Connect */
+ ACQUIRE_SERIAL_MUTEX();
lwip_err = tcp_connect(Context->lwip_tcp_pcb,
(ip_addr_t*)&SocketAddressInRemote->sin_addr.s_addr,
SocketAddressInRemote->sin_port,
lwip_tcp_connected_callback);
+ RELEASE_SERIAL_MUTEX();
switch (lwip_err)
{
case ERR_OK :
- DPRINT("Queueing TDI_CONNECT\n");
/* If successful, enqueue the IRP, set the TCP State variable, and return */
Status = PrepareIrpForCancel(
Irp,
+ Context,
CancelRequestRoutine,
TCP_REQUEST_CANCEL_MODE_ABORT,
TCP_REQUEST_PENDING_CONNECT);
TCP_SET_STATE(TCP_STATE_CONNECTING, Context);
goto FINISH;
case ERR_VAL :
- DPRINT("lwip ERR_VAL\n");
+ DPRINT1("lwip ERR_VAL\n");
Status = STATUS_INVALID_PARAMETER;
goto FINISH;
case ERR_ISCONN :
- DPRINT("lwip ERR_ISCONN\n");
+ DPRINT1("lwip ERR_ISCONN\n");
Status = STATUS_CONNECTION_ACTIVE;
goto FINISH;
case ERR_RTE :
- DPRINT("lwip ERR_RTE\n");
+ DPRINT1("lwip ERR_RTE\n");
Status = STATUS_NETWORK_UNREACHABLE;
goto FINISH;
case ERR_BUF :
/* Use correct error once NDIS errors are included.
* This return value means local port unavailable. */
- DPRINT("lwip ERR_BUF\n");
+ DPRINT1("lwip ERR_BUF\n");
Status = STATUS_ADDRESS_ALREADY_EXISTS;
goto FINISH;
case ERR_USE :
- DPRINT("lwip ERR_USE\n");
+ DPRINT1("lwip ERR_USE\n");
Status = STATUS_CONNECTION_ACTIVE;
goto FINISH;
case ERR_MEM :
- DPRINT("lwip ERR_MEM\n");
+ DPRINT1("lwip ERR_MEM\n");
Status = STATUS_NO_MEMORY;
goto FINISH;
default :
/* unknown return value */
- DPRINT("lwip unknown return code\n");
+ DPRINT1("lwip unknown return code\n");
Status = STATUS_NOT_IMPLEMENTED;
goto FINISH;
}
-
+
FINISH:
ReleaseExclusiveContextAccess(Context);
return Status;
+}
+
+NTSTATUS
+TcpIpDisconnect(
+ _Inout_ PIRP Irp
+)
+{
+#ifndef NDEBUG
+ INT i;
+ KIRQL OldIrql;
+#endif
+
+ PIO_STACK_LOCATION IrpSp;
+ PTCP_CONTEXT Context;
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* Sanity checks. We do not acquire the Context mutex because TDI_DISCONNECT results
from an
+ * IoCompleteRequest() called with the Context mutex held. */
+ if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
+ {
+ DPRINT1("Disconnection on something that is not a TCP Context\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Mark the Context for disconnect. Do not shut down the PCB, because this function
is called
+ * while another thread context holds the global MTSerialMutex. */
+ Context = IrpSp->FileObject->FsContext;
+ TCP_SET_STATE(TCP_STATE_CLOSED, Context);
+
+ return STATUS_SUCCESS;
}
NTSTATUS
@@ -1365,15 +1558,13 @@
{
PIO_STACK_LOCATION IrpSp;
PTCP_CONTEXT Context;
-
- DPRINT1("TcpIpReceive(PIRP %p)\n", Irp);
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
+
/* Sanity checks */
if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
{
- DPRINT("Received TDI_RECEIVE for something that is not a TCP
Context\n");
+ DPRINT1("Received TDI_RECEIVE for something that is not a TCP
Context\n");
return STATUS_INVALID_PARAMETER;
}
Context = IrpSp->FileObject->FsContext;
@@ -1385,25 +1576,25 @@
}
if (!(Context->TcpState & TCP_STATE_CONNECTED))
{
- DPRINT("TCP Context %p is in the wrong state for receiving data:
%08x\n",
+ DPRINT1("TCP Context %p is in the wrong state for receiving data:
%08x\n",
Context,
Context->TcpState);
ReleaseExclusiveContextAccess(Context);
return STATUS_ADDRESS_CLOSED;
}
-
+
/* No need to call into lwIP. The Receive callback should have been set when the
connection was
* established. */
-
+
/* Mark IRP as pending, and the TCP Context as Receiving */
- DPRINT("Queueing TDI_RECEIVE\n");
PrepareIrpForCancel(
Irp,
+ Context,
CancelRequestRoutine,
TCP_REQUEST_CANCEL_MODE_PRESERVE,
TCP_REQUEST_PENDING_RECEIVE);
TCP_ADD_STATE(TCP_STATE_RECEIVING, Context);
-
+
ReleaseExclusiveContextAccess(Context);
return STATUS_PENDING;
}
@@ -1415,50 +1606,50 @@
{
NTSTATUS Status;
UINT SendBytes;
-
+
PIO_STACK_LOCATION IrpSp;
PTDI_REQUEST_KERNEL_SEND RequestInfo;
PTCP_CONTEXT Context;
PVOID Buffer;
-
+
err_t lwip_err;
-
- DPRINT("TcpIpSend(PIRP %p)\n", Irp);
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
+
/* Sanity checks */
if (IrpSp->FileObject->FsContext2 != (PVOID)TDI_CONNECTION_FILE)
{
- DPRINT("Received TDI_SEND for something that is not a TCP Context\n");
+ DPRINT1("Received TDI_SEND for something that is not a TCP
Context\n");
return STATUS_INVALID_PARAMETER;
}
Context = IrpSp->FileObject->FsContext;
if (GetExclusiveContextAccess(Context) == FALSE)
{
- DPRINT("Context has been disassociated\n");
+ DPRINT1("Context has been disassociated\n");
ReleaseExclusiveContextAccess(Context);
return STATUS_ADDRESS_CLOSED;
}
if (!(Context->TcpState & TCP_STATE_CONNECTED))
{
- DPRINT("Attempting to send on Context at %p without an established
connection\n", Context);
+ DPRINT1("Attempting to send on Context at %p without an established
connection\n", Context);
ReleaseExclusiveContextAccess(Context);
return STATUS_ONLY_IF_CONNECTED;
}
-
+
/* Get send buffer and length */
NdisQueryBuffer(Irp->MdlAddress, &Buffer, &SendBytes);
RequestInfo = (PTDI_REQUEST_KERNEL_SEND)&IrpSp->Parameters;
-
+
/* If the Context is already servicing a Send request, do not initiate another one
right now */
if (Context->TcpState & TCP_STATE_SENDING)
{
goto WAIT_TO_SEND;
}
-
+
/* Call into lwIP to initiate send */
+ ACQUIRE_SERIAL_MUTEX();
lwip_err = tcp_write(Context->lwip_tcp_pcb, Buffer, RequestInfo->SendLength,
0);
+ RELEASE_SERIAL_MUTEX();
switch (lwip_err)
{
case ERR_OK:
@@ -1466,36 +1657,35 @@
TCP_ADD_STATE(TCP_STATE_SENDING, Context);
break;
case ERR_MEM:
- DPRINT("lwIP ERR_MEM\n");
+ DPRINT1("lwIP ERR_MEM\n");
Status = STATUS_NO_MEMORY;
goto FINISH;
case ERR_ARG:
- DPRINT("lwIP ERR_ARG\n");
+ DPRINT1("lwIP ERR_ARG\n");
Status = STATUS_INVALID_PARAMETER;
goto FINISH;
case ERR_CONN:
- DPRINT("lwIP ERR_CONN\n");
+ DPRINT1("lwIP ERR_CONN\n");
Status = STATUS_CONNECTION_ACTIVE;
goto FINISH;
default:
- DPRINT("Unknwon lwIP Error: %d\n", lwip_err);
+ DPRINT1("Unknwon lwIP Error: %d\n", lwip_err);
Status = STATUS_NOT_IMPLEMENTED;
goto FINISH;
}
-
+
WAIT_TO_SEND:
- DPRINT("Queueing TDI_SEND\n");
Status = PrepareIrpForCancel(
Irp,
+ Context,
CancelRequestRoutine,
TCP_REQUEST_CANCEL_MODE_PRESERVE,
TCP_REQUEST_PENDING_SEND);
-
+
FINISH:
- ReleaseExclusiveContextAccess(Context);
+ ReleaseExclusiveContextAccess(Context);
return Status;
}
-
NTSTATUS
AddressSetIpDontFragment(
@@ -1587,6 +1777,9 @@
_Inout_ struct _DEVICE_OBJECT* DeviceObject,
_Inout_ _IRQL_uses_cancel_ struct _IRP *Irp)
{
+#ifndef NDEBUG
+ INT i;
+#endif
PIO_STACK_LOCATION IrpSp;
ADDRESS_FILE* AddressFile;
RECEIVE_DATAGRAM_REQUEST* Request;
@@ -1613,12 +1806,16 @@
NT_ASSERT(ListEntry != &AddressFile->RequestListHead);
RemoveEntryList(&Request->ListEntry);
-
+
KeReleaseSpinLock(&AddressFile->RequestLock, OldIrql);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
ExFreePoolWithTag(Request, TAG_DGRAM_REQST);
@@ -1628,6 +1825,10 @@
TcpIpReceiveDatagram(
_Inout_ PIRP Irp)
{
+#ifndef NDEBUG
+ KIRQL OldIrql;
+ INT i;
+#endif
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
ADDRESS_FILE *AddressFile;
RECEIVE_DATAGRAM_REQUEST* Request = NULL;
@@ -1701,6 +1902,10 @@
if (Request)
ExFreePoolWithTag(Request, TAG_DGRAM_REQST);
Irp->IoStatus.Status = Status;
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return Status;
}
@@ -1709,6 +1914,10 @@
TcpIpSendDatagram(
_Inout_ PIRP Irp)
{
+#ifndef NDEBUG
+ KIRQL OldIrql;
+ INT i;
+#endif
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
ADDRESS_FILE *AddressFile;
PTDI_REQUEST_KERNEL_SENDDG RequestInfo;
@@ -1823,19 +2032,19 @@
break;
case ERR_MEM:
case ERR_BUF:
- DPRINT("Received ERR_MEM from lwip.\n");
+ DPRINT1("Received ERR_MEM from lwip.\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
case ERR_RTE:
- DPRINT("Received ERR_RTE from lwip.\n");
+ DPRINT1("Received ERR_RTE from lwip.\n");
Status = STATUS_INVALID_ADDRESS;
break;
case ERR_VAL:
- DPRINT("Received ERR_VAL from lwip.\n");
+ DPRINT1("Received ERR_VAL from lwip.\n");
Status = STATUS_INVALID_PARAMETER;
break;
default:
- DPRINT("Received error %d from lwip.\n", lwip_error);
+ DPRINT1("Received error %d from lwip.\n", lwip_error);
Status = STATUS_UNEXPECTED_NETWORK_ERROR;
}
@@ -1843,11 +2052,17 @@
if (p)
pbuf_free(p);
Irp->IoStatus.Status = Status;
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return Status;
}
-/* If the PCB is deallocated, set the PCB pointer to NULL before calling */
+/* Acquire Context mutex before calling. If the PCB is deallocated, also set the PCB
pointer to NULL
+ * before calling. */
+VOID
ProcessPCBError(
PTCP_CONTEXT Context,
ULONG TcpState)
@@ -1856,31 +2071,27 @@
PLIST_ENTRY Entry;
PLIST_ENTRY Head;
PTCP_REQUEST Request;
-
+
/* Set the Context's State to indicate it is no longer active */
TCP_SET_STATE(TcpState, Context);
-
+
/* Walk the Context's list of pending requests and finish them */
Head = &Context->RequestListHead;
Entry = Head->Flink;
while (Entry != Head)
{
-#ifndef NDEBUG
- DPRINT("Closing Context with outstanding Requests\n");
-#endif
/* Extract Request */
Request = CONTAINING_RECORD(Entry, TCP_REQUEST, ListEntry);
-
+
/* Block potential cancellations */
Irp = Request->Payload.PendingIrp;
IoSetCancelRoutine(Irp, NULL);
-
+
/* Dequeue Request and increment list walk */
Entry = Entry->Flink;
RemoveEntryList(&Request->ListEntry);
-
+
/* Complete the IRP, deallocate the Request, and deallocate the lwIP PCB if
necessary */
- DPRINT("Dequeueing Pending Request from %p\n", Context);
Irp->IoStatus.Information = 0;
CleanupRequest(Request, STATUS_CANCELLED, Context);
}
@@ -1893,52 +2104,50 @@
)
{
ULONG TcpState;
-
+
PTCP_CONTEXT Context;
-
- DPRINT("lwip_tcp_err_callback\n");
-
+
/* Interpret lwIP error */
// TODO: detailed NTSTATUS codes
switch (err)
{
case ERR_ABRT :
- DPRINT("lwIP socket aborted\n");
+ DPRINT1("lwIP socket aborted\n");
TcpState = TCP_STATE_ABORTED;
break;
case ERR_RST :
/* This is the only case that indicates the lwIP PCB still exists */
- DPRINT("lwIP socket reset\n");
+ DPRINT1("lwIP socket reset\n");
TcpState = TCP_STATE_CLOSED;
goto RETAIN_PCB;
case ERR_CLSD :
- DPRINT("lwIP socket closed\n");
+ DPRINT1("lwIP socket closed\n");
TcpState = TCP_STATE_CLOSED;
break;
case ERR_CONN :
- DPRINT("lwIP connection failed\n");
+ DPRINT1("lwIP connection failed\n");
TcpState = TCP_STATE_CLOSED;
break;
case ERR_ARG :
- DPRINT("lwIP invalid arguments\n");
+ DPRINT1("lwIP invalid arguments\n");
TcpState = TCP_STATE_ABORTED;
break;
case ERR_IF :
- DPRINT("Low-level error\n");
+ DPRINT1("Low-level error\n");
TcpState = TCP_STATE_ABORTED;
break;
default :
- DPRINT("Unsupported lwIP error code: %d\n", err);
+ DPRINT1("Unsupported lwIP error code: %d\n", err);
TcpState = TCP_STATE_ABORTED;
break;
}
-
+
Context = (PTCP_CONTEXT)arg;
if (Context == NULL)
{
return;
}
-
+
GetExclusiveContextAccess(Context);
Context->lwip_tcp_pcb = NULL;
RETAIN_PCB:
@@ -1958,24 +2167,22 @@
PLIST_ENTRY Entry;
PTCP_CONTEXT Context;
PTCP_REQUEST Request;
-
- DPRINT("lwip_tcp_connected_callback\n");
-
+
/* lwIP currently never sends anything other than ERR_OK here */
-
+
Context = (PTCP_CONTEXT)arg;
GetExclusiveContextAccess(Context);
-
+
/* Sanity checks */
if (Context->TcpState != TCP_STATE_CONNECTING)
{
- DPRINT("Callback on a context that did not initiate a connection\n");
+ DPRINT1("Callback on a context that did not initiate a connection\n");
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
}
if (Context->lwip_tcp_pcb != tpcb)
{
- DPRINT("Connected PCB mismatch\n");
+ DPRINT1("Connected PCB mismatch\n");
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
}
@@ -1983,35 +2190,33 @@
Entry = RemoveHeadList(&Context->RequestListHead);
if (Entry == &Context->RequestListHead)
{
- DPRINT("No matching Connect Request found\n");
+ DPRINT1("No matching Connect Request found\n");
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
}
-
+
Request = CONTAINING_RECORD(Entry, TCP_REQUEST, ListEntry);
Irp = Request->Payload.PendingIrp;
-
+
/* Block cancellations */
IoSetCancelRoutine(Irp, NULL);
-
+
/* One last sanity check */
if (Request->PendingMode != TCP_REQUEST_PENDING_CONNECT)
{
- DPRINT("Pending Request is not a Connect request. This should never
happen.\n");
+ DPRINT1("Pending Request is not a Connect request. This should never
happen.\n");
Irp->IoStatus.Information = 0;
- DPRINT("Dequeueing TDI_CONNECT\n");
CleanupRequest(Request, STATUS_CANCELLED, Context);
ReleaseExclusiveContextAccess(Context);
return ERR_CONN;
}
-
+
/* Complete the Request, set TCP State variable, and set callback information */
- DPRINT("Dequeueing TDI_CONNECT\n");
TCP_SET_STATE(TCP_STATE_CONNECTED, Context);
tcp_sent(Context->lwip_tcp_pcb, lwip_tcp_sent_callback);
tcp_recv(Context->lwip_tcp_pcb, lwip_tcp_receive_callback);
CleanupRequest(Request, STATUS_SUCCESS, Context);
-
+
ReleaseExclusiveContextAccess(Context);
return ERR_OK;
}
@@ -2029,7 +2234,7 @@
KIRQL OldIrql;
#endif
NTSTATUS Status;
-
+
PIO_STACK_LOCATION IrpSp;
PIRP Irp;
PLIST_ENTRY Entry;
@@ -2039,19 +2244,16 @@
PTCP_REQUEST CurrentRequest;
PTCP_REQUEST DummyRequest;
PTCP_REQUEST Request;
-
- DPRINT("lwip_tcp_accept_callback\n");
-
+
/* lwIP currently never sends anything other than ERR_OK here */
-
+
Context = (PTCP_CONTEXT)arg;
GetExclusiveContextAccess(Context);
-
+
/* Sanity check */
- DPRINT("Sanity Checks\n");
if (!(Context->TcpState & TCP_STATE_LISTENING))
{
- DPRINT("lwIP sending Accept event to non-listening TCP Context\n");
+ DPRINT1("lwIP sending Accept event to non-listening TCP Context\n");
#ifndef NDEBUG
REMOVE_PCB(Context->lwip_tcp_pcb);
#endif
@@ -2060,9 +2262,8 @@
ReleaseExclusiveContextAccess(Context);
return ERR_CLSD;
}
-
+
/* Look for a Listen request and an available dummy Context */
- DPRINT("Look for a Listen request\n");
Head = &Context->RequestListHead;
NewContext = NULL;
Request = NULL;
@@ -2070,18 +2271,17 @@
while (Entry != Head)
{
// TODO: optimize checking logic
-
+
CurrentRequest = CONTAINING_RECORD(Entry, TCP_REQUEST, ListEntry);
if ((CurrentRequest->PendingMode == TCP_REQUEST_PENDING_LISTEN) &&
(Request == NULL))
{
- DPRINT("Found a Listen\n");
/* This is the Listen request we are looking for. Immediately block
cancellations, then
* dequeue the Request. */
Irp = CurrentRequest->Payload.PendingIrp;
IoSetCancelRoutine(Irp, NULL);
RemoveEntryList(&CurrentRequest->ListEntry);
Request = CurrentRequest;
-
+
/* If we have already found a dummy Context, associate it with the
Established PCB. */
if (NewContext != NULL)
{
@@ -2093,13 +2293,12 @@
else if ((CurrentRequest->PendingMode == TCP_REQUEST_PENDING_LISTEN_POLL)
&& (NewContext == NULL))
{
- DPRINT("Found a dummy\n");
/* This is a dummy Context we can use instead of creating a new one. Store a
reference
* to it. No need to acquire exclusive access to this Context because this is
the only
* existing pointer to it at this moment. */
NewContext = CurrentRequest->Payload.Context;
DummyRequest = CurrentRequest;
-
+
/* If we have already found a Listen request, we still must associate this
Context with
* the Established PCB before completing the Request. */
if (Request != NULL)
@@ -2111,16 +2310,15 @@
}
Entry = Entry->Flink;
}
-
+
/* We need a Context to store the Established PCB in. If the list does not contain a
dummy
* Context, we need to create a new one. */
if (NewContext == NULL)
{
- DPRINT("Allocate and intialize new TCP Context\n");
NewContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewContext),
TAG_TCP_CONTEXT);
if (NewContext == NULL)
{
- DPRINT("Not enough resources\n");
+ DPRINT1("Not enough resources\n");
ReleaseExclusiveContextAccess(Context);
return ERR_MEM;
}
@@ -2129,14 +2327,13 @@
#endif
NewContext->AddressFile = Context->AddressFile;
InitializeListHead(&NewContext->RequestListHead);
- NewContext->CreatedWithoutRequest = TRUE;
+ NewContext->ReferencedByUpperLayer = FALSE;
InitializeContextMutex(NewContext);
-
- /* Increment the Address File's Context reference count and set PCB callback
info */
- DPRINT("Increment Address File's Context count and set PCB callback
information\n");
+
+ /* Increment the Address File's Context reference count */
InterlockedIncrement(&NewContext->AddressFile->ContextCount);
}
-
+
CONTEXT_FOUND:
/* Associate the new Context and the Established PCB with each other */
#ifndef NDEBUG
@@ -2147,43 +2344,43 @@
tcp_err(NewContext->lwip_tcp_pcb, lwip_tcp_err_callback);
tcp_sent(NewContext->lwip_tcp_pcb, lwip_tcp_sent_callback);
tcp_recv(NewContext->lwip_tcp_pcb, lwip_tcp_receive_callback);
-
+
/* If we found a Listen request, complete it. */
if (Request != NULL)
{
- DPRINT("Completing Listen\n");
/* Store new Context information */
TCP_SET_STATE(TCP_STATE_CONNECTED, NewContext);
IrpSp = IoGetCurrentIrpStackLocation(Irp);
IrpSp->FileObject->FsContext = NewContext;
IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
-
+
/* Finish the Request */
+ NewContext->ReferencedByUpperLayer = TRUE;
CleanupRequest(Request, STATUS_SUCCESS, Context);
-
+
/* Notify the listening lwIP PCB that we accepted the connection */
tcp_accepted(Context->lwip_tcp_pcb);
-
+
ReleaseExclusiveContextAccess(Context);
return ERR_OK;
}
-
- DPRINT("Enqueueing prepared Context %p\n", NewContext);
+
/* If we did not find a Listen request, we need to enqueue the new Context. The next
TDI_LISTEN
* will find it and complete without pending. */
TCP_SET_STATE(TCP_STATE_BOUND, NewContext);
- Status = EnqueueRequest(NewContext,
+ Status = EnqueueRequest(
+ NewContext,
Context,
TCP_REQUEST_CANCEL_MODE_PRESERVE,
TCP_REQUEST_PENDING_ACCEPTED_CONNECTION,
TCP_REQUEST_PAYLOAD_CONTEXT);
if (Status != STATUS_SUCCESS)
{
- DPRINT("Ran out of resources trying to enqueue a connected
Context\n");
+ DPRINT1("Ran out of resources trying to enqueue a connected
Context\n");
ReleaseExclusiveContextAccess(Context);
return ERR_MEM;
}
-
+
ReleaseExclusiveContextAccess(Context);
return ERR_OK;
}
@@ -2200,25 +2397,23 @@
INT CopiedLength;
INT RemainingDestBytes;
UCHAR *CurrentDestLocation;
-
+
PIRP Irp;
PLIST_ENTRY Head;
PLIST_ENTRY Entry;
PNDIS_BUFFER Buffer;
PTCP_CONTEXT Context;
PTCP_REQUEST Request;
-
+
struct pbuf *next;
-
- DPRINT("lwip_tcp_receive_callback\n");
-
+
/* lwIP currently never sends anything other than ERR_OK here */
-
+
Context = (PTCP_CONTEXT)arg;
-
+
/* Get exclusive access to the Context */
GetExclusiveContextAccess(Context);
-
+
/* If the buffer is NULL, the PCB has been closed */
if (p == NULL)
{
@@ -2227,21 +2422,21 @@
ReleaseExclusiveContextAccess(Context);
return ERR_OK;
}
-
+
/* Sanity checks */
if (!(Context->TcpState & TCP_STATE_RECEIVING))
{
- DPRINT("Receive callback on Context that is not currently
receiving\n");
+ DPRINT1("Receive callback on Context that is not currently
receiving\n");
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
}
if (Context->lwip_tcp_pcb != tpcb)
{
- DPRINT("Receive PCB mismatch\n");
+ DPRINT1("Receive PCB mismatch\n");
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
}
-
+
/* Walk the Request list for the matching Receive request */
Head = &Context->RequestListHead;
Entry = Head->Flink;
@@ -2259,16 +2454,16 @@
}
Entry = Entry->Flink;
}
- DPRINT("Failed to find a pending Receive\n");
+ DPRINT1("Failed to find a pending Receive\n");
TCP_RMV_STATE(TCP_STATE_RECEIVING, Context);
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
-
+
FOUND:
/* Get buffer pointers to write to */
Buffer = (PNDIS_BUFFER)Irp->MdlAddress;
NdisQueryBuffer(Buffer, &CurrentDestLocation, &RemainingDestBytes);
-
+
/**
* Copy the data from the pbuf to the NDIS Buffer
**/
@@ -2277,12 +2472,12 @@
while (RemainingDestBytes > p->len)
{
RtlCopyMemory(CurrentDestLocation, p->payload, p->len);
-
+
/* Update pointers and byte count */
CopiedLength += p->len;
CurrentDestLocation += p->len;
RemainingDestBytes -= p->len;
-
+
/* If there is still data left, go to the next pbuf. Otherwise, we are done
copying. */
if (p->next != NULL)
{
@@ -2300,11 +2495,11 @@
* final copy to top off the NDIS Buffer, then update the byte count. */
RtlCopyMemory(CurrentDestLocation, p->payload, RemainingDestBytes);
CopiedLength += RemainingDestBytes;
-
+
COPY_DONE:
/* Inform lwIP of how much data we copied */
tcp_recved(Context->lwip_tcp_pcb, CopiedLength);
-
+
/* Check for other pending Receive requests. If there are none, clear the Receive TCP
State bit.
* Otherwise, leave the state variable alone. */
Entry = Head->Flink;
@@ -2319,13 +2514,12 @@
}
}
TCP_RMV_STATE(TCP_STATE_RECEIVING, Context);
-
+
STILL_PENDING:
/* Clean up the Request struct and the IRP */
Irp->IoStatus.Information = CopiedLength;
- DPRINT("Dequeueing TDI_RECEIVE\n");
CleanupRequest(Request, STATUS_SUCCESS, Context);
-
+
ReleaseExclusiveContextAccess(Context);
return ERR_OK;
}
@@ -2343,57 +2537,54 @@
PLIST_ENTRY Head;
PTCP_CONTEXT Context;
PTCP_REQUEST Request;
-
- DPRINT("lwip_tcp_sent_callback\n");
-
+
Context = (PTCP_CONTEXT)arg;
-
+
/* Get exclusive access to the Context */
GetExclusiveContextAccess(Context);
-
+
/* Sanity check */
if (!(Context->TcpState & TCP_STATE_SENDING))
{
- DPRINT("Callback on a connection that is not sending anything\n");
+ DPRINT1("Callback on a connection that is not sending anything\n");
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
}
-
+
/* Walk Request list for the first Send request */
Head = &Context->RequestListHead;
Entry = Head->Flink;
while (Entry != Head)
{
Request = CONTAINING_RECORD(Entry, TCP_REQUEST, ListEntry);
-
+
/* Jump to handler when Request found */
if (Request->PendingMode == TCP_REQUEST_PENDING_SEND)
{
/* Immediately block any cancellations */
Irp = Request->Payload.PendingIrp;
IoSetCancelRoutine(Irp, NULL);
-
+
/* Dequeue the entry and jump to handler */
RemoveEntryList(&Request->ListEntry);
goto FOUND;
}
-
+
Entry = Entry->Flink;
}
-
+
/* Being here means we walked the entire list without finding a Send request. We
should clear
* the TCP State variable SENDING bit. */
- DPRINT("Callback on Context with no outstanding Send requests\n");
+ DPRINT1("Callback on Context with no outstanding Send requests\n");
TCP_RMV_STATE(TCP_STATE_SENDING, Context);
ReleaseExclusiveContextAccess(Context);
return ERR_ARG;
-
+
FOUND:
/* Complete the Request */
- DPRINT("Dequeueing TDI_SEND\n");
Irp->IoStatus.Information = len;
CleanupRequest(Request, STATUS_SUCCESS, Context);
-
+
ReleaseExclusiveContextAccess(Context);
return ERR_OK;
}
Modified: branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.h
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/drivers/ne…
==============================================================================
--- branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.h [iso-8859-1] (original)
+++ branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/address.h [iso-8859-1] Wed Aug 3
19:57:20 2016
@@ -28,13 +28,116 @@
#define TCP_STATE_DISASSOCIATED 0x1 << 8
#define TCP_STATE_CLOSED 0x1 << 9
+//#define TCPIP_NDEBUG
+#ifndef TCPIP_NDEBUG
+KSPIN_LOCK IRPArrayLock;
+PIRP IRPArray[16];
+volatile long int IRPCount;
+
+#define ADD_IRP(Irp) \
+ KeAcquireSpinLock(&IRPArrayLock, &OldIrql); \
+ IRPArray[IRPCount] = Irp; \
+ IRPCount++; \
+ KeReleaseSpinLock(&IRPArrayLock, OldIrql)
+
+#define ADD_IRP_DPC(Irp) \
+ KeAcquireSpinLockAtDpcLevel(&IRPArrayLock); \
+ IRPArray[IRPCount] = Irp; \
+ IRPCount++; \
+ KeReleaseSpinLockFromDpcLevel(&IRPArrayLock)
+
+#define REMOVE_IRP(Irp) \
+ KeAcquireSpinLock(&IRPArrayLock, &OldIrql); \
+ for (i = 0; i < IRPCount; i++) \
+ { \
+ if (Irp == IRPArray[i]) \
+ { \
+ IRPArray[i] = NULL; \
+ } \
+ if (IRPArray[i] == NULL) \
+ { \
+ IRPArray[i] = IRPArray[i+1]; \
+ IRPArray[i+1] = NULL; \
+ } \
+ } \
+ IRPCount--; \
+ KeReleaseSpinLock(&IRPArrayLock, OldIrql)
+
+#define REMOVE_IRP_DPC(Irp) \
+ KeAcquireSpinLockAtDpcLevel(&IRPArrayLock); \
+ for (i = 0; i < IRPCount; i++) \
+ { \
+ if (Irp == IRPArray[i]) \
+ { \
+ IRPArray[i] = NULL; \
+ } \
+ if (IRPArray[i] == NULL) \
+ { \
+ IRPArray[i] = IRPArray[i+1]; \
+ IRPArray[i+1] = NULL; \
+ } \
+ } \
+ IRPCount--; \
+ KeReleaseSpinLockFromDpcLevel(&IRPArrayLock)
+
+KSPIN_LOCK IRPSPArrayLock;
+PIO_STACK_LOCATION IRPSPArray[16];
+volatile long int IRPSPCount;
+
+#define ADD_IRPSP(IrpSp) \
+ KeAcquireSpinLock(&IRPSPArrayLock, &OldIrql); \
+ IRPSPArray[IRPSPCount] = IrpSp; \
+ IRPSPCount++; \
+ KeReleaseSpinLock(&IRPSPArrayLock, OldIrql)
+
+#define ADD_IRPSP_DPC(IrpSp) \
+ KeAcquireSpinLockAtDpcLevel(&IRPSPArrayLock); \
+ IRPSPArray[IRPSPCount] = IrpSp; \
+ IRPSPCount++; \
+ KeReleaseSpinLockFromDpcLevel(&IRPSPArrayLock)
+
+#define REMOVE_IRPSP(IrpSp) \
+ KeAcquireSpinLock(&IRPSPArrayLock, &OldIrql); \
+ for (i = 0; i < IRPSPCount; i++) \
+ { \
+ if (IrpSp == IRPSPArray[i]) \
+ { \
+ IRPSPArray[i] = NULL; \
+ } \
+ if (IRPSPArray[i] == NULL) \
+ { \
+ IRPSPArray[i] = IRPSPArray[i+1]; \
+ IRPSPArray[i+1] = NULL; \
+ } \
+ } \
+ IRPSPCount--; \
+ KeReleaseSpinLock(&IRPSPArrayLock, OldIrql)
+
+#define REMOVE_IRPSP_DPC(IrpSp) \
+ KeAcquireSpinLockAtDpcLevel(&IRPSPArrayLock); \
+ for (i = 0; i < IRPSPCount; i++) \
+ { \
+ if (IrpSp == IRPSPArray[i]) \
+ { \
+ IRPSPArray[i] = NULL; \
+ } \
+ if (IRPSPArray[i] == NULL) \
+ { \
+ IRPSPArray[i] = IRPSPArray[i+1]; \
+ IRPSPArray[i+1] = NULL; \
+ } \
+ } \
+ IRPSPCount--; \
+ KeReleaseSpinLockFromDpcLevel(&IRPSPArrayLock)
+#endif
+
struct _TCP_CONTEXT;
typedef struct _TCP_CONTEXT TCP_CONTEXT, *PTCP_CONTEXT;
typedef struct _ADDRESS_FILE {
LIST_ENTRY ListEntry;
LONG RefCount;
- LONG ContextCount;
+ volatile long ContextCount;
IPPROTO Protocol;
TDI_ADDRESS_IP Address;
struct netif *NetInterface;
@@ -56,9 +159,9 @@
PADDRESS_FILE AddressFile;
LIST_ENTRY RequestListHead;
struct tcp_pcb* lwip_tcp_pcb;
- BOOLEAN CreatedWithoutRequest;
+ BOOLEAN ReferencedByUpperLayer;
HANDLE MutexOwner;
- volatile long int MutexDepth;
+ volatile long MutexDepth;
};
typedef struct _TCP_REQUEST {
@@ -106,6 +209,11 @@
);
NTSTATUS
+TcpIpDisconnect(
+ _Inout_ PIRP Irp
+);
+
+NTSTATUS
TcpIpAssociateAddress(
_Inout_ PIRP Irp
);
@@ -132,7 +240,7 @@
NTSTATUS
TcpIpSend(
_Inout_ PIRP Irp);
-
+
NTSTATUS
TcpIpSendDatagram(
_Inout_ PIRP Irp);
Modified: branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/interface.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/drivers/ne…
==============================================================================
--- branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/interface.c [iso-8859-1]
(original)
+++ branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/interface.c [iso-8859-1] Wed Aug
3 19:57:20 2016
@@ -203,6 +203,7 @@
IP4_ADDR(&GatewayAddr, 127,0,0,1);
IP4_ADDR(&IpAddr, 127,0,0,1);
IP4_ADDR(&SubnetMask, 255,0,0,0);
+ ACQUIRE_SERIAL_MUTEX();
lwip_error = netifapi_netif_add(
&LoopbackInterface->lwip_netif,
&IpAddr,
@@ -214,10 +215,12 @@
if (lwip_error != ERR_OK)
{
ExFreePoolWithTag(LoopbackInterface, TAG_INTERFACE);
+ RELEASE_SERIAL_MUTEX();
return STATUS_INSUFFICIENT_RESOURCES;
}
netifapi_netif_set_up(&LoopbackInterface->lwip_netif);
+ RELEASE_SERIAL_MUTEX();
/* Add this interface into the entities DB */
InsertEntityInstance(CL_NL_ENTITY, &LoopbackInterface->ClNlInstance);
Modified: branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/main.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/drivers/ne…
==============================================================================
--- branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/main.c [iso-8859-1] (original)
+++ branches/GSoC_2016/lwIP-tcpip/drivers/network/tcpip/main.c [iso-8859-1] Wed Aug 3
19:57:20 2016
@@ -38,7 +38,8 @@
#define DD_IP_DEVICE_NAME L"\\Device\\Ip"
#define DD_RAWIP_DEVICE_NAME L"\\Device\\RawIp"
-/* This is a small utility which get the IPPROTO_* constant from the device object this
driver was passed */
+/* This is a small utility which get the IPPROTO_* constant from the device object this
driver was
+ * passed */
static
IPPROTO
ProtocolFromIrp(
@@ -98,6 +99,7 @@
/* Initialize the lwip library */
tcpip_init(NULL, NULL);
+ RELEASE_SERIAL_MUTEX();
/* Create the device objects */
Status = IoCreateDevice(
@@ -207,14 +209,23 @@
_Inout_ struct _IRP *Irp
)
{
+#ifndef NDEBUG
+ KIRQL OldIrql;
+ INT i;
+#endif
NTSTATUS Status;
PFILE_FULL_EA_INFORMATION FileInfo;
IPPROTO Protocol;
// ADDRESS_FILE *AddressFile;
-
+
// ULONG *temp;
-
+
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+#ifndef NDEBUG
+ ADD_IRP(Irp);
+ ADD_IRPSP(IrpSp);
+#endif
/* Grab the info describing the file */
FileInfo = Irp->AssociatedIrp.SystemBuffer;
@@ -227,14 +238,14 @@
Status = STATUS_SUCCESS;
goto Quickie;
}
-
+
/* Validate it */
switch (FileInfo->EaNameLength)
{
case TDI_TRANSPORT_ADDRESS_LENGTH:
{
PTA_IP_ADDRESS Address;
-
+
DPRINT1("TCPIP Create Transport Address\n");
if (strncmp(&FileInfo->EaName[0], TdiTransportAddress,
TDI_TRANSPORT_ADDRESS_LENGTH) != 0)
@@ -284,17 +295,17 @@
case TDI_CONNECTION_CONTEXT_LENGTH:
{
PTA_IP_ADDRESS Address;
-
+
DPRINT1("TCPIP Create connection Context\n");
-
+
if (strncmp(&FileInfo->EaName[0], TdiConnectionContext,
TDI_CONNECTION_CONTEXT_LENGTH) != 0)
{
DPRINT1("TCPIP: Should maybe open file %*s.\n",
FileInfo->EaNameLength, &FileInfo->EaName[0]);
return STATUS_INVALID_PARAMETER;
}
-
+
Address = (PTA_IP_ADDRESS)(&FileInfo->EaName[FileInfo->EaNameLength
+ 1]);
-
+
/* Get the protocol this address will be created for. */
Protocol = ProtocolFromIrp(DeviceObject, IrpSp);
if (Protocol == (IPPROTO)-1)
@@ -302,12 +313,12 @@
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
-
+
/* temp = (ULONG*)Protocol;
DPRINT1("\n Protocol: %08x\n", temp);
-
+
temp = (ULONG*)Address;*/
-
+
/* All good. */
/* DPRINT1("\n PTA_IP_ADDRESS dump before\n %08x %08x %08x %08x\n %08x
%08x %08x %08x\n",
temp[7], temp[6], temp[5], temp[4],
@@ -332,6 +343,10 @@
}
else
{
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
}
@@ -346,11 +361,20 @@
_Inout_ struct _IRP *Irp
)
{
+#ifndef NDEBUG
+ KIRQL OldIrql;
+ INT i;
+#endif
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
ULONG_PTR FileType;
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+#ifndef NDEBUG
+ ADD_IRP(Irp);
+ ADD_IRPSP(IrpSp);
+#endif
FileType = (ULONG_PTR)IrpSp->FileObject->FsContext2;
@@ -367,7 +391,7 @@
Status = TcpIpCloseAddress(IrpSp->FileObject->FsContext);
break;
case TDI_CONNECTION_FILE:
- DPRINT1("TCPIP Close Transport Address\n");
+ DPRINT1("TCPIP Close Connection File\n");
if (!IrpSp->FileObject->FsContext)
{
DPRINT1("TCPIP: Got a close request without a file to
close!\n");
@@ -390,8 +414,12 @@
Quickie:
Irp->IoStatus.Status = Status;
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
-
+
return Status;
}
@@ -403,14 +431,23 @@
_Inout_ struct _IRP *Irp
)
{
+#ifndef NDEBUG
+ KIRQL OldIrql;
+ INT i;
+#endif
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp;
PTCP_CONTEXT Context;
PADDRESS_FILE AddressFile;
DPRINT1("TcpIpDispatchInternal\n");
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+#ifndef NDEBUG
+ ADD_IRP(Irp);
+ ADD_IRPSP(IrpSp);
+#endif
switch ((ULONG)IrpSp->FileObject->FsContext2)
{
@@ -425,7 +462,7 @@
DPRINT1("Unknown FileObject type\n");
break;
}
-
+
switch (IrpSp->MinorFunction)
{
case TDI_RECEIVE:
@@ -496,7 +533,8 @@
case TDI_DISCONNECT:
DPRINT1("TCPIP: TDI_DISCONNECT!\n");
- Status = STATUS_NOT_IMPLEMENTED;
+ Status = TcpIpDisconnect(Irp);
+ DPRINT("TcpIpDisconnect() Returned\n");
break;
case TDI_ASSOCIATE_ADDRESS:
@@ -533,7 +571,7 @@
DPRINT1("TCPIP: Unknown internal IOCTL: 0x%x.\n",
IrpSp->MinorFunction);
Status = STATUS_NOT_IMPLEMENTED;
}
-
+
FINISH:
Irp->IoStatus.Status = Status;
if (Status == STATUS_PENDING)
@@ -542,6 +580,10 @@
}
else
{
+#ifndef NDEBUG
+ REMOVE_IRP(Irp);
+ REMOVE_IRPSP(IrpSp);
+#endif
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
}
@@ -558,7 +600,7 @@
{
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp;
-
+
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
Modified: branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/arch/sys_arch.h
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/sdk/lib/dr…
==============================================================================
---
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/arch/sys_arch.h [iso-8859-1]
(original)
+++
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/arch/sys_arch.h [iso-8859-1]
Wed Aug 3 19:57:20 2016
@@ -39,5 +39,4 @@
sys_arch_unprotect(sys_prot_t lev);
void
-sys_shutdown(void);
-
+sys_shutdown(void);
Modified: branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcp.h
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/sdk/lib/dr…
==============================================================================
--- branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcp.h [iso-8859-1]
(original)
+++ branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcp.h [iso-8859-1]
Wed Aug 3 19:57:20 2016
@@ -368,9 +368,23 @@
err_t tcp_output (struct tcp_pcb *pcb);
+/**
+ * REACT_OS Global Mutex
+ * Serializes all kernel network activity to circumvent lwIP core's lack of
thread-safety.
+ */
+KMUTEX MTSerialMutex;
+
+#define ACQUIRE_SERIAL_MUTEX() \
+ DPRINT("Acquiring MTSerialMutex on thread %p\n", PsGetCurrentThreadId());
\
+ KeWaitForMutexObject(&MTSerialMutex, Executive, KernelMode, FALSE, NULL); \
+ DPRINT("MTSerialMutex acquired on thread %p\n", PsGetCurrentThreadId())
+
+#define RELEASE_SERIAL_MUTEX() \
+ DPRINT("Releasing MTSerialMutex on thread %p\n", PsGetCurrentThreadId());
\
+ KeReleaseMutex(&MTSerialMutex, FALSE); \
+ DPRINT("MTSerialMutex released on thread %p\n", PsGetCurrentThreadId())
const char* tcp_debug_state_str(enum tcp_state s);
-
#ifdef __cplusplus
}
Modified: branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcpip.h
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/sdk/lib/dr…
==============================================================================
---
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcpip.h [iso-8859-1]
(original)
+++
branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/include/lwip/tcpip.h [iso-8859-1]
Wed Aug 3 19:57:20 2016
@@ -158,6 +158,8 @@
} msg;
};
+extern KMUTEX MTSerialMutex;
+
#ifdef __cplusplus
}
#endif
Modified: branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/sys_arch.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/lwIP-tcpip/sdk/lib/dr…
==============================================================================
--- branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/sys_arch.c [iso-8859-1]
(original)
+++ branches/GSoC_2016/lwIP-tcpip/sdk/lib/drivers/lwip/src/sys_arch.c [iso-8859-1] Wed Aug
3 19:57:20 2016
@@ -1,3 +1,5 @@
+#include <ntifs.h>
+
#include "lwip/sys.h"
#include "lwip/tcp.h"
@@ -95,6 +97,7 @@
KeQuerySystemTime(&PreWaitTime);
+ RELEASE_SERIAL_MUTEX();
Status = KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
@@ -103,6 +106,7 @@
FALSE,
timeout != 0 ? &LargeTimeout : NULL,
NULL);
+ ACQUIRE_SERIAL_MUTEX();
if (Status == STATUS_WAIT_0)
{
KeQuerySystemTime(&PostWaitTime);
@@ -190,6 +194,7 @@
KeQuerySystemTime(&PreWaitTime);
+ RELEASE_SERIAL_MUTEX();
Status = KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
@@ -198,6 +203,7 @@
FALSE,
timeout != 0 ? &LargeTimeout : NULL,
NULL);
+ ACQUIRE_SERIAL_MUTEX();
if (Status == STATUS_WAIT_0)
{
@@ -261,7 +267,9 @@
ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry,
&ThreadListLock);
+ ACQUIRE_SERIAL_MUTEX();
Container->ThreadFunction(Container->ThreadContext);
+ RELEASE_SERIAL_MUTEX();
KeAcquireSpinLock(&ThreadListLock, &OldIrql);
RemoveEntryList(&Container->ListEntry);
@@ -311,6 +319,9 @@
KeQuerySystemTime(&StartTime);
KeInitializeEvent(&TerminationEvent, NotificationEvent, FALSE);
+ KeInitializeMutex(&MTSerialMutex, 0);
+
+ ACQUIRE_SERIAL_MUTEX();
}
void
@@ -329,13 +340,15 @@
if (Container->ThreadFunction)
{
+ RELEASE_SERIAL_MUTEX();
KeWaitForSingleObject(Container->Handle,
Executive,
KernelMode,
FALSE,
NULL);
+ ACQUIRE_SERIAL_MUTEX();
ZwClose(Container->Handle);
}
}
-}
+}