X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Flib%2Fdrivers%2Fip%2Ftransport%2Ftcp%2Ftcp.c;fp=reactos%2Flib%2Fdrivers%2Fip%2Ftransport%2Ftcp%2Ftcp.c;h=ce46f9597d2b277fec224a54b452f89177fe868a;hp=951e807e34aef1296e8c331358519418c6b9e50a;hb=0a3dc4735f9acc13288684dd590472ed70c41e9e;hpb=6e4f110888e6cb7fb615f222e27a476c23952a20 diff --git a/reactos/lib/drivers/ip/transport/tcp/tcp.c b/reactos/lib/drivers/ip/transport/tcp/tcp.c index 951e807e34a..ce46f9597d2 100644 --- a/reactos/lib/drivers/ip/transport/tcp/tcp.c +++ b/reactos/lib/drivers/ip/transport/tcp/tcp.c @@ -14,311 +14,14 @@ LONG TCP_IPIdentification = 0; static BOOLEAN TCPInitialized = FALSE; -static NPAGED_LOOKASIDE_LIST TCPSegmentList; PORT_SET TCPPorts; -CLIENT_DATA ClientInfo; -VOID -CompleteBucketWorker(PVOID Context) -{ - PTDI_BUCKET Bucket = Context; - PCONNECTION_ENDPOINT Connection; - PTCP_COMPLETION_ROUTINE Complete; - - ASSERT(Bucket); - - Connection = Bucket->AssociatedEndpoint; - Complete = Bucket->Request.RequestNotifyObject; - - Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); - - ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); - - DereferenceObject(Connection); -} - -VOID -CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket) -{ - Bucket->AssociatedEndpoint = Connection; - ReferenceObject(Connection); - ChewCreate(CompleteBucketWorker, Bucket); -} - -VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection) -{ - PTDI_BUCKET Bucket; - PLIST_ENTRY Entry; - NTSTATUS Status; - PIRP Irp; - PMDL Mdl; - - if (ClientInfo.Unlocked) - LockObjectAtDpcLevel(Connection); - - TI_DbgPrint(MID_TRACE,("Handling signalled state on %x\n", - Connection)); - - /* Things that can happen when we try the initial connection */ - if( Connection->SignalState & (SEL_CONNECT | SEL_FIN | SEL_ERROR) ) { - while (!IsListEmpty(&Connection->ConnectRequest)) { - Entry = RemoveHeadList( &Connection->ConnectRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - if (Connection->SignalState & SEL_ERROR) - { - Bucket->Status = TCPTranslateError(OskitTCPGetSocketError(Connection)); - } - else if (Connection->SignalState & SEL_FIN) - { - Bucket->Status = STATUS_CANCELLED; - } - else - { - Bucket->Status = STATUS_SUCCESS; - } - Bucket->Information = 0; - - CompleteBucket(Connection, Bucket); - } - } - - if( Connection->SignalState & (SEL_ACCEPT | SEL_FIN | SEL_ERROR) ) { - /* Handle readable on a listening socket -- - * TODO: Implement filtering - */ - TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n", - Connection, - IsListEmpty(&Connection->ListenRequest) ? - "empty" : "nonempty")); - - while (!IsListEmpty(&Connection->ListenRequest)) { - PIO_STACK_LOCATION IrpSp; - - Entry = RemoveHeadList( &Connection->ListenRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - Irp = Bucket->Request.RequestContext; - IrpSp = IoGetCurrentIrpStackLocation( Irp ); - - TI_DbgPrint(DEBUG_TCP,("Getting the socket\n")); - - if (Connection->SignalState & SEL_ERROR) - { - Status = TCPTranslateError(OskitTCPGetSocketError(Connection)); - } - else if (Connection->SignalState & SEL_FIN) - { - Status = STATUS_CANCELLED; - } - else - { - Status = TCPServiceListeningSocket(Connection->AddressFile->Listener, - Bucket->AssociatedEndpoint, - (PTDI_REQUEST_KERNEL)&IrpSp->Parameters); - } - - TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n")); - - if( Status == STATUS_PENDING ) { - InsertHeadList( &Connection->ListenRequest, &Bucket->Entry ); - break; - } else { - Bucket->Status = Status; - Bucket->Information = 0; - DereferenceObject(Bucket->AssociatedEndpoint); - - CompleteBucket(Connection, Bucket); - } - } - } - - /* Things that happen after we're connected */ - if( Connection->SignalState & (SEL_READ | SEL_FIN | SEL_ERROR) ) { - TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n", - IsListEmpty(&Connection->ReceiveRequest) ? - "empty" : "nonempty")); - - while (!IsListEmpty(&Connection->ReceiveRequest)) { - OSK_UINT RecvLen = 0, Received = 0; - PVOID RecvBuffer = 0; - - Entry = RemoveHeadList( &Connection->ReceiveRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - Irp = Bucket->Request.RequestContext; - Mdl = Irp->MdlAddress; - - TI_DbgPrint(DEBUG_TCP, - ("Getting the user buffer from %x\n", Mdl)); - - NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen ); - - TI_DbgPrint(DEBUG_TCP, - ("Reading %d bytes to %x\n", RecvLen, RecvBuffer)); - - TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection)); - TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer)); - - if (Connection->SignalState & SEL_ERROR) - { - Status = TCPTranslateError(OskitTCPGetSocketError(Connection)); - } - else if (Connection->SignalState & SEL_FIN) - { - /* We got here because of a SEL_FIN event */ - Status = STATUS_CANCELLED; - } - else - { - Status = TCPTranslateError(OskitTCPRecv(Connection, - RecvBuffer, - RecvLen, - &Received, - 0)); - } - - TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received)); - - if( Status == STATUS_PENDING ) { - InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry ); - break; - } else { - TI_DbgPrint(DEBUG_TCP, - ("Completing Receive request: %x %x\n", - Bucket->Request, Status)); - - Bucket->Status = Status; - Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Received : 0; - - CompleteBucket(Connection, Bucket); - } - } - } - if( Connection->SignalState & (SEL_WRITE | SEL_FIN | SEL_ERROR) ) { - TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n", - IsListEmpty(&Connection->SendRequest) ? - "empty" : "nonempty")); - - while (!IsListEmpty(&Connection->SendRequest)) { - OSK_UINT SendLen = 0, Sent = 0; - PVOID SendBuffer = 0; - - Entry = RemoveHeadList( &Connection->SendRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - Irp = Bucket->Request.RequestContext; - Mdl = Irp->MdlAddress; - - TI_DbgPrint(DEBUG_TCP, - ("Getting the user buffer from %x\n", Mdl)); - - NdisQueryBuffer( Mdl, &SendBuffer, &SendLen ); - - TI_DbgPrint(DEBUG_TCP, - ("Writing %d bytes to %x\n", SendLen, SendBuffer)); - - TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection)); - - if (Connection->SignalState & SEL_ERROR) - { - Status = TCPTranslateError(OskitTCPGetSocketError(Connection)); - } - else if (Connection->SignalState & SEL_FIN) - { - /* We got here because of a SEL_FIN event */ - Status = STATUS_CANCELLED; - } - else - { - Status = TCPTranslateError(OskitTCPSend(Connection, - SendBuffer, - SendLen, - &Sent, - 0)); - } - - TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent)); - - if( Status == STATUS_PENDING ) { - InsertHeadList( &Connection->SendRequest, &Bucket->Entry ); - break; - } else { - TI_DbgPrint(DEBUG_TCP, - ("Completing Send request: %x %x\n", - Bucket->Request, Status)); - - Bucket->Status = Status; - Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Sent : 0; - - CompleteBucket(Connection, Bucket); - } - } - } - if( Connection->SignalState & (SEL_WRITE | SEL_FIN | SEL_ERROR) ) { - while (!IsListEmpty(&Connection->ShutdownRequest)) { - Entry = RemoveHeadList( &Connection->ShutdownRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - if (Connection->SignalState & SEL_ERROR) - { - Status = TCPTranslateError(OskitTCPGetSocketError(Connection)); - } - else if (Connection->SignalState & SEL_FIN) - { - /* We were cancelled by a FIN */ - Status = STATUS_CANCELLED; - } - else - { - /* See if we can satisfy this after the events */ - if (IsListEmpty(&Connection->SendRequest)) - { - /* Send queue is empty so we're good to go */ - Status = TCPTranslateError(OskitTCPShutdown(Connection, FWRITE)); - } - else - { - /* We still have to wait */ - Status = STATUS_PENDING; - } - } - - if( Status == STATUS_PENDING ) { - InsertHeadList( &Connection->ShutdownRequest, &Bucket->Entry ); - break; - } else { - TI_DbgPrint(DEBUG_TCP, - ("Completing shutdown request: %x %x\n", - Bucket->Request, Status)); - - if (KeCancelTimer(&Connection->DisconnectTimer)) - { - DereferenceObject(Connection); - } +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "lwip/arch.h" - Bucket->Status = Status; - Bucket->Information = 0; - - CompleteBucket(Connection, Bucket); - } - } - } - - if (Connection->SignalState & SEL_FIN) - { - Connection->SocketContext = NULL; - DereferenceObject(Connection); - } - - if (ClientInfo.Unlocked) - UnlockObjectFromDpcLevel(Connection); -} +#include "rosip.h" VOID NTAPI DisconnectTimeoutDpc(PKDPC Dpc, @@ -326,14 +29,15 @@ DisconnectTimeoutDpc(PKDPC Dpc, PVOID SystemArgument1, PVOID SystemArgument2) { - PCONNECTION_ENDPOINT Connection = DeferredContext; + PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext; PLIST_ENTRY Entry; PTDI_BUCKET Bucket; + NTSTATUS Status; LockObjectAtDpcLevel(Connection); /* We timed out waiting for pending sends so force it to shutdown */ - OskitTCPShutdown(Connection, FWRITE); + Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); while (!IsListEmpty(&Connection->SendRequest)) { @@ -344,10 +48,11 @@ DisconnectTimeoutDpc(PKDPC Dpc, Bucket->Information = 0; Bucket->Status = STATUS_FILE_CLOSED; - CompleteBucket(Connection, Bucket); + CompleteBucket(Connection, Bucket, FALSE); } - while (!IsListEmpty(&Connection->ShutdownRequest)) { + while (!IsListEmpty(&Connection->ShutdownRequest)) + { Entry = RemoveHeadList( &Connection->ShutdownRequest ); Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); @@ -355,7 +60,7 @@ DisconnectTimeoutDpc(PKDPC Dpc, Bucket->Status = STATUS_TIMEOUT; Bucket->Information = 0; - CompleteBucket(Connection, Bucket); + CompleteBucket(Connection, Bucket, FALSE); } UnlockObjectFromDpcLevel(Connection); @@ -363,8 +68,9 @@ DisconnectTimeoutDpc(PKDPC Dpc, DereferenceObject(Connection); } -VOID ConnectionFree(PVOID Object) { - PCONNECTION_ENDPOINT Connection = Object; +VOID ConnectionFree(PVOID Object) +{ + PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n")); @@ -376,8 +82,9 @@ VOID ConnectionFree(PVOID Object) { ExFreePoolWithTag( Connection, CONN_ENDPT_TAG ); } -PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) { - PCONNECTION_ENDPOINT Connection = +PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) +{ + PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT) ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT), CONN_ENDPT_TAG); if (!Connection) @@ -394,14 +101,16 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) { InitializeListHead(&Connection->ReceiveRequest); InitializeListHead(&Connection->SendRequest); InitializeListHead(&Connection->ShutdownRequest); - + InitializeListHead(&Connection->PacketQueue); + + /* Initialize disconnect timer */ KeInitializeTimer(&Connection->DisconnectTimer); KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection); /* Save client context pointer */ Connection->ClientContext = ClientContext; - Connection->RefCount = 2; + Connection->RefCount = 1; Connection->Free = ConnectionFree; /* Add connection endpoint to global list */ @@ -413,142 +122,64 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) { } NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection, - UINT Family, UINT Type, UINT Proto ) { + UINT Family, UINT Type, UINT Proto ) +{ NTSTATUS Status; KIRQL OldIrql; LockObject(Connection, &OldIrql); - TI_DbgPrint(DEBUG_TCP,("Called: Connection %x, Family %d, Type %d, " - "Proto %d\n", - Connection, Family, Type, Proto)); - - Status = TCPTranslateError( OskitTCPSocket( Connection, - &Connection->SocketContext, - Family, - Type, - Proto ) ); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Called: Connection %x, Family %d, Type %d, " + "Proto %d, sizeof(CONNECTION_ENDPOINT) = %d\n", + Connection, Family, Type, Proto, sizeof(CONNECTION_ENDPOINT))); - ASSERT_KM_POINTER(Connection->SocketContext); + Connection->SocketContext = LibTCPSocket(Connection); + if (Connection->SocketContext) + Status = STATUS_SUCCESS; + else + Status = STATUS_INSUFFICIENT_RESOURCES; UnlockObject(Connection, OldIrql); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Leaving. Status = 0x%x\n", Status)); + return Status; } -VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket) -/* - * FUNCTION: Receives and queues TCP data - * ARGUMENTS: - * IPPacket = Pointer to an IP packet that was received - * NOTES: - * This is the low level interface for receiving TCP data - */ +NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection ) { KIRQL OldIrql; + PVOID Socket; - TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n", - IPPacket->TotalSize, - IPPacket->HeaderSize)); + LockObject(Connection, &OldIrql); - KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql); - ClientInfo.Unlocked = TRUE; - ClientInfo.OldIrql = OldIrql; + Socket = Connection->SocketContext; - OskitTCPReceiveDatagram( IPPacket->Header, - IPPacket->TotalSize, - IPPacket->HeaderSize ); + FlushAllQueues(Connection, STATUS_CANCELLED); - ClientInfo.Unlocked = FALSE; - KeReleaseSpinLock(&ClientInfo.Lock, OldIrql); -} + LibTCPClose(Connection, FALSE, TRUE); -/* event.c */ -int TCPSocketState( void *ClientData, - void *WhichSocket, - void *WhichConnection, - OSK_UINT NewState ); - -int TCPPacketSend( void *ClientData, - OSK_PCHAR Data, - OSK_UINT Len ); - -POSK_IFADDR TCPFindInterface( void *ClientData, - OSK_UINT AddrType, - OSK_UINT FindType, - OSK_SOCKADDR *ReqAddr ); - -NTSTATUS TCPMemStartup( void ); -void *TCPMalloc( void *ClientData, - OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line ); -void TCPFree( void *ClientData, - void *data, OSK_PCHAR file, OSK_UINT line ); -void TCPMemShutdown( void ); - -OSKITTCP_EVENT_HANDLERS EventHandlers = { - NULL, /* Client Data */ - TCPSocketState, /* SocketState */ - TCPPacketSend, /* PacketSend */ - TCPFindInterface, /* FindInterface */ - TCPMalloc, /* Malloc */ - TCPFree, /* Free */ - NULL, /* Sleep */ - NULL, /* Wakeup */ -}; - -static KEVENT TimerLoopEvent; -static HANDLE TimerThreadHandle; - -/* - * We are running 2 timers here, one with a 200ms interval (fast) and the other - * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600, - * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the - * "slow" events at 500 and 1000. - */ -static VOID NTAPI -TimerThread(PVOID Context) -{ - LARGE_INTEGER Timeout; - NTSTATUS Status; - unsigned Current, NextFast, NextSlow, Next; - - Current = 0; - Next = 0; - NextFast = 0; - NextSlow = 0; - while ( 1 ) { - if (Next == NextFast) { - NextFast += 2; - } - if (Next == NextSlow) { - NextSlow += 5; - } - Next = min(NextFast, NextSlow); - Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */ - Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode, - FALSE, &Timeout); - if (Status != STATUS_TIMEOUT) { - PsTerminateSystemThread(Status); - } + UnlockObject(Connection, OldIrql); - TimerOskitTCP( Next == NextFast, Next == NextSlow ); + DereferenceObject(Connection); - Current = Next; - if (10 <= Current) { - Current = 0; - Next = 0; - NextFast = 0; - NextSlow = 0; - } - } + return STATUS_SUCCESS; } -static VOID -StartTimer(VOID) +VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket) +/* + * FUNCTION: Receives and queues TCP data + * ARGUMENTS: + * IPPacket = Pointer to an IP packet that was received + * NOTES: + * This is the low level interface for receiving TCP data + */ { - KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE); - PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, - TimerThread, NULL); + TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n", + IPPacket->TotalSize, + IPPacket->HeaderSize)); + + LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize); } NTSTATUS TCPStartup(VOID) @@ -560,37 +191,18 @@ NTSTATUS TCPStartup(VOID) { NTSTATUS Status; - Status = TCPMemStartup(); - if ( ! NT_SUCCESS(Status) ) { - return Status; - } - Status = PortsStartup( &TCPPorts, 1, 0xfffe ); - if( !NT_SUCCESS(Status) ) { - TCPMemShutdown(); + if (!NT_SUCCESS(Status)) + { return Status; } - - KeInitializeSpinLock(&ClientInfo.Lock); - ClientInfo.Unlocked = FALSE; - - RegisterOskitTCPEventHandlers( &EventHandlers ); - InitOskitTCP(); - + + /* Initialize our IP library */ + LibIPInitialize(); + /* Register this protocol with IP layer */ IPRegisterProtocol(IPPROTO_TCP, TCPReceive); - - ExInitializeNPagedLookasideList( - &TCPSegmentList, /* Lookaside list */ - NULL, /* Allocate routine */ - NULL, /* Free routine */ - 0, /* Flags */ - sizeof(TCP_SEGMENT), /* Size of each entry */ - 'SPCT', /* Tag */ - 0); /* Depth */ - - StartTimer(); - + TCPInitialized = TRUE; return STATUS_SUCCESS; @@ -604,99 +216,52 @@ NTSTATUS TCPShutdown(VOID) * Status of operation */ { - LARGE_INTEGER WaitForThread; - if (!TCPInitialized) return STATUS_SUCCESS; - - WaitForThread.QuadPart = -2500000; /* 250 ms */ - KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE); - ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread); + + LibIPShutdown(); /* Deregister this protocol with IP layer */ IPRegisterProtocol(IPPROTO_TCP, NULL); - ExDeleteNPagedLookasideList(&TCPSegmentList); - TCPInitialized = FALSE; - DeinitOskitTCP(); - PortsShutdown( &TCPPorts ); - TCPMemShutdown(); - return STATUS_SUCCESS; } -NTSTATUS TCPTranslateError( int OskitError ) { +NTSTATUS TCPTranslateError(const err_t err) +{ NTSTATUS Status; - switch( OskitError ) { - case 0: Status = STATUS_SUCCESS; break; - case OSK_EADDRNOTAVAIL: - Status = STATUS_INVALID_ADDRESS; - DbgPrint("OskitTCP: EADDRNOTAVAIL\n"); - break; - case OSK_EADDRINUSE: - Status = STATUS_ADDRESS_ALREADY_EXISTS; - DbgPrint("OskitTCP: EADDRINUSE\n"); - break; - case OSK_EAFNOSUPPORT: - Status = STATUS_INVALID_CONNECTION; - DbgPrint("OskitTCP: EAFNOSUPPORT\n"); - break; - case OSK_ECONNREFUSED: - Status = STATUS_REMOTE_NOT_LISTENING; - DbgPrint("OskitTCP: ECONNREFUSED\n"); - break; - case OSK_ECONNRESET: - Status = STATUS_REMOTE_DISCONNECT; - DbgPrint("OskitTCP: ECONNRESET\n"); - break; - case OSK_ECONNABORTED: - Status = STATUS_LOCAL_DISCONNECT; - DbgPrint("OskitTCP: ECONNABORTED\n"); - break; - case OSK_EWOULDBLOCK: - case OSK_EINPROGRESS: Status = STATUS_PENDING; break; - case OSK_EINVAL: - Status = STATUS_INVALID_PARAMETER; - DbgPrint("OskitTCP: EINVAL\n"); - break; - case OSK_ENOMEM: - case OSK_ENOBUFS: - Status = STATUS_INSUFFICIENT_RESOURCES; - DbgPrint("OskitTCP: ENOMEM/ENOBUFS\n"); - break; - case OSK_EPIPE: - case OSK_ESHUTDOWN: - Status = STATUS_FILE_CLOSED; - DbgPrint("OskitTCP: ESHUTDOWN/EPIPE\n"); - break; - case OSK_EMSGSIZE: - Status = STATUS_BUFFER_TOO_SMALL; - DbgPrint("OskitTCP: EMSGSIZE\n"); - break; - case OSK_ETIMEDOUT: - Status = STATUS_TIMEOUT; - DbgPrint("OskitTCP: ETIMEDOUT\n"); - break; - case OSK_ENETUNREACH: - Status = STATUS_NETWORK_UNREACHABLE; - DbgPrint("OskitTCP: ENETUNREACH\n"); - break; - case OSK_EFAULT: - Status = STATUS_ACCESS_VIOLATION; - DbgPrint("OskitTCP: EFAULT\n"); - break; - default: - DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError); - Status = STATUS_INVALID_CONNECTION; - break; + switch (err) + { + case ERR_OK: Status = STATUS_SUCCESS; return Status; //0 + case ERR_MEM: Status = STATUS_INSUFFICIENT_RESOURCES; break; //-1 + case ERR_BUF: Status = STATUS_BUFFER_TOO_SMALL; break; //-2 + case ERR_TIMEOUT: Status = STATUS_TIMEOUT; break; // -3 + case ERR_RTE: Status = STATUS_NETWORK_UNREACHABLE; break; //-4 + case ERR_INPROGRESS: Status = STATUS_PENDING; return Status; //-5 + case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-6 + case ERR_WOULDBLOCK: Status = STATUS_CANT_WAIT; break; //-7 + case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-8 + case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-9 (FIXME) + case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-10 + case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-11 + case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-12 + case ERR_CONN: Status = STATUS_INVALID_CONNECTION; break; //-13 + case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-14 + case ERR_IF: Status = STATUS_UNEXPECTED_NETWORK_ERROR; break; //-15 + default: + DbgPrint("Invalid error value: %d\n", err); + ASSERT(FALSE); + Status = STATUS_UNSUCCESSFUL; + break; } + + DbgPrint("TCP operation failed: 0x%x (%d)\n", Status, err); - TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status)); return Status; } @@ -705,24 +270,26 @@ NTSTATUS TCPConnect PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, - PVOID Context ) { + PVOID Context ) +{ NTSTATUS Status; - SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 }; + struct ip_addr bindaddr, connaddr; IP_ADDRESS RemoteAddress; USHORT RemotePort; TA_IP_ADDRESS LocalAddress; PTDI_BUCKET Bucket; - PNEIGHBOR_CACHE_ENTRY NCE = NULL; + PNEIGHBOR_CACHE_ENTRY NCE; KIRQL OldIrql; - TI_DbgPrint(DEBUG_TCP,("TCPConnect: Called\n")); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n")); Status = AddrBuildAddress ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress, &RemoteAddress, &RemotePort); - if (!NT_SUCCESS(Status)) { + if (!NT_SUCCESS(Status)) + { TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n")); return Status; } @@ -733,9 +300,6 @@ NTSTATUS TCPConnect RemoteAddress.Address.IPv4Address, RemotePort)); - AddressToConnect.sin_family = AF_INET; - AddressToBind = AddressToConnect; - LockObject(Connection, &OldIrql); if (!Connection->AddressFile) @@ -751,91 +315,61 @@ NTSTATUS TCPConnect UnlockObject(Connection, OldIrql); return STATUS_NETWORK_UNREACHABLE; } - } - if (Connection->AddressFile->Port) - { - /* See if we had an unspecified bind address */ - if (NCE) - { - /* We did, so use the interface unicast address associated with the route */ - AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address; - } - else - { - /* Bind address was explicit so use it */ - AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address; - } - - AddressToBind.sin_port = Connection->AddressFile->Port; - - /* Perform an explicit bind */ - Status = TCPTranslateError(OskitTCPBind(Connection, - &AddressToBind, - sizeof(AddressToBind))); + bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address; } else { - /* An implicit bind will be performed */ - Status = STATUS_SUCCESS; + bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address; } - if (NT_SUCCESS(Status)) { - if (NT_SUCCESS(Status)) + Status = TCPTranslateError(LibTCPBind(Connection, + &bindaddr, + Connection->AddressFile->Port)); + + if (NT_SUCCESS(Status)) + { + /* Check if we had an unspecified port */ + if (!Connection->AddressFile->Port) { - memcpy( &AddressToConnect.sin_addr, - &RemoteAddress.Address.IPv4Address, - sizeof(AddressToConnect.sin_addr) ); - AddressToConnect.sin_port = RemotePort; - - Status = TCPTranslateError - ( OskitTCPConnect( Connection, - &AddressToConnect, - sizeof(AddressToConnect) ) ); - + /* We did, so we need to copy back the port */ + Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE); if (NT_SUCCESS(Status)) { - /* Check if we had an unspecified port */ - if (!Connection->AddressFile->Port) - { - /* We did, so we need to copy back the port */ - if (NT_SUCCESS(TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE))) - { - /* 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); - } - } - - /* Check if the address was unspecified */ - if (AddrIsUnspecified(&Connection->AddressFile->Address)) - { - /* It is, so store the address of the outgoing NIC */ - Connection->AddressFile->Address = NCE->Interface->Unicast; - } + /* 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 (Status == STATUS_PENDING) + if (NT_SUCCESS(Status)) + { + connaddr.addr = RemoteAddress.Address.IPv4Address; + + Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG ); + if (!Bucket) { - Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG ); - if( !Bucket ) - { - UnlockObject(Connection, OldIrql); - return STATUS_NO_MEMORY; - } - - Bucket->Request.RequestNotifyObject = (PVOID)Complete; - Bucket->Request.RequestContext = Context; - - InsertTailList( &Connection->ConnectRequest, &Bucket->Entry ); + 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, OldIrql); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status)); + return Status; } @@ -846,155 +380,86 @@ NTSTATUS TCPDisconnect PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, - PVOID Context ) { + PVOID Context ) +{ NTSTATUS Status = STATUS_INVALID_PARAMETER; PTDI_BUCKET Bucket; KIRQL OldIrql; - PLIST_ENTRY Entry; LARGE_INTEGER ActualTimeout; - TI_DbgPrint(DEBUG_TCP,("started\n")); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n")); LockObject(Connection, &OldIrql); - if (Flags & TDI_DISCONNECT_RELEASE) + if (Connection->SocketContext) { - /* See if we can satisfy this right now */ - if (IsListEmpty(&Connection->SendRequest)) + if (Flags & TDI_DISCONNECT_RELEASE) { - /* Send queue is empty so we're good to go */ - Status = TCPTranslateError(OskitTCPShutdown(Connection, FWRITE)); - - UnlockObject(Connection, OldIrql); - - return Status; - } - - /* Check if the timeout was 0 */ - if (Timeout && Timeout->QuadPart == 0) - { - OskitTCPShutdown(Connection, FWRITE); - - while (!IsListEmpty(&Connection->SendRequest)) + if (IsListEmpty(&Connection->SendRequest)) { - Entry = RemoveHeadList(&Connection->SendRequest); - - Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); - - Bucket->Information = 0; - Bucket->Status = STATUS_FILE_CLOSED; - - CompleteBucket(Connection, Bucket); + Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); } - - UnlockObject(Connection, OldIrql); - - return STATUS_TIMEOUT; - } - - /* Otherwise we wait for the send queue to be empty */ - } + else if (Timeout && Timeout->QuadPart == 0) + { + FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE); + TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); + Status = STATUS_TIMEOUT; + } + else + { + /* Use the timeout specified or 1 second if none was specified */ + if (Timeout) + { + ActualTimeout = *Timeout; + } + else + { + ActualTimeout.QuadPart = -1000000; + } - if ((Flags & TDI_DISCONNECT_ABORT) || !Flags) - { - /* This request overrides any pending graceful disconnects */ - while (!IsListEmpty(&Connection->ShutdownRequest)) - { - Entry = RemoveHeadList(&Connection->ShutdownRequest); - - Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); - - Bucket->Information = 0; - Bucket->Status = STATUS_FILE_CLOSED; - - CompleteBucket(Connection, Bucket); - } - - /* Also kill any pending reads and writes */ - while (!IsListEmpty(&Connection->SendRequest)) - { - Entry = RemoveHeadList(&Connection->SendRequest); - - Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); - - Bucket->Information = 0; - Bucket->Status = STATUS_FILE_CLOSED; - - CompleteBucket(Connection, Bucket); + /* We couldn't complete the request now because we need to wait for outstanding I/O */ + Bucket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG); + if (!Bucket) + { + UnlockObject(Connection, OldIrql); + return STATUS_NO_MEMORY; + } + + Bucket->Request.RequestNotifyObject = (PVOID)Complete; + Bucket->Request.RequestContext = Context; + + InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry); + + ReferenceObject(Connection); + if (KeCancelTimer(&Connection->DisconnectTimer)) + { + DereferenceObject(Connection); + } + KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc); + + Status = STATUS_PENDING; + } } - - while (!IsListEmpty(&Connection->ReceiveRequest)) + + if ((Flags & TDI_DISCONNECT_ABORT) || !Flags) { - Entry = RemoveHeadList(&Connection->ReceiveRequest); - - Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); - - Bucket->Information = 0; - Bucket->Status = STATUS_FILE_CLOSED; - - CompleteBucket(Connection, Bucket); + FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE); + FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE); + FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE); + Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1)); } - - /* An abort never pends; we just drop everything and complete */ - Status = TCPTranslateError(OskitTCPShutdown(Connection, FWRITE | FREAD)); - - UnlockObject(Connection, OldIrql); - - return Status; - } - - /* We couldn't complete the request now because we need to wait for outstanding I/O */ - Bucket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG); - if (!Bucket) - { - UnlockObject(Connection, OldIrql); - return STATUS_NO_MEMORY; - } - - Bucket->Request.RequestNotifyObject = (PVOID)Complete; - Bucket->Request.RequestContext = Context; - - InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry); - - /* Use the timeout specified or 1 second if none was specified */ - if (Timeout) - { - ActualTimeout = *Timeout; } else { - ActualTimeout.QuadPart = -1000000; + /* We already got closed by the other side so just return success */ + Status = STATUS_SUCCESS; } - - ReferenceObject(Connection); - KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc); UnlockObject(Connection, OldIrql); - TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status)); - - return STATUS_PENDING; -} + TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status)); -NTSTATUS TCPClose -( PCONNECTION_ENDPOINT Connection ) -{ - KIRQL OldIrql; - - LockObject(Connection, &OldIrql); - - /* We should not be associated to an address file at this point */ - ASSERT(!Connection->AddressFile); - - OskitTCPClose(Connection); - - Connection->SocketContext = NULL; - - UnlockObject(Connection, OldIrql); - - DereferenceObject(Connection); - - return STATUS_SUCCESS; + return Status; } NTSTATUS TCPReceiveData @@ -1004,53 +469,46 @@ NTSTATUS TCPReceiveData PULONG BytesReceived, ULONG ReceiveFlags, PTCP_COMPLETION_ROUTINE Complete, - PVOID Context ) { - PVOID DataBuffer; - UINT DataLen, Received = 0; - NTSTATUS Status; + PVOID Context ) +{ PTDI_BUCKET Bucket; - KIRQL OldIrql; - - NdisQueryBuffer( Buffer, &DataBuffer, &DataLen ); - - TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen)); + PUCHAR DataBuffer; + UINT DataLen, Received; + NTSTATUS Status; - LockObject(Connection, &OldIrql); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n", + ReceiveLength, Connection->SocketContext)); - Status = TCPTranslateError - ( OskitTCPRecv - ( Connection, - DataBuffer, - DataLen, - &Received, - ReceiveFlags ) ); + NdisQueryBuffer(Buffer, &DataBuffer, &DataLen); - TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received)); + Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received); - /* Keep this request around ... there was no data yet */ - if( Status == STATUS_PENDING ) { + if (Status == STATUS_PENDING) + { + /* Freed in TCPSocketState */ - Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG ); - if( !Bucket ) { - TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n")); - UnlockObject(Connection, OldIrql); + Bucket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG); + if (!Bucket) + { + TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Failed to allocate bucket\n")); + return STATUS_NO_MEMORY; } - + Bucket->Request.RequestNotifyObject = Complete; Bucket->Request.RequestContext = Context; - *BytesReceived = 0; - InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry ); - TI_DbgPrint(DEBUG_TCP,("Queued read irp\n")); - } else { - TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received)); - *BytesReceived = Received; - } + ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock ); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n")); - UnlockObject(Connection, OldIrql); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n")); - TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status)); + (*BytesReceived) = 0; + } + else + { + (*BytesReceived) = Received; + } return Status; } @@ -1062,30 +520,37 @@ NTSTATUS TCPSendData PULONG BytesSent, ULONG Flags, PTCP_COMPLETION_ROUTINE Complete, - PVOID Context ) { - UINT Sent = 0; + PVOID Context ) +{ NTSTATUS Status; PTDI_BUCKET Bucket; KIRQL OldIrql; LockObject(Connection, &OldIrql); - TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection)); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n", + SendLength, Connection->SocketContext)); - Status = TCPTranslateError - ( OskitTCPSend( Connection, - (OSK_PCHAR)BufferData, SendLength, - &Sent, 0 ) ); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection)); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n", + Connection->SocketContext)); - TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent)); + Status = TCPTranslateError(LibTCPSend(Connection, + BufferData, + SendLength, + FALSE)); + + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength)); /* Keep this request around ... there was no data yet */ - if( Status == STATUS_PENDING ) { + if (Status == STATUS_PENDING) + { /* Freed in TCPSocketState */ Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG ); - if( !Bucket ) { + if (!Bucket) + { UnlockObject(Connection, OldIrql); - TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n")); + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n")); return STATUS_NO_MEMORY; } @@ -1094,65 +559,83 @@ NTSTATUS TCPSendData *BytesSent = 0; InsertTailList( &Connection->SendRequest, &Bucket->Entry ); - TI_DbgPrint(DEBUG_TCP,("Queued write irp\n")); - } else { - TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent)); - *BytesSent = Sent; + TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n")); + } + else if (Status == STATUS_SUCCESS) + { + *BytesSent = SendLength; + } + else + { + *BytesSent = 0; } UnlockObject(Connection, OldIrql); - TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status)); + TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status)); return Status; } -UINT TCPAllocatePort( UINT HintPort ) { - if( HintPort ) { - if( AllocatePort( &TCPPorts, HintPort ) ) return HintPort; - else { - TI_DbgPrint - (MID_TRACE,("We got a hint port but couldn't allocate it\n")); +UINT TCPAllocatePort(const UINT HintPort) +{ + if (HintPort) + { + if (AllocatePort(&TCPPorts, HintPort)) + return HintPort; + else + { + TI_DbgPrint(MID_TRACE,("We got a hint port but couldn't allocate it\n")); return (UINT)-1; } - } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 ); + } + else + return AllocatePortFromRange( &TCPPorts, 1024, 5000 ); } -VOID TCPFreePort( UINT Port ) { - DeallocatePort( &TCPPorts, Port ); +VOID TCPFreePort(const UINT Port) +{ + DeallocatePort(&TCPPorts, Port); } NTSTATUS TCPGetSockAddress ( PCONNECTION_ENDPOINT Connection, PTRANSPORT_ADDRESS Address, - BOOLEAN GetRemote ) { - OSK_UINT LocalAddress, RemoteAddress; - OSK_UI16 LocalPort, RemotePort; + BOOLEAN GetRemote ) +{ 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); - Status = TCPTranslateError(OskitTCPGetAddress(Connection, - &LocalAddress, &LocalPort, - &RemoteAddress, &RemotePort)); + if (GetRemote) + { + Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext, + &ipaddr, + &AddressIP->Address[0].Address[0].sin_port)); + } + else + { + Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext, + &ipaddr, + &AddressIP->Address[0].Address[0].sin_port)); + } UnlockObject(Connection, OldIrql); - - if (!NT_SUCCESS(Status)) - return Status; - - AddressIP->TAAddressCount = 1; - AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; - AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; - AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort; - AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress; + + AddressIP->Address[0].Address[0].in_addr = ipaddr.addr; return Status; } -BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) { +BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) +{ PLIST_ENTRY Entry; PLIST_ENTRY ListHead[5]; KIRQL OldIrql;