[TCPIP][IP] Use an ERESOURCE as mutex for address files & connection end points

Spinlocks are not reentrant (and this is done a lot), using them forces us to have
an horrible hack in the kernel, which unschedules threads which are at DISPATCH_LEVEL
thus allowing another thread to take ownership of the spinlock while the unscheduled
thread should already hold it.

CORE-6473
This commit is contained in:
Jérôme Gardou 2021-05-21 09:36:27 +02:00 committed by Jérôme Gardou
parent 10e48faf1d
commit 27fcfe66a2
14 changed files with 326 additions and 343 deletions

View file

@ -16,13 +16,12 @@ BOOLEAN DGRemoveIRP(
{
PLIST_ENTRY ListEntry;
PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
KIRQL OldIrql;
BOOLEAN Found = FALSE;
TI_DbgPrint(MAX_TRACE, ("Called (Cancel IRP %08x for file %08x).\n",
Irp, AddrFile));
LockObject(AddrFile, &OldIrql);
LockObject(AddrFile);
for( ListEntry = AddrFile->ReceiveQueue.Flink;
ListEntry != &AddrFile->ReceiveQueue;
@ -42,7 +41,7 @@ BOOLEAN DGRemoveIRP(
}
}
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
TI_DbgPrint(MAX_TRACE, ("Done.\n"));
@ -73,7 +72,6 @@ DGDeliverData(
* handler if it exists, otherwise we drop the packet.
*/
{
KIRQL OldIrql;
LONG AddressLength;
PVOID SourceAddress;
ULONG BytesTaken;
@ -82,7 +80,7 @@ DGDeliverData(
TI_DbgPrint(MIN_TRACE, ("Called.\n"));
LockObject(AddrFile, &OldIrql);
LockObject(AddrFile);
if (AddrFile->Protocol == IPPROTO_UDP)
{
@ -145,7 +143,7 @@ DGDeliverData(
SrcAddress->Address.IPv4Address, SrcPort));
ReferenceObject(AddrFile);
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
/* Complete the receive request */
if (Current->BufferSize < DataSize)
@ -153,12 +151,12 @@ DGDeliverData(
else
Current->Complete(Current->Context, STATUS_SUCCESS, DataSize);
LockObject(AddrFile, &OldIrql);
LockObject(AddrFile);
DereferenceObject(AddrFile);
}
}
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
}
else if (AddrFile->RegisteredReceiveDatagramHandler)
{
@ -186,7 +184,7 @@ DGDeliverData(
}
ReferenceObject(AddrFile);
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
TI_DbgPrint(MIN_TRACE, ("OptionsSize %d DataSize: %u\n", OptionsSize, DataSize));
@ -209,7 +207,7 @@ DGDeliverData(
}
else
{
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
TI_DbgPrint(MAX_TRACE, ("Discarding datagram.\n"));
}
@ -254,11 +252,10 @@ NTSTATUS DGReceiveDatagram(
{
NTSTATUS Status;
PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
KIRQL OldIrql;
TI_DbgPrint(MAX_TRACE, ("Called.\n"));
LockObject(AddrFile, &OldIrql);
LockObject(AddrFile);
ReceiveRequest = ExAllocatePoolWithTag(NonPagedPool, sizeof(DATAGRAM_RECEIVE_REQUEST),
DATAGRAM_RECV_TAG);
@ -276,7 +273,7 @@ NTSTATUS DGReceiveDatagram(
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG);
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return Status;
}
}
@ -304,13 +301,13 @@ NTSTATUS DGReceiveDatagram(
TI_DbgPrint(MAX_TRACE, ("Leaving (pending %08x).\n", ReceiveRequest));
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_PENDING;
}
else
{
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
Status = STATUS_INSUFFICIENT_RESOURCES;
}

View file

@ -191,9 +191,8 @@ NTSTATUS RawIPSendDatagram(
USHORT RemotePort;
NTSTATUS Status;
PNEIGHBOR_CACHE_ENTRY NCE;
KIRQL OldIrql;
LockObject(AddrFile, &OldIrql);
LockObject(AddrFile);
TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
AddrFile, ConnInfo, BufferData, DataSize));
@ -208,7 +207,7 @@ NTSTATUS RawIPSendDatagram(
break;
default:
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_UNSUCCESSFUL;
}
@ -222,7 +221,7 @@ NTSTATUS RawIPSendDatagram(
* interface we're sending over
*/
if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_NETWORK_UNREACHABLE;
}
@ -231,7 +230,7 @@ NTSTATUS RawIPSendDatagram(
else
{
if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) {
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_INVALID_PARAMETER;
}
}
@ -245,7 +244,7 @@ NTSTATUS RawIPSendDatagram(
BufferData,
DataSize );
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
if( !NT_SUCCESS(Status) )
return Status;

View file

@ -48,12 +48,11 @@ NTSTATUS TCPListen(PCONNECTION_ENDPOINT Connection, UINT Backlog)
{
NTSTATUS Status = STATUS_SUCCESS;
struct ip_addr AddressToBind;
KIRQL OldIrql;
TA_IP_ADDRESS LocalAddress;
ASSERT(Connection);
LockObject(Connection, &OldIrql);
LockObject(Connection);
ASSERT_KM_POINTER(Connection->AddressFile);
@ -93,7 +92,7 @@ NTSTATUS TCPListen(PCONNECTION_ENDPOINT Connection, UINT Backlog)
Status = STATUS_UNSUCCESSFUL;
}
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Leaving. Status = %x\n", Status));
@ -106,10 +105,9 @@ BOOLEAN TCPAbortListenForSocket
{
PLIST_ENTRY ListEntry;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
BOOLEAN Found = FALSE;
LockObject(Listener, &OldIrql);
LockObject(Listener);
ListEntry = Listener->ListenRequest.Flink;
while (ListEntry != &Listener->ListenRequest)
@ -128,7 +126,7 @@ BOOLEAN TCPAbortListenForSocket
ListEntry = ListEntry->Flink;
}
UnlockObject(Listener, OldIrql);
UnlockObject(Listener);
return Found;
}
@ -141,9 +139,8 @@ NTSTATUS TCPAccept ( PTDI_REQUEST Request,
{
NTSTATUS Status;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
LockObject(Listener, &OldIrql);
LockObject(Listener);
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
@ -160,7 +157,7 @@ NTSTATUS TCPAccept ( PTDI_REQUEST Request,
else
Status = STATUS_NO_MEMORY;
UnlockObject(Listener, OldIrql);
UnlockObject(Listener);
return Status;
}

View file

@ -50,125 +50,66 @@ CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEA
}
VOID
FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
if (interlocked)
while (!IsListEmpty(&Connection->ReceiveRequest))
{
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Entry = RemoveHeadList(&Connection->ReceiveRequest);
TI_DbgPrint(DEBUG_TCP,
("Completing Receive request: %x %x\n",
Bucket->Request, Status));
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Status = Status;
Bucket->Information = 0;
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
CompleteBucket(Connection, Bucket, FALSE);
}
else
{
while (!IsListEmpty(&Connection->ReceiveRequest))
{
Entry = RemoveHeadList(&Connection->ReceiveRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
DereferenceObject(Connection);
}
VOID
FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
if (interlocked)
while (!IsListEmpty(&Connection->SendRequest))
{
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Entry = RemoveHeadList(&Connection->SendRequest);
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Status = Status;
Bucket->Information = 0;
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
CompleteBucket(Connection, Bucket, FALSE);
}
else
{
while (!IsListEmpty(&Connection->SendRequest))
{
Entry = RemoveHeadList(&Connection->SendRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
DereferenceObject(Connection);
}
VOID
FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
if (interlocked)
while (!IsListEmpty(&Connection->ShutdownRequest))
{
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ShutdownRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Entry = RemoveHeadList(&Connection->ShutdownRequest);
Bucket->Status = Status;
Bucket->Information = 0;
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
CompleteBucket(Connection, Bucket, FALSE);
}
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
else
{
while (!IsListEmpty(&Connection->ShutdownRequest))
{
Entry = RemoveHeadList(&Connection->ShutdownRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
DereferenceObject(Connection);
}
VOID
@ -177,10 +118,11 @@ FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
while (!IsListEmpty(&Connection->ConnectRequest))
{
Entry = RemoveHeadList(&Connection->ConnectRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
@ -188,8 +130,6 @@ FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
}
VOID
@ -198,10 +138,11 @@ FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
while (!IsListEmpty(&Connection->ListenRequest))
{
Entry = RemoveHeadList(&Connection->ListenRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
@ -210,17 +151,13 @@ FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
DereferenceObject(Bucket->AssociatedEndpoint);
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
}
VOID
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
{
ReferenceObject(Connection);
// flush receive queue
FlushReceiveQueue(Connection, Status, TRUE);
FlushReceiveQueue(Connection, Status);
/* We completed the reads successfully but we need to return failure now */
if (Status == STATUS_SUCCESS)
@ -232,15 +169,13 @@ FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
FlushListenQueue(Connection, Status);
// flush send queue
FlushSendQueue(Connection, Status, TRUE);
FlushSendQueue(Connection, Status);
// flush connect queue
FlushConnectQueue(Connection, Status);
// flush shutdown queue
FlushShutdownQueue(Connection, Status, TRUE);
DereferenceObject(Connection);
FlushShutdownQueue(Connection, Status);
}
VOID
@ -248,18 +183,17 @@ TCPFinEventHandler(void *arg, const err_t err)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg, LastConnection;
const NTSTATUS Status = TCPTranslateError(err);
KIRQL OldIrql;
ASSERT(Connection->SocketContext == NULL);
ASSERT(Connection->AddressFile);
ASSERT(err != ERR_OK);
LockObject(Connection);
/* Complete all outstanding requests now */
FlushAllQueues(Connection, Status);
LockObject(Connection, &OldIrql);
LockObjectAtDpcLevel(Connection->AddressFile);
LockObject(Connection->AddressFile);
/* Unlink this connection from the address file */
if (Connection->AddressFile->Connection == Connection)
@ -284,13 +218,13 @@ TCPFinEventHandler(void *arg, const err_t err)
}
}
UnlockObjectFromDpcLevel(Connection->AddressFile);
UnlockObject(Connection->AddressFile);
/* Remove the address file from this connection */
DereferenceObject(Connection->AddressFile);
Connection->AddressFile = NULL;
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
}
VOID
@ -301,14 +235,15 @@ TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
KIRQL OldIrql;
ReferenceObject(Connection);
LockObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
while (!IsListEmpty(&Connection->ListenRequest))
{
PIO_STACK_LOCATION IrpSp;
Entry = RemoveHeadList(&Connection->ListenRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
@ -326,7 +261,7 @@ TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
if (Status == STATUS_SUCCESS)
{
LockObject(Bucket->AssociatedEndpoint, &OldIrql);
LockObject(Bucket->AssociatedEndpoint);
/* sanity assert...this should never be in anything else but a CLOSED state */
ASSERT( ((PTCP_PCB)Bucket->AssociatedEndpoint->SocketContext)->state == CLOSED );
@ -337,9 +272,9 @@ TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
/* free previously created socket context (we don't use it, we use newpcb) */
Bucket->AssociatedEndpoint->SocketContext = newpcb;
LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint);
UnlockObject(Bucket->AssociatedEndpoint);
UnlockObject(Bucket->AssociatedEndpoint, OldIrql);
LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint);
}
DereferenceObject(Bucket->AssociatedEndpoint);
@ -352,7 +287,7 @@ TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
}
}
DereferenceObject(Connection);
UnlockObject(Connection);
}
VOID
@ -367,12 +302,17 @@ TCPSendEventHandler(void *arg, const u16_t space)
ULONG BytesSent;
ReferenceObject(Connection);
LockObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
while (!IsListEmpty(&Connection->SendRequest))
{
UINT SendLen = 0;
PVOID SendBuffer = 0;
Entry = RemoveHeadList(&Connection->SendRequest);
UnlockObject(Connection);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
@ -400,9 +340,8 @@ TCPSendEventHandler(void *arg, const u16_t space)
if( Status == STATUS_PENDING )
{
ExInterlockedInsertHeadList(&Connection->SendRequest,
&Bucket->Entry,
&Connection->Lock);
LockObject(Connection);
InsertHeadList(&Connection->SendRequest, &Bucket->Entry);
break;
}
else
@ -416,13 +355,15 @@ TCPSendEventHandler(void *arg, const u16_t space)
CompleteBucket(Connection, Bucket, FALSE);
}
LockObject(Connection);
}
// If we completed all outstanding send requests then finish all pending shutdown requests,
// cancel the timer and dereference the connection
if (IsListEmpty(&Connection->SendRequest))
{
FlushShutdownQueue(Connection, STATUS_SUCCESS, FALSE);
FlushShutdownQueue(Connection, STATUS_SUCCESS);
if (KeCancelTimer(&Connection->DisconnectTimer))
{
@ -430,6 +371,8 @@ TCPSendEventHandler(void *arg, const u16_t space)
}
}
UnlockObject(Connection);
DereferenceObject(Connection);
}
@ -446,10 +389,11 @@ TCPRecvEventHandler(void *arg)
PUCHAR RecvBuffer;
NTSTATUS Status;
ReferenceObject(Connection);
LockObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
while(!IsListEmpty(&Connection->ReceiveRequest))
{
Entry = RemoveHeadList(&Connection->ReceiveRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
@ -460,9 +404,7 @@ TCPRecvEventHandler(void *arg)
Status = LibTCPGetDataFromConnectionQueue(Connection, RecvBuffer, RecvLen, &Received);
if (Status == STATUS_PENDING)
{
ExInterlockedInsertHeadList(&Connection->ReceiveRequest,
&Bucket->Entry,
&Connection->Lock);
InsertHeadList(&Connection->ReceiveRequest, &Bucket->Entry);
break;
}
@ -471,8 +413,7 @@ TCPRecvEventHandler(void *arg)
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
UnlockObject(Connection);
}
VOID
@ -482,10 +423,11 @@ TCPConnectEventHandler(void *arg, const err_t err)
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
LockObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
while (!IsListEmpty(&Connection->ConnectRequest))
{
Entry = RemoveHeadList(&Connection->ConnectRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
@ -495,5 +437,5 @@ TCPConnectEventHandler(void *arg, const err_t err)
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
UnlockObject(Connection);
}

View file

@ -25,21 +25,27 @@ PORT_SET TCPPorts;
NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
VOID NTAPI
DisconnectTimeoutDpc(PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
static
IO_WORKITEM_ROUTINE
DisconnectWorker;
_Use_decl_annotations_
VOID
NTAPI
DisconnectWorker(
_Unreferenced_parameter_ PDEVICE_OBJECT DeviceObject,
_In_ PVOID Context
)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext;
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Context;
PLIST_ENTRY Entry;
PTDI_BUCKET Bucket;
LockObjectAtDpcLevel(Connection);
/* We timed out waiting for pending sends so force it to shutdown */
TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
LockObject(Connection);
while (!IsListEmpty(&Connection->SendRequest))
{
Entry = RemoveHeadList(&Connection->SendRequest);
@ -64,11 +70,23 @@ DisconnectTimeoutDpc(PKDPC Dpc,
CompleteBucket(Connection, Bucket, FALSE);
}
UnlockObjectFromDpcLevel(Connection);
UnlockObject(Connection);
DereferenceObject(Connection);
}
VOID
NTAPI
DisconnectTimeoutDpc(PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext;
IoQueueWorkItem(Connection->DisconnectWorkItem, DisconnectWorker, DelayedWorkQueue, Connection);
}
VOID ConnectionFree(PVOID Object)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object;
@ -80,6 +98,9 @@ VOID ConnectionFree(PVOID Object)
RemoveEntryList(&Connection->ListEntry);
TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
ExDeleteResourceLite(&Connection->Resource);
IoFreeWorkItem(Connection->DisconnectWorkItem);
ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
}
@ -96,7 +117,7 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext )
RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
/* Initialize spin lock that protects the connection endpoint file object */
KeInitializeSpinLock(&Connection->Lock);
ExInitializeResourceLite(&Connection->Resource);
InitializeListHead(&Connection->ConnectRequest);
InitializeListHead(&Connection->ListenRequest);
InitializeListHead(&Connection->ReceiveRequest);
@ -107,6 +128,13 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext )
/* Initialize disconnect timer */
KeInitializeTimer(&Connection->DisconnectTimer);
KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection);
Connection->DisconnectWorkItem = IoAllocateWorkItem(TCPDeviceObject);
if (!Connection->DisconnectWorkItem)
{
ExDeleteResourceLite(&Connection->Resource);
ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
return NULL;
}
/* Save client context pointer */
Connection->ClientContext = ClientContext;
@ -126,9 +154,8 @@ NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
UINT Family, UINT Type, UINT Proto )
{
NTSTATUS Status;
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
LockObject(Connection);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Called: Connection %x, Family %d, Type %d, "
"Proto %d, sizeof(CONNECTION_ENDPOINT) = %d\n",
@ -140,7 +167,7 @@ NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
else
Status = STATUS_INSUFFICIENT_RESOURCES;
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Leaving. Status = 0x%x\n", Status));
@ -149,15 +176,13 @@ NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection )
{
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
LockObject(Connection);
FlushAllQueues(Connection, STATUS_CANCELLED);
LibTCPClose(Connection, FALSE, TRUE);
UnlockObject(Connection);
UnlockObject(Connection, OldIrql);
LibTCPClose(Connection, FALSE, TRUE);
DereferenceObject(Connection);
@ -287,7 +312,6 @@ NTSTATUS TCPConnect
TA_IP_ADDRESS LocalAddress;
PTDI_BUCKET Bucket;
PNEIGHBOR_CACHE_ENTRY NCE;
KIRQL OldIrql;
TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n"));
@ -308,11 +332,11 @@ NTSTATUS TCPConnect
RemoteAddress.Address.IPv4Address,
RemotePort));
LockObject(Connection, &OldIrql);
LockObject(Connection);
if (!Connection->AddressFile)
{
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
return STATUS_INVALID_PARAMETER;
}
@ -320,7 +344,7 @@ NTSTATUS TCPConnect
{
if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
{
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
return STATUS_NETWORK_UNREACHABLE;
}
@ -335,48 +359,51 @@ NTSTATUS TCPConnect
&bindaddr,
Connection->AddressFile->Port));
if (NT_SUCCESS(Status))
if (!NT_SUCCESS(Status))
{
/* Copy bind address into connection */
Connection->AddressFile->Address.Address.IPv4Address = bindaddr.addr;
/* Check if we had an unspecified port */
if (!Connection->AddressFile->Port)
{
/* We did, so we need to copy back the port */
Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
if (NT_SUCCESS(Status))
{
/* Allocate the port in the port bitmap */
Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
/* This should never fail */
ASSERT(Connection->AddressFile->Port != 0xFFFF);
}
}
if (NT_SUCCESS(Status))
{
connaddr.addr = RemoteAddress.Address.IPv4Address;
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection, OldIrql);
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = (PVOID)Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
Status = TCPTranslateError(LibTCPConnect(Connection,
&connaddr,
RemotePort));
}
UnlockObject(Connection);
return Status;
}
UnlockObject(Connection, OldIrql);
/* Copy bind address into connection */
Connection->AddressFile->Address.Address.IPv4Address = bindaddr.addr;
/* Check if we had an unspecified port */
if (!Connection->AddressFile->Port)
{
/* We did, so we need to copy back the port */
Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
if (!NT_SUCCESS(Status))
{
UnlockObject(Connection);
return Status;
}
/* Allocate the port in the port bitmap */
Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
/* This should never fail */
ASSERT(Connection->AddressFile->Port != 0xFFFF);
}
connaddr.addr = RemoteAddress.Address.IPv4Address;
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection);
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = (PVOID)Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
UnlockObject(Connection);
Status = TCPTranslateError(LibTCPConnect(Connection,
&connaddr,
RemotePort));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status));
@ -394,12 +421,11 @@ NTSTATUS TCPDisconnect
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
LARGE_INTEGER ActualTimeout;
TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));
LockObject(Connection, &OldIrql);
LockObject(Connection);
if (Connection->SocketContext)
{
@ -407,12 +433,20 @@ NTSTATUS TCPDisconnect
{
if (IsListEmpty(&Connection->SendRequest))
{
ReferenceObject(Connection);
UnlockObject(Connection);
Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
LockObject(Connection);
DereferenceObject(Connection);
}
else if (Timeout && Timeout->QuadPart == 0)
{
FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
FlushSendQueue(Connection, STATUS_FILE_CLOSED);
ReferenceObject(Connection);
UnlockObject(Connection);
LibTCPShutdown(Connection, 0, 1);
LockObject(Connection);
DereferenceObject(Connection);
Status = STATUS_TIMEOUT;
}
else
@ -431,7 +465,7 @@ NTSTATUS TCPDisconnect
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
return STATUS_NO_MEMORY;
}
@ -441,11 +475,11 @@ NTSTATUS TCPDisconnect
InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry);
ReferenceObject(Connection);
if (KeCancelTimer(&Connection->DisconnectTimer))
if (KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc))
{
/* Timer was already in the queue. */
DereferenceObject(Connection);
}
KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc);
Status = STATUS_PENDING;
}
@ -453,20 +487,26 @@ NTSTATUS TCPDisconnect
if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
{
FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE);
FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE);
FlushReceiveQueue(Connection, STATUS_FILE_CLOSED);
FlushSendQueue(Connection, STATUS_FILE_CLOSED);
FlushShutdownQueue(Connection, STATUS_FILE_CLOSED);
ReferenceObject(Connection);
UnlockObject(Connection);
Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
DereferenceObject(Connection);
}
else
{
UnlockObject(Connection);
}
}
else
{
UnlockObject(Connection);
/* We already got closed by the other side so just return success */
Status = STATUS_SUCCESS;
}
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));
return Status;
@ -506,7 +546,9 @@ NTSTATUS TCPReceiveData
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
LockObject(Connection);
InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
UnlockObject(Connection);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n"));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n"));
@ -532,9 +574,8 @@ NTSTATUS TCPSendData
{
NTSTATUS Status;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
ReferenceObject(Connection);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n",
SendLength, Connection->SocketContext));
@ -558,7 +599,7 @@ NTSTATUS TCPSendData
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection, OldIrql);
DereferenceObject(Connection);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n"));
return STATUS_NO_MEMORY;
}
@ -566,13 +607,15 @@ NTSTATUS TCPSendData
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
LockObject(Connection);
InsertTailList( &Connection->SendRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
UnlockObject(Connection);
}
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status));
DereferenceObject(Connection);
return Status;
}
@ -606,13 +649,12 @@ NTSTATUS TCPGetSockAddress
PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
struct ip_addr ipaddr;
NTSTATUS Status;
KIRQL OldIrql;
AddressIP->TAAddressCount = 1;
AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
LockObject(Connection, &OldIrql);
LockObject(Connection);
if (GetRemote)
{
@ -627,7 +669,7 @@ NTSTATUS TCPGetSockAddress
&AddressIP->Address[0].Address[0].sin_port));
}
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
@ -641,7 +683,6 @@ BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
{
PLIST_ENTRY Entry;
PLIST_ENTRY ListHead[5];
KIRQL OldIrql;
PTDI_BUCKET Bucket;
UINT i = 0;
BOOLEAN Found = FALSE;
@ -652,7 +693,7 @@ BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
ListHead[3] = &Endpoint->ListenRequest;
ListHead[4] = &Endpoint->ShutdownRequest;
LockObject(Endpoint, &OldIrql);
LockObject(Endpoint);
for( i = 0; i < 5; i++ )
{
@ -671,7 +712,7 @@ BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
}
}
UnlockObject(Endpoint, OldIrql);
UnlockObject(Endpoint);
return Found;
}

View file

@ -171,9 +171,8 @@ NTSTATUS UDPSendDatagram(
USHORT RemotePort;
NTSTATUS Status;
PNEIGHBOR_CACHE_ENTRY NCE;
KIRQL OldIrql;
LockObject(AddrFile, &OldIrql);
LockObject(AddrFile);
TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
AddrFile, ConnInfo, BufferData, DataSize));
@ -188,7 +187,7 @@ NTSTATUS UDPSendDatagram(
break;
default:
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_UNSUCCESSFUL;
}
@ -200,7 +199,7 @@ NTSTATUS UDPSendDatagram(
* interface we're sending over
*/
if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_NETWORK_UNREACHABLE;
}
@ -209,7 +208,7 @@ NTSTATUS UDPSendDatagram(
else
{
if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) {
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
return STATUS_INVALID_PARAMETER;
}
}
@ -223,7 +222,7 @@ NTSTATUS UDPSendDatagram(
BufferData,
DataSize );
UnlockObject(AddrFile, OldIrql);
UnlockObject(AddrFile);
if( !NT_SUCCESS(Status) )
return Status;

View file

@ -31,6 +31,9 @@ struct lwip_callback_msg
struct {
PVOID Arg;
} Socket;
struct {
struct tcp_pcb* pcb;
} FreeSocket;
struct {
PCONNECTION_ENDPOINT Connection;
struct ip_addr *IpAddress;
@ -99,6 +102,7 @@ extern void TCPRecvEventHandler(void *arg);
/* TCP functions */
PTCP_PCB LibTCPSocket(void *arg);
VOID LibTCPFreeSocket(PTCP_PCB pcb);
err_t LibTCPBind(PCONNECTION_ENDPOINT Connection, struct ip_addr *const ipaddr, const u16_t port);
PTCP_PCB LibTCPListen(PCONNECTION_ENDPOINT Connection, const u8_t backlog);
err_t LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, u32_t *sent, const int safe);

View file

@ -81,7 +81,9 @@ void LibTCPEnqueuePacket(PCONNECTION_ENDPOINT Connection, struct pbuf *p)
qp->p = p;
qp->Offset = 0;
ExInterlockedInsertTailList(&Connection->PacketQueue, &qp->ListEntry, &Connection->Lock);
LockObject(Connection);
InsertTailList(&Connection->PacketQueue, &qp->ListEntry);
UnlockObject(Connection);
}
PQUEUE_ENTRY LibTCPDequeuePacket(PCONNECTION_ENDPOINT Connection)
@ -104,11 +106,10 @@ NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHA
struct pbuf* p;
NTSTATUS Status;
UINT ReadLength, PayloadLength, Offset, Copied;
KIRQL OldIrql;
(*Received) = 0;
LockObject(Connection, &OldIrql);
LockObject(Connection);
if (!IsListEmpty(&Connection->PacketQueue))
{
@ -132,13 +133,9 @@ NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHA
qp = NULL;
}
UnlockObject(Connection, OldIrql);
Copied = pbuf_copy_partial(p, RecvBuffer, ReadLength, Offset);
ASSERT(Copied == ReadLength);
LockObject(Connection, &OldIrql);
/* Update trackers */
RecvLen -= ReadLength;
RecvBuffer += ReadLength;
@ -172,7 +169,7 @@ NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHA
Status = STATUS_PENDING;
}
UnlockObject(Connection, OldIrql);
UnlockObject(Connection);
return Status;
}
@ -364,6 +361,33 @@ LibTCPSocket(void *arg)
return NULL;
}
static
void
LibTCPFreeSocketCallback(void *arg)
{
struct lwip_callback_msg *msg = arg;
ASSERT(msg);
/* Calling tcp_close will free it */
tcp_close(msg->Input.FreeSocket.pcb);
KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE);
}
void LibTCPFreeSocket(PTCP_PCB pcb)
{
struct lwip_callback_msg msg;
KeInitializeEvent(&msg.Event, NotificationEvent, FALSE);
msg.Input.FreeSocket.pcb = pcb;
tcpip_callback_with_block(LibTCPFreeSocketCallback, &msg, 1);
WaitForEventSafely(&msg.Event);
}
static
void
LibTCPBindCallback(void *arg)