From 318a90741d72a285fe673caaff307127bc5edc4b Mon Sep 17 00:00:00 2001 From: Casper Hornstrup Date: Thu, 4 Mar 2004 20:45:39 +0000 Subject: [PATCH] 2004-03-04 Casper S. Hornstrup * drivers/net/tcpip/tcpip/i386: New directory. * drivers/net/tcpip/tcpip/i386/checksum.S: New file. * drivers/net/tcpip/notes.txt: New file. * drivers/net/afd/afd/dispatch.c (AfdDispCompleteListen): Signal ACCEPT network event. (AfdDispEventSelect): Reference event handle. * drivers/net/afd/afd/tdi.c (TdiListen): Remove unused event. Move Iosb and RequestConnectionInfo to AFD_LISTEN_REQUEST structure. * drivers/net/afd/include/afd.h (AFDFCB): Replace EventObjects with EventObject of type PKEVENT. * drivers/net/tcpip/makefile (ARCH_OBJECTS): New variable. (TARGET_OBJECTS): Add ARCH_OBJECTS. * drivers/net/tcpip/include/address.h (AddrCloneAddress): New prototype. * drivers/net/tcpip/include/checksum.h (ChecksumFold, csum_partial): New prototype. (TCPv4Checksum): New macro. (CorrectChecksum): Rename to IPv4CorrectChecksum. (TCPv4CorrectChecksum): New macro. * drivers/net/tcpip/include/ip.h (IPv4_DF_MASK): New constant. * drivers/net/tcpip/include/tcp.h (TCP_XXX): Correct constants. (TCPCreateSegment, TCPFreeSegment, TCPAddSegment): Prototype. * drivers/net/tcpip/include/titypes.h (TCP_SEND_REQUEST): Add SequenceNumber and AckNumber. (TCP_SEGMENT): New structure. (CONNECTION_ENDPOINT): Add ListenRequest and ReceivedSegments. * drivers/net/tcpip/network/transmit.c (SendFragments): Release memory for Data on failure. * drivers/net/tcpip/tcpip/address.c (AddrCloneAddress): New function. * drivers/net/tcpip/tcpip/checksum.c (ChecksumFold): Factor out folding from ChecksumCompute. * drivers/net/tcpip/tcpip/dispatch.c (DispTdiListen): Support asynchronous operation. * drivers/net/tcpip/tcpip/fileobjs.c (FileOpenAddress): Don't cast to PTDI_ADDRESS_IP. Initialize ReceivedSegments. * drivers/net/tcpip/tcpip/routines.c (DisplayIPHeader): New function. (DisplayIPPacket): Call DisplayIPHeader(). (DisplayTCPHeader): Change format strings. * drivers/net/tcpip/transport/tcp/tcp.c (IPIdentification, TCPSegmentList): Add. (TCPCreateSegment, TCPFreeSegment, TCPAddSegment, TCPBuildAndTransmitSendRequest2, TCPiSelectISS, TCPiReceiveListen, TCPiReceiveSynSent, TCPiReceiveSynReceived, TCPiReceiveData): New function. (TCPiBuildPacket): Build segment. (TCPStartup): Initialize TCPSegmentList. (TCPShutdown): Cleanup TCPSegmentList. svn path=/trunk/; revision=8537 --- reactos/ChangeLog | 50 + reactos/drivers/net/afd/afd/dispatch.c | 62 +- reactos/drivers/net/afd/afd/tdi.c | 39 +- reactos/drivers/net/afd/include/afd.h | 6 +- reactos/drivers/net/tcpip/include/address.h | 3 + reactos/drivers/net/tcpip/include/checksum.h | 29 +- reactos/drivers/net/tcpip/include/ip.h | 9 +- reactos/drivers/net/tcpip/include/tcp.h | 63 +- reactos/drivers/net/tcpip/include/titypes.h | 26 +- reactos/drivers/net/tcpip/makefile | 6 +- reactos/drivers/net/tcpip/network/icmp.c | 2 +- reactos/drivers/net/tcpip/network/receive.c | 2 +- reactos/drivers/net/tcpip/network/transmit.c | 6 +- reactos/drivers/net/tcpip/notes.txt | 27 + reactos/drivers/net/tcpip/tcpip/address.c | 27 +- reactos/drivers/net/tcpip/tcpip/checksum.c | 47 +- reactos/drivers/net/tcpip/tcpip/dispatch.c | 58 +- reactos/drivers/net/tcpip/tcpip/fileobjs.c | 7 +- .../drivers/net/tcpip/tcpip/i386/checksum.S | 249 ++++ reactos/drivers/net/tcpip/tcpip/routines.c | 65 +- reactos/drivers/net/tcpip/transport/tcp/tcp.c | 1134 +++++++++++++---- reactos/lib/msafd/include/msafd.h | 7 + reactos/lib/msafd/misc/dllmain.c | 62 +- 23 files changed, 1577 insertions(+), 409 deletions(-) create mode 100644 reactos/drivers/net/tcpip/notes.txt create mode 100644 reactos/drivers/net/tcpip/tcpip/i386/checksum.S diff --git a/reactos/ChangeLog b/reactos/ChangeLog index a2ad4d45f3b..df43974f9f6 100644 --- a/reactos/ChangeLog +++ b/reactos/ChangeLog @@ -1,3 +1,53 @@ +2004-03-04 Casper S. Hornstrup + + * drivers/net/tcpip/tcpip/i386: New directory. + * drivers/net/tcpip/tcpip/i386/checksum.S: New file. + * drivers/net/tcpip/notes.txt: New file. + * drivers/net/afd/afd/dispatch.c (AfdDispCompleteListen): Signal ACCEPT + network event. + (AfdDispEventSelect): Reference event handle. + * drivers/net/afd/afd/tdi.c (TdiListen): Remove unused event. + Move Iosb and RequestConnectionInfo to AFD_LISTEN_REQUEST structure. + * drivers/net/afd/include/afd.h (AFDFCB): Replace EventObjects with + EventObject of type PKEVENT. + * drivers/net/tcpip/makefile (ARCH_OBJECTS): New variable. + (TARGET_OBJECTS): Add ARCH_OBJECTS. + * drivers/net/tcpip/include/address.h (AddrCloneAddress): New prototype. + * drivers/net/tcpip/include/checksum.h (ChecksumFold, csum_partial): New + prototype. + (TCPv4Checksum): New macro. + (CorrectChecksum): Rename to IPv4CorrectChecksum. + (TCPv4CorrectChecksum): New macro. + * drivers/net/tcpip/include/ip.h (IPv4_DF_MASK): New constant. + * drivers/net/tcpip/include/tcp.h (TCP_XXX): Correct constants. + (TCPCreateSegment, TCPFreeSegment, TCPAddSegment): Prototype. + * drivers/net/tcpip/include/titypes.h (TCP_SEND_REQUEST): Add SequenceNumber + and AckNumber. + (TCP_SEGMENT): New structure. + (CONNECTION_ENDPOINT): Add ListenRequest and ReceivedSegments. + * drivers/net/tcpip/network/transmit.c (SendFragments): Release memory + for Data on failure. + * drivers/net/tcpip/tcpip/address.c (AddrCloneAddress): New function. + * drivers/net/tcpip/tcpip/checksum.c (ChecksumFold): Factor out folding + from ChecksumCompute. + * drivers/net/tcpip/tcpip/dispatch.c (DispTdiListen): Support asynchronous + operation. + * drivers/net/tcpip/tcpip/fileobjs.c (FileOpenAddress): Don't cast to + PTDI_ADDRESS_IP. + Initialize ReceivedSegments. + * drivers/net/tcpip/tcpip/routines.c (DisplayIPHeader): New function. + (DisplayIPPacket): Call DisplayIPHeader(). + (DisplayTCPHeader): Change format strings. + * drivers/net/tcpip/transport/tcp/tcp.c (IPIdentification, + TCPSegmentList): Add. + (TCPCreateSegment, TCPFreeSegment, TCPAddSegment, + TCPBuildAndTransmitSendRequest2, TCPiSelectISS, TCPiReceiveListen, + TCPiReceiveSynSent, TCPiReceiveSynReceived, TCPiReceiveData): New + function. + (TCPiBuildPacket): Build segment. + (TCPStartup): Initialize TCPSegmentList. + (TCPShutdown): Cleanup TCPSegmentList. + 2004-02-25 Casper S. Hornstrup * drivers/net/tcpip/datalink/loopback.c: Reformat. diff --git a/reactos/drivers/net/afd/afd/dispatch.c b/reactos/drivers/net/afd/afd/dispatch.c index d7cfdc2e708..f1dd9dcf33f 100644 --- a/reactos/drivers/net/afd/afd/dispatch.c +++ b/reactos/drivers/net/afd/afd/dispatch.c @@ -139,9 +139,25 @@ AfdDispCompleteListen( { PAFD_LISTEN_REQUEST ListenRequest = (PAFD_LISTEN_REQUEST) Context; - AFD_DbgPrint(MAX_TRACE, ("Called. ListenRequest (0x%X).\n", ListenRequest)); + /* FIXME: Protect ListenRequest->Fcb->ListenRequestQueue */ + RemoveEntryList(&ListenRequest->ListEntry); - AFD_DbgPrint(MAX_TRACE, ("Fcb (0x%X).\n", ListenRequest->Fcb)); + AFD_DbgPrint(MAX_TRACE, ("Completed ListenRequest at (0x%X).\n", ListenRequest)); + + if (NT_SUCCESS(ListenRequest->Iosb.Status)) + { + if (ListenRequest->Fcb->EventObject != NULL) + { + /* FIXME: Protect ListenRequest->Fcb */ + ListenRequest->Fcb->NetworkEvents.lNetworkEvents |= FD_ACCEPT; + ListenRequest->Fcb->NetworkEvents.iErrorCode[FD_ACCEPT_BIT] = NO_ERROR; + KeSetEvent(ListenRequest->Fcb->EventObject, EVENT_INCREMENT, FALSE); + } + } + + ExFreePool(ListenRequest->RequestConnectionInfo); + ListenRequest->RequestConnectionInfo = NULL; + ExFreePool(ListenRequest); return STATUS_SUCCESS; } @@ -197,14 +213,14 @@ NTSTATUS AfdDispListen( if (NT_SUCCESS(Status)) { - ListenRequest = ExAllocateFromNPagedLookasideList(&ListenRequestLookasideList); + ListenRequest = ExAllocateFromNPagedLookasideList(&ListenRequestLookasideList); if (ListenRequest != NULL) { ListenRequest->Fcb = FCB; /* FIXME: Protect ListenRequestQueue */ InsertTailList(&FCB->ListenRequestQueue, &ListenRequest->ListEntry); - Status = TdiListen(FCB->TdiConnectionObject, AfdDispCompleteListen, ListenRequest); + Status = TdiListen(ListenRequest, AfdDispCompleteListen, ListenRequest); if ((Status == STATUS_PENDING) || NT_SUCCESS(Status)) { if (Status != STATUS_PENDING) @@ -630,8 +646,8 @@ NTSTATUS AfdDispEventSelect( UINT OutputBufferLength; PFILE_REQUEST_EVENTSELECT Request; PFILE_REPLY_EVENTSELECT Reply; + PKEVENT Event; PAFDFCB FCB; - ULONG i; InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; @@ -644,20 +660,32 @@ NTSTATUS AfdDispEventSelect( Request = (PFILE_REQUEST_EVENTSELECT)Irp->AssociatedIrp.SystemBuffer; Reply = (PFILE_REPLY_EVENTSELECT)Irp->AssociatedIrp.SystemBuffer; - FCB->NetworkEvents.lNetworkEvents = Request->lNetworkEvents; - for (i = 0; i < FD_MAX_EVENTS; i++) { - if ((Request->lNetworkEvents & (1 << i)) > 0) { - FCB->EventObjects[i] = Request->hEventObject; - } else { - /* The effect of any previous call to this function is cancelled */ - FCB->EventObjects[i] = (WSAEVENT)0; - } - } + /* FIXME: Need to ObDereferenceObject(FCB->EventObject) this somewhere */ + Status = ObReferenceObjectByHandle( + Request->hEventObject, + 0, + ExEventObjectType, + UserMode, + (PVOID*)&Event, + NULL); + if (NT_SUCCESS(Status)) { + FCB->NetworkEvents.lNetworkEvents = Request->lNetworkEvents; + FCB->EventObject = Event; + Reply->Status = NO_ERROR; + Status = STATUS_SUCCESS; + } + else + { + AFD_DbgPrint(MID_TRACE, ("Bad event handle (0x%X).\n", Status)); - Reply->Status = NO_ERROR; - Status = STATUS_SUCCESS; - } else + Reply->Status = WSAEINVAL; + Status = STATUS_SUCCESS; + } + } + else + { Status = STATUS_INVALID_PARAMETER; + } AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status)); diff --git a/reactos/drivers/net/afd/afd/tdi.c b/reactos/drivers/net/afd/afd/tdi.c index ad5602cc550..a2c6d8258f2 100644 --- a/reactos/drivers/net/afd/afd/tdi.c +++ b/reactos/drivers/net/afd/afd/tdi.c @@ -199,6 +199,7 @@ NTSTATUS TdiOpenAddressFileIPv4( EaInfo->EaValueLength = sizeof(TA_IP_ADDRESS); Address = (PTA_IP_ADDRESS)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1); /* 0-terminated */ TdiBuildAddressIPv4(Address, Name); + Status = TdiOpenDevice(DeviceName, EaLength, EaInfo, @@ -414,13 +415,13 @@ NTSTATUS TdiAssociateAddressFile( NTSTATUS TdiListen( - PFILE_OBJECT ConnectionObject, + PAFD_LISTEN_REQUEST ListenRequest, PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID CompletionContext) /* * FUNCTION: Listen on a connection endpoint for a connection request from a remote peer * ARGUMENTS: - * ConnectionObject = Pointer to connection endpoint file object + * ListenRequest = Pointer to listen request object * CompletionRoutine = Routine to be called when IRP is completed * CompletionContext = Context for CompletionRoutine * RETURNS: @@ -428,35 +429,34 @@ NTSTATUS TdiListen( * May return STATUS_PENDING */ { - PTDI_CONNECTION_INFORMATION RequestConnectionInfo; - //PTDI_CONNECTION_INFORMATION ReturnConnectionInfo; + PFILE_OBJECT ConnectionObject; PDEVICE_OBJECT DeviceObject; - IO_STATUS_BLOCK Iosb; NTSTATUS Status; - KEVENT Event; PIRP Irp; AFD_DbgPrint(MAX_TRACE, ("Called\n")); + ConnectionObject = ListenRequest->Fcb->TdiConnectionObject; assert(ConnectionObject); DeviceObject = IoGetRelatedDeviceObject(ConnectionObject); - Status = TdiBuildNullConnectionInfo(&RequestConnectionInfo, TDI_ADDRESS_TYPE_IP); + Status = TdiBuildNullConnectionInfo(&ListenRequest->RequestConnectionInfo, + TDI_ADDRESS_TYPE_IP); if (!NT_SUCCESS(Status)) - return Status; - - KeInitializeEvent(&Event, NotificationEvent, FALSE); + return Status; Irp = TdiBuildInternalDeviceControlIrp(TDI_LISTEN, /* Sub function */ DeviceObject, /* Device object */ ConnectionObject, /* File object */ - &Event, /* Event */ - &Iosb); /* Status */ - if (!Irp) { - ExFreePool(RequestConnectionInfo); - return STATUS_INSUFFICIENT_RESOURCES; - } + NULL, /* Event */ + &ListenRequest->Iosb); /* Status */ + if (Irp == NULL) + { + ExFreePool(ListenRequest->RequestConnectionInfo); + ListenRequest->RequestConnectionInfo = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } TdiBuildListen(Irp, /* IRP */ DeviceObject, /* Device object */ @@ -464,13 +464,10 @@ NTSTATUS TdiListen( CompletionRoutine, /* Completion routine */ CompletionContext, /* Completion routine context */ 0, /* Flags */ - RequestConnectionInfo, /* Request connection information */ + ListenRequest->RequestConnectionInfo, /* Request connection information */ NULL /* ReturnConnectionInfo */); /* Return connection information */ - Status = TdiCall(Irp, DeviceObject, NULL /* Don't wait for completion */, &Iosb); - - ExFreePool(RequestConnectionInfo); - //ExFreePool(ReturnConnectionInfo); + Status = TdiCall(Irp, DeviceObject, NULL /* Don't wait for completion */, &ListenRequest->Iosb); return Status; } diff --git a/reactos/drivers/net/afd/include/afd.h b/reactos/drivers/net/afd/include/afd.h index 3c1fcb3cf83..c73c45a6568 100644 --- a/reactos/drivers/net/afd/include/afd.h +++ b/reactos/drivers/net/afd/include/afd.h @@ -75,7 +75,7 @@ typedef struct _AFDFCB { LIST_ENTRY ListenRequestQueue; /* For WSAEventSelect() */ WSANETWORKEVENTS NetworkEvents; - WSAEVENT EventObjects[FD_MAX_EVENTS]; + PKEVENT EventObject; } AFDFCB, *PAFDFCB; /* Socket states */ @@ -99,6 +99,8 @@ typedef struct _AFD_READ_REQUEST { typedef struct _AFD_LISTEN_REQUEST { LIST_ENTRY ListEntry; PAFDFCB Fcb; + PTDI_CONNECTION_INFORMATION RequestConnectionInfo; + IO_STATUS_BLOCK Iosb; } AFD_LISTEN_REQUEST, *PAFD_LISTEN_REQUEST; typedef struct IPSNMP_INFO { @@ -363,7 +365,7 @@ NTSTATUS TdiAssociateAddressFile( PFILE_OBJECT ConnectionObject); NTSTATUS TdiListen( - PFILE_OBJECT ConnectionObject, + PAFD_LISTEN_REQUEST Request, PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID CompletionContext); diff --git a/reactos/drivers/net/tcpip/include/address.h b/reactos/drivers/net/tcpip/include/address.h index d3febb8f9e5..c93b6772115 100644 --- a/reactos/drivers/net/tcpip/include/address.h +++ b/reactos/drivers/net/tcpip/include/address.h @@ -61,6 +61,9 @@ BOOLEAN AddrIsEqualIPv4( PIP_ADDRESS AddrBuildIPv4( IPv4_RAW_ADDRESS Address); +PIP_ADDRESS AddrCloneAddress( + PIP_ADDRESS Address); + PADDRESS_ENTRY AddrLocateADEv4( IPv4_RAW_ADDRESS Address); diff --git a/reactos/drivers/net/tcpip/include/checksum.h b/reactos/drivers/net/tcpip/include/checksum.h index e23c0a5a81d..2157c50f797 100644 --- a/reactos/drivers/net/tcpip/include/checksum.h +++ b/reactos/drivers/net/tcpip/include/checksum.h @@ -8,20 +8,39 @@ #define __CHECKSUM_H +ULONG ChecksumFold( + ULONG Sum); + ULONG ChecksumCompute( PVOID Data, UINT Count, ULONG Seed); -#define IPv4Checksum(Data, Count, Seed)(ChecksumCompute(Data, Count, Seed)) +unsigned int +csum_partial( + const unsigned char * buff, + int len, + unsigned int sum); + +#define IPv4Checksum(Data, Count, Seed)(~ChecksumFold(ChecksumCompute(Data, Count, Seed))) +#define TCPv4Checksum(Data, Count, Seed)(~ChecksumFold(csum_partial(Data, Count, Seed))) +//#define TCPv4Checksum(Data, Count, Seed)(~ChecksumFold(ChecksumCompute(Data, Count, Seed))) /* * Macro to check for a correct checksum - * BOOLEAN CorrectChecksum(PVOID Data, UINT Count) + * BOOLEAN IPv4CorrectChecksum(PVOID Data, UINT Count) */ -#define CorrectChecksum(Data, Count) \ +#define IPv4CorrectChecksum(Data, Count) \ (BOOLEAN)(IPv4Checksum(Data, Count, 0) == DH2N(0x0000FFFF)) -#endif /* __CHECKSUM_H */ +/* + * Macro to check for a correct checksum + * BOOLEAN TCPv4CorrectChecksum(PTCPv4_PSEUDO_HEADER TcpPseudoHeader, + * PVOID Data, UINT Count) + */ +#define TCPv4CorrectChecksum(TcpPseudoHeader, Data, Count) \ + (BOOLEAN)(TCPv4Checksum(Data, Count, \ + TCPv4Checksum(TcpPseudoHeader, sizeof(TCPv4_PSEUDO_HEADER), \ + 0)) == DH2N(0x0000FFFF)) -/* EOF */ +#endif /* __CHECKSUM_H */ diff --git a/reactos/drivers/net/tcpip/include/ip.h b/reactos/drivers/net/tcpip/include/ip.h index e7e6983ad90..81670ac507a 100644 --- a/reactos/drivers/net/tcpip/include/ip.h +++ b/reactos/drivers/net/tcpip/include/ip.h @@ -49,8 +49,9 @@ typedef struct IPv4_HEADER { IPv4_RAW_ADDRESS DstAddr; /* Destination Address */ } IPv4_HEADER, *PIPv4_HEADER; -#define IPv4_FRAGOFS_MASK 0x1FFF -#define IPv4_MF_MASK 0x2000 +#define IPv4_FRAGOFS_MASK 0x1FFF /* Fragment offset mask (host byte order) */ +#define IPv4_MF_MASK 0x2000 /* More fragments (host byte order) */ +#define IPv4_DF_MASK 0x4000 /* Don't fragment (host byte order) */ #define IPv4_MAX_HEADER_SIZE 60 /* Packet completion handler prototype */ @@ -60,7 +61,7 @@ typedef VOID (*PACKET_COMPLETION_ROUTINE)( NDIS_STATUS NdisStatus); /* Structure for an IP packet */ -typedef struct IP_PACKET { +typedef struct _IP_PACKET { DEFINE_TAG ULONG RefCount; /* Reference count for this object */ OBJECT_FREE_ROUTINE Free; /* Routine used to free resources for the object */ @@ -81,7 +82,7 @@ typedef struct IP_PACKET { /* Packet context */ -typedef struct PACKET_CONTEXT { +typedef struct _PACKET_CONTEXT { PACKET_COMPLETION_ROUTINE Complete; /* Transport level completion handler */ PVOID Context; /* Context information for handler */ PACKET_COMPLETION_ROUTINE DLComplete; /* Data link level completion handler. Also diff --git a/reactos/drivers/net/tcpip/include/tcp.h b/reactos/drivers/net/tcpip/include/tcp.h index edadae3a364..949dee73950 100644 --- a/reactos/drivers/net/tcpip/include/tcp.h +++ b/reactos/drivers/net/tcpip/include/tcp.h @@ -7,27 +7,26 @@ #ifndef __TCP_H #define __TCP_H - /* TCPv4 header structure */ -typedef struct TCP_HEADER { - USHORT SourcePort; /* Source port */ - USHORT DestPort; /* Destination port */ - USHORT SeqNum; /* Sequence number */ - USHORT AckNum; /* Acknowledgment number */ - UCHAR DataOfs; /* Data offset (leftmost 4 bits) */ - UCHAR Flags; /* Control bits (rightmost 6 bits) */ - USHORT Window; /* Maximum acceptable receive window */ - USHORT Checksum; /* Checksum of segment */ - USHORT Urgent; /* Pointer to urgent data */ -} __attribute__((packed)) TCP_HEADER, *PTCP_HEADER; +typedef struct TCPv4_HEADER { + USHORT SourcePort; /* Source port */ + USHORT DestinationPort; /* Destination port */ + ULONG SequenceNumber; /* Sequence number */ + ULONG AckNumber; /* Acknowledgement number */ + UCHAR DataOffset; /* Data offset; 32-bit words (leftmost 4 bits) */ + UCHAR Flags; /* Control bits (rightmost 6 bits) */ + USHORT Window; /* Maximum acceptable receive window */ + USHORT Checksum; /* Checksum of segment */ + USHORT Urgent; /* Pointer to urgent data */ +} __attribute__((packed)) TCPv4_HEADER, *PTCPv4_HEADER; /* TCPv4 header flags */ -#define TCP_URG 0x04 -#define TCP_ACK 0x08 -#define TCP_PSH 0x10 -#define TCP_RST 0x20 -#define TCP_SYN 0x40 -#define TCP_FIN 0x80 +#define TCP_URG 0x20 +#define TCP_ACK 0x10 +#define TCP_PSH 0x08 +#define TCP_RST 0x04 +#define TCP_SYN 0x02 +#define TCP_FIN 0x01 #define TCPOPT_END_OF_LIST 0x0 @@ -38,13 +37,13 @@ typedef struct TCP_HEADER { /* TCPv4 pseudo header */ -typedef struct TCP_PSEUDO_HEADER { - ULONG SourceAddress; /* Source address */ - ULONG DestAddress; /* Destination address */ - UCHAR Zero; /* Reserved */ - UCHAR Protocol; /* Protocol */ - USHORT TCPLength; /* Size of TCP segment */ -} __attribute__((packed)) TCP_PSEUDO_HEADER, *PTCP_PSEUDO_HEADER; +typedef struct TCPv4_PSEUDO_HEADER { + ULONG SourceAddress; /* Source address */ + ULONG DestinationAddress; /* Destination address */ + UCHAR Zero; /* Reserved */ + UCHAR Protocol; /* Protocol */ + USHORT TCPLength; /* Size of TCP segment */ +} __attribute__((packed)) TCPv4_PSEUDO_HEADER, *PTCPv4_PSEUDO_HEADER; /* Retransmission timeout constants */ @@ -72,6 +71,18 @@ typedef struct TCP_PSEUDO_HEADER { #define SRF_FIN TCP_FIN +PTCP_SEGMENT TCPCreateSegment( + PIP_PACKET IPPacket, + ULONG SequenceNumber, + ULONG SegmentLength); + +VOID TCPFreeSegment( + PTCP_SEGMENT Segment); + +VOID TCPAddSegment( + PCONNECTION_ENDPOINT Connection, + PTCP_SEGMENT Segment); + inline NTSTATUS TCPBuildSendRequest( PTCP_SEND_REQUEST *SendRequest, PDATAGRAM_SEND_REQUEST *DGSendRequest, @@ -113,5 +124,3 @@ NTSTATUS TCPShutdown( VOID); #endif /* __TCP_H */ - -/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/titypes.h b/reactos/drivers/net/tcpip/include/titypes.h index 88be6127689..b2cbfc3b90c 100644 --- a/reactos/drivers/net/tcpip/include/titypes.h +++ b/reactos/drivers/net/tcpip/include/titypes.h @@ -266,6 +266,8 @@ typedef struct _TCP_SEND_REQUEST { PVOID Context; /* Pointer to context information */ PVOID ProtocolContext; /* Protocol specific context */ ULONG Flags; /* Protocol specific flags */ + ULONG SequenceNumber; /* Sequence number (network byte order) */ + ULONG AckNumber; /* Acknowledgement number (network byte order) */ } TCP_SEND_REQUEST, *PTCP_SEND_REQUEST; #define InitializeTCPSendRequest( \ @@ -296,6 +298,15 @@ typedef enum { } CONNECTION_STATE, *PCONNECTION_STATE; +/* Structure for an TCP segment */ +typedef struct _TCP_SEGMENT { + LIST_ENTRY ListEntry; + PIP_PACKET IPPacket; /* Pointer to IP packet */ + ULONG SequenceNumber; /* Sequence number of first byte in segment */ + ULONG Length; /* Number of bytes in segment */ +} TCP_SEGMENT, *PTCP_SEGMENT; + + /* Transport connection context structure A.K.A. Transmission Control Block (TCB) in TCP terminology. The FileObject->FsContext2 field holds a pointer to this structure */ @@ -324,14 +335,21 @@ typedef struct _CONNECTION_ENDPOINT { ULONG SendISS; /* Initial send sequence number */ /* Receive sequence variables */ - ULONG RecvNext; /* Sequence number of last data block received */ - ULONG RecvWindow; /* Maximum allowed number of octets in a segment */ - ULONG RecvUrgentPointer; /* Sequence number of start of urgent data */ - ULONG RecvIRS; /* Initial receive sequence number */ + ULONG ReceiveNext; /* Sequence number of last data block received */ + ULONG ReceiveWindow; /* Maximum allowed number of octets in a segment */ + ULONG ReceiveUrgentPointer; /* Sequence number of start of urgent data */ + ULONG ReceiveIRS; /* Initial receive sequence number */ /* Statistics for computing the retransmission timeout */ ULONG TimestampSend; /* Timestamp when sending a segment */ ULONG TimestampAck; /* Timestamp when receiving acknowledgment */ + + /* Requests */ + PTDI_REQUEST ListenRequest; /* Queued listen request */ + + /* Queues */ + LIST_ENTRY ReceivedSegments; + } CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT; diff --git a/reactos/drivers/net/tcpip/makefile b/reactos/drivers/net/tcpip/makefile index 2a501cb50c9..1453a369a79 100644 --- a/reactos/drivers/net/tcpip/makefile +++ b/reactos/drivers/net/tcpip/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.15 2004/03/02 18:18:14 navaraf Exp $ +# $Id: makefile,v 1.16 2004/03/04 20:45:38 chorns Exp $ PATH_TO_TOP = ../../.. @@ -34,6 +34,7 @@ TCP_OBJECTS = transport/tcp/tcp.o transport/tcp/tcpcore.o \ transport/tcp/tcp_input.o transport/tcp/tcp_ipv4.o \ transport/tcp/tcp_output.o transport/tcp/tcp_timer.o UDP_OBJECTS = transport/udp/udp.o +ARCH_OBJECTS = tcpip/i386/checksum.o TARGET_OBJECTS = \ $(TCPIP_OBJECTS) \ @@ -42,7 +43,8 @@ TARGET_OBJECTS = \ $(DATAGRAM_OBJECTS) \ $(RAWIP_OBJECTS) \ $(TCP_OBJECTS) \ - $(UDP_OBJECTS) + $(UDP_OBJECTS) \ + $(ARCH_OBJECTS) include $(PATH_TO_TOP)/rules.mak diff --git a/reactos/drivers/net/tcpip/network/icmp.c b/reactos/drivers/net/tcpip/network/icmp.c index f45bb49300d..c5855cea471 100644 --- a/reactos/drivers/net/tcpip/network/icmp.c +++ b/reactos/drivers/net/tcpip/network/icmp.c @@ -182,7 +182,7 @@ VOID ICMPReceive( TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum)); /* Checksum ICMP header and data */ - if (!CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) { + if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) { TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n")); /* Discard packet */ return; diff --git a/reactos/drivers/net/tcpip/network/receive.c b/reactos/drivers/net/tcpip/network/receive.c index 4704ea7eb34..8e57493e7eb 100644 --- a/reactos/drivers/net/tcpip/network/receive.c +++ b/reactos/drivers/net/tcpip/network/receive.c @@ -552,7 +552,7 @@ VOID IPv4Receive( } /* Checksum IPv4 header */ - if (!CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) { + if (!IPv4CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) { TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n", WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum))); /* Discard packet */ diff --git a/reactos/drivers/net/tcpip/network/transmit.c b/reactos/drivers/net/tcpip/network/transmit.c index b650a547971..80e561fb222 100644 --- a/reactos/drivers/net/tcpip/network/transmit.c +++ b/reactos/drivers/net/tcpip/network/transmit.c @@ -104,13 +104,13 @@ NTSTATUS SendFragments( IPPacket, NCE, PathMTU)); IFC = ExAllocatePool(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT)); - if (!IFC) + if (IFC == NULL) return STATUS_INSUFFICIENT_RESOURCES; /* We allocate a buffer for a PathMTU sized packet and reuse it for all fragments */ Data = ExAllocatePool(NonPagedPool, MaxLLHeaderSize + PathMTU); - if (!IFC->Header) { + if (Data == NULL) { ExFreePool(IFC); return STATUS_INSUFFICIENT_RESOURCES; } @@ -118,7 +118,7 @@ NTSTATUS SendFragments( /* Allocate NDIS packet */ NdisAllocatePacket(&NdisStatus, &IFC->NdisPacket, GlobalPacketPool); if (NdisStatus != NDIS_STATUS_SUCCESS) { - //ExFreePool(Data); // RobD - why are we trying to free this here?, not allocated yet! + ExFreePool(Data); ExFreePool(IFC); return STATUS_INSUFFICIENT_RESOURCES; } diff --git a/reactos/drivers/net/tcpip/notes.txt b/reactos/drivers/net/tcpip/notes.txt new file mode 100644 index 00000000000..242d649039c --- /dev/null +++ b/reactos/drivers/net/tcpip/notes.txt @@ -0,0 +1,27 @@ + +RFC 791 - Internet Protocol +http://www.faqs.org/rfcs/rfc791.html + +RFC 792 - Internet Control Message Protocol +http://www.faqs.org/rfcs/rfc792.html + +RFC 793 - Transmission Control Protocol +http://www.faqs.org/rfcs/rfc793.html + +RFC 826 - Ethernet Address Resolution Protocol +http://www.faqs.org/rfcs/rfc826.html + +RFC 1122 - Requirements for Internet Hosts - Communication Layers +http://www.faqs.org/rfcs/rfc1122.html + +RFC 1123 - Requirements for Internet Hosts - Application and Support +http://www.faqs.org/rfcs/rfc1123.html + +RFC 2398 - Some Testing Tools for TCP Implementors +http://www.faqs.org/rfcs/rfc2398.html + +RFC 2525 - Known TCP Implementation Problems +http://www.faqs.org/rfcs/rfc2525.html + +RFC 2581 - TCP Congestion Control +http://www.faqs.org/rfcs/rfc2581.html \ No newline at end of file diff --git a/reactos/drivers/net/tcpip/tcpip/address.c b/reactos/drivers/net/tcpip/tcpip/address.c index 76f032fb9d2..252f6ddd387 100644 --- a/reactos/drivers/net/tcpip/tcpip/address.c +++ b/reactos/drivers/net/tcpip/tcpip/address.c @@ -289,7 +289,7 @@ BOOLEAN AddrIsEqualIPv4( /* * FUNCTION: Build an IPv4 style address * ARGUMENTS: - * Address = Raw IPv4 address + * Address = Raw IPv4 address (network byte order) * RETURNS: * Pointer to IP address structure, NULL if there was not enough free * non-paged memory @@ -300,7 +300,7 @@ PIP_ADDRESS AddrBuildIPv4( PIP_ADDRESS IPAddress; IPAddress = ExAllocatePool(NonPagedPool, sizeof(IP_ADDRESS)); - if (IPAddress) { + if (IPAddress != NULL) { IPAddress->RefCount = 1; IPAddress->Type = IP_ADDRESS_V4; IPAddress->Address.IPv4Address = Address; @@ -311,6 +311,29 @@ PIP_ADDRESS AddrBuildIPv4( } +/* + * FUNCTION: Clone an IP address + * ARGUMENTS: + * IPAddress = Pointer to IP address + * RETURNS: + * Pointer to new IP address structure, NULL if there was not enough free + * non-paged memory + */ +PIP_ADDRESS AddrCloneAddress( + PIP_ADDRESS Address) +{ + if (Address->Type == IP_ADDRESS_V4) + { + return AddrBuildIPv4(Address->Address.IPv4Address); + } + else + { + TI_DbgPrint(MIN_TRACE, ("Cannot clone IPv6 address.\n")); + return NULL; + } +} + + /* * FUNCTION: Locates and returns an address entry using IPv4 adress as argument * ARGUMENTS: diff --git a/reactos/drivers/net/tcpip/tcpip/checksum.c b/reactos/drivers/net/tcpip/tcpip/checksum.c index 72c08e8fa5d..d39a3a8830d 100644 --- a/reactos/drivers/net/tcpip/tcpip/checksum.c +++ b/reactos/drivers/net/tcpip/tcpip/checksum.c @@ -12,10 +12,22 @@ #include +ULONG ChecksumFold( + ULONG Sum) +{ + /* Fold 32-bit sum to 16 bits */ + while (Sum >> 16) + { + Sum = (Sum & 0xFFFF) + (Sum >> 16); + } + + return Sum; +} + ULONG ChecksumCompute( - PVOID Data, - UINT Count, - ULONG Seed) + PVOID Data, + UINT Count, + ULONG Seed) /* * FUNCTION: Calculate checksum of a buffer * ARGUMENTS: @@ -26,25 +38,20 @@ ULONG ChecksumCompute( * Checksum of buffer */ { - /* FIXME: This should be done in assembler */ + register ULONG Sum = Seed; - register ULONG Sum = Seed; - - while (Count > 1) { - Sum += *(PUSHORT)Data; - Count -= 2; - (ULONG_PTR)Data += 2; + while (Count > 1) + { + Sum += *(PUSHORT)Data; + Count -= 2; + (ULONG_PTR)Data += 2; } - /* Add left-over byte, if any */ - if (Count > 0) - Sum += *(PUCHAR)Data; + /* Add left-over byte, if any */ + if (Count > 0) + { + Sum += *(PUCHAR)Data; + } - /* Fold 32-bit sum to 16 bits */ - while (Sum >> 16) - Sum = (Sum & 0xFFFF) + (Sum >> 16); - - return ~Sum; + return Sum; } - -/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/dispatch.c b/reactos/drivers/net/tcpip/tcpip/dispatch.c index c3cfd162e6f..9f846f90b6a 100644 --- a/reactos/drivers/net/tcpip/tcpip/dispatch.c +++ b/reactos/drivers/net/tcpip/tcpip/dispatch.c @@ -529,8 +529,9 @@ NTSTATUS DispTdiListen( PTDI_REQUEST_KERNEL Parameters; PTRANSPORT_CONTEXT TranContext; PIO_STACK_LOCATION IrpSp; - TDI_REQUEST Request; + PTDI_REQUEST Request; NTSTATUS Status; + KIRQL OldIrql; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); @@ -539,28 +540,51 @@ NTSTATUS DispTdiListen( /* Get associated connection endpoint file object. Quit if none exists */ TranContext = IrpSp->FileObject->FsContext; - if (!TranContext) { - TI_DbgPrint(MID_TRACE, ("Bad transport context.\n")); - return STATUS_INVALID_CONNECTION; - } + if (TranContext == NULL) + { + TI_DbgPrint(MID_TRACE, ("Bad transport context.\n")); + return STATUS_INVALID_CONNECTION; + } Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext; - if (!Connection) { - TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n")); - return STATUS_INVALID_CONNECTION; - } + if (Connection == NULL) + { + TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n")); + return STATUS_INVALID_CONNECTION; + } Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters; - /* Initialize a connect request */ - Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext; - Request.RequestNotifyObject = DispDataRequestComplete; - Request.RequestContext = Irp; + /* Initialize a listen request */ + Request = (PTDI_REQUEST) ExAllocatePool(NonPagedPool, sizeof(TDI_REQUEST)); + if (Request == NULL) + { + return STATUS_NO_MEMORY; + } - Status = TCPListen( - &Request, - Parameters->RequestConnectionInformation, - Parameters->ReturnConnectionInformation); + Status = DispPrepareIrpForCancel(TranContext, Irp, NULL); + if (NT_SUCCESS(Status)) + { + Request->Handle.ConnectionContext = TranContext->Handle.ConnectionContext; + Request->RequestNotifyObject = DispDataRequestComplete; + Request->RequestContext = Irp; + + Status = TCPListen( + Request, + Parameters->RequestConnectionInformation, + Parameters->ReturnConnectionInformation); + if (Status != STATUS_PENDING) + { + IoAcquireCancelSpinLock(&OldIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(OldIrql); + } + } + + if (Status != STATUS_PENDING) + { + ExFreePool(Request); + } return Status; } diff --git a/reactos/drivers/net/tcpip/tcpip/fileobjs.c b/reactos/drivers/net/tcpip/tcpip/fileobjs.c index a46e1e5c845..0a80d685bcc 100644 --- a/reactos/drivers/net/tcpip/tcpip/fileobjs.c +++ b/reactos/drivers/net/tcpip/tcpip/fileobjs.c @@ -296,13 +296,13 @@ NTSTATUS FileOpenAddress( switch (Protocol) { case IPPROTO_TCP: /* FIXME: If specified port is 0, a port is chosen dynamically */ - AddrFile->Port = ((PTDI_ADDRESS_IP)Address->Address)->sin_port; + AddrFile->Port = Address->Address[0].Address[0].sin_port; AddrFile->Send = TCPSendDatagram; break; case IPPROTO_UDP: /* FIXME: If specified port is 0, a port is chosen dynamically */ - AddrFile->Port = ((PTDI_ADDRESS_IP)Address->Address)->sin_port; + AddrFile->Port = Address->Address[0].Address[0].sin_port; AddrFile->Send = UDPSendDatagram; break; @@ -449,6 +449,9 @@ NTSTATUS FileOpenConnection( /* Save client context pointer */ Connection->ClientContext = ClientContext; + /* Initialize receive queue */ + InitializeListHead(&Connection->ReceivedSegments); + /* Return connection endpoint file object */ Request->Handle.ConnectionContext = Connection; diff --git a/reactos/drivers/net/tcpip/tcpip/i386/checksum.S b/reactos/drivers/net/tcpip/tcpip/i386/checksum.S new file mode 100644 index 00000000000..468b85e7ad6 --- /dev/null +++ b/reactos/drivers/net/tcpip/tcpip/i386/checksum.S @@ -0,0 +1,249 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Pentium Pro/II routines: + * Alexander Kjeldaas + * Finn Arne Gangstad + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * Andi Kleen, add zeroing on error + * converted to pure assembler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ + +.text +.align 4 +.globl _csum_partial + +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ +_csum_partial: + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: unsigned char *buff + testl $3, %esi # Check alignment. + jz 2f # Jump if alignment is ok. + testl $1, %esi # Check alignment. + jz 10f # Jump if alignment is boundary of 2bytes. + + # buf is odd + dec %ecx + jl 8f + movzbl (%esi), %ebx + adcl %ebx, %eax + roll $8, %eax + inc %esi + testl $2, %esi + jz 2f +10: + subl $2, %ecx # Alignment uses up two bytes. + jae 1f # Jump if we had at least two bytes. + addl $2, %ecx # ecx was < 2. Deal with it. + jmp 4f +1: movw (%esi), %bx + addl $2, %esi + addw %bx, %ax + adcl $0, %eax +2: + movl %ecx, %edx + shrl $5, %ecx + jz 2f + testl %esi, %esi +1: movl (%esi), %ebx + adcl %ebx, %eax + movl 4(%esi), %ebx + adcl %ebx, %eax + movl 8(%esi), %ebx + adcl %ebx, %eax + movl 12(%esi), %ebx + adcl %ebx, %eax + movl 16(%esi), %ebx + adcl %ebx, %eax + movl 20(%esi), %ebx + adcl %ebx, %eax + movl 24(%esi), %ebx + adcl %ebx, %eax + movl 28(%esi), %ebx + adcl %ebx, %eax + lea 32(%esi), %esi + dec %ecx + jne 1b + adcl $0, %eax +2: movl %edx, %ecx + andl $0x1c, %edx + je 4f + shrl $2, %edx # This clears CF +3: adcl (%esi), %eax + lea 4(%esi), %esi + dec %edx + jne 3b + adcl $0, %eax +4: andl $3, %ecx + jz 7f + cmpl $2, %ecx + jb 5f + movw (%esi),%cx + leal 2(%esi),%esi + je 6f + shll $16,%ecx +5: movb (%esi),%cl +6: addl %ecx,%eax + adcl $0, %eax +7: + testl $1, 12(%esp) + jz 8f + roll $8, %eax +8: + popl %ebx + popl %esi + ret + +#else + +/* Version for PentiumII/PPro */ + +csum_partial: + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: const unsigned char *buf + + testl $3, %esi + jnz 25f +10: + movl %ecx, %edx + movl %ecx, %ebx + andl $0x7c, %ebx + shrl $7, %ecx + addl %ebx,%esi + shrl $2, %ebx + negl %ebx + lea 45f(%ebx,%ebx,2), %ebx + testl %esi, %esi + jmp *%ebx + + # Handle 2-byte-aligned regions +20: addw (%esi), %ax + lea 2(%esi), %esi + adcl $0, %eax + jmp 10b +25: + testl $1, %esi + jz 30f + # buf is odd + dec %ecx + jl 90f + movzbl (%esi), %ebx + addl %ebx, %eax + adcl $0, %eax + roll $8, %eax + inc %esi + testl $2, %esi + jz 10b + +30: subl $2, %ecx + ja 20b + je 32f + addl $2, %ecx + jz 80f + movzbl (%esi),%ebx # csumming 1 byte, 2-aligned + addl %ebx, %eax + adcl $0, %eax + jmp 80f +32: + addw (%esi), %ax # csumming 2 bytes, 2-aligned + adcl $0, %eax + jmp 80f + +40: + addl -128(%esi), %eax + adcl -124(%esi), %eax + adcl -120(%esi), %eax + adcl -116(%esi), %eax + adcl -112(%esi), %eax + adcl -108(%esi), %eax + adcl -104(%esi), %eax + adcl -100(%esi), %eax + adcl -96(%esi), %eax + adcl -92(%esi), %eax + adcl -88(%esi), %eax + adcl -84(%esi), %eax + adcl -80(%esi), %eax + adcl -76(%esi), %eax + adcl -72(%esi), %eax + adcl -68(%esi), %eax + adcl -64(%esi), %eax + adcl -60(%esi), %eax + adcl -56(%esi), %eax + adcl -52(%esi), %eax + adcl -48(%esi), %eax + adcl -44(%esi), %eax + adcl -40(%esi), %eax + adcl -36(%esi), %eax + adcl -32(%esi), %eax + adcl -28(%esi), %eax + adcl -24(%esi), %eax + adcl -20(%esi), %eax + adcl -16(%esi), %eax + adcl -12(%esi), %eax + adcl -8(%esi), %eax + adcl -4(%esi), %eax +45: + lea 128(%esi), %esi + adcl $0, %eax + dec %ecx + jge 40b + movl %edx, %ecx +50: andl $3, %ecx + jz 80f + + # Handle the last 1-3 bytes without jumping + notl %ecx # 1->2, 2->1, 3->0, higher bits are masked + movl $0xffffff,%ebx # by the shll and shrl instructions + shll $3,%ecx + shrl %cl,%ebx + andl -128(%esi),%ebx # esi is 4-aligned so should be ok + addl %ebx,%eax + adcl $0,%eax +80: + testl $1, 12(%esp) + jz 90f + roll $8, %eax +90: + popl %ebx + popl %esi + ret + +#endif diff --git a/reactos/drivers/net/tcpip/tcpip/routines.c b/reactos/drivers/net/tcpip/tcpip/routines.c index a45223ec1c4..64bf343bff4 100644 --- a/reactos/drivers/net/tcpip/tcpip/routines.c +++ b/reactos/drivers/net/tcpip/tcpip/routines.c @@ -480,6 +480,33 @@ UINT ResizePacket( #ifdef DBG +static VOID DisplayIPHeader( + PUCHAR Header, + UINT Length) +{ + /* FIXME: IPv4 only */ + PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header; + + DbgPrint("IPv4 header:\n"); + DbgPrint("VerIHL: 0x%x (version 0x%x, length %d 32-bit words)\n", + IPHeader->VerIHL, (IPHeader->VerIHL & 0xF0) >> 4, IPHeader->VerIHL & 0x0F); + DbgPrint(" Tos: %d\n", IPHeader->Tos); + DbgPrint(" TotalLength: %d\n", WN2H(IPHeader->TotalLength)); + DbgPrint(" Id: %d\n", WN2H(IPHeader->Id)); + DbgPrint(" FlagsFragOfs: 0x%x (offset 0x%x)\n", WN2H(IPHeader->FlagsFragOfs), WN2H(IPHeader->FlagsFragOfs) & IPv4_FRAGOFS_MASK); + if ((WN2H(IPHeader->FlagsFragOfs) & IPv4_DF_MASK) > 0) DbgPrint(" IPv4_DF - Don't fragment\n"); + if ((WN2H(IPHeader->FlagsFragOfs) & IPv4_MF_MASK) > 0) DbgPrint(" IPv4_MF - More fragments\n"); + DbgPrint(" Ttl: %d\n", IPHeader->Ttl); + DbgPrint(" Protocol: %d\n", IPHeader->Protocol); + DbgPrint(" Checksum: 0x%x\n", WN2H(IPHeader->Checksum)); + DbgPrint(" SrcAddr: %d.%d.%d.%d\n", + ((IPHeader->SrcAddr >> 0) & 0xFF), ((IPHeader->SrcAddr >> 8) & 0xFF), + ((IPHeader->SrcAddr >> 16) & 0xFF), ((IPHeader->SrcAddr >> 24) & 0xFF)); + DbgPrint(" DstAddr: %d.%d.%d.%d\n", + ((IPHeader->DstAddr >> 0) & 0xFF), ((IPHeader->DstAddr >> 8) & 0xFF), + ((IPHeader->DstAddr >> 16) & 0xFF), ((IPHeader->DstAddr >> 24) & 0xFF)); +} + VOID DisplayIPPacket( PIP_PACKET IPPacket) { @@ -488,6 +515,7 @@ VOID DisplayIPPacket( UINT Length; PNDIS_BUFFER Buffer; PNDIS_BUFFER NextBuffer; + PUCHAR CharBuffer; if ((DebugTraceLevel & (DEBUG_BUFFER | DEBUG_IP)) != (DEBUG_BUFFER | DEBUG_IP)) { return; @@ -528,6 +556,19 @@ VOID DisplayIPPacket( } DbgPrint("\n"); } + + if (IPPacket->NdisPacket) { + NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length); + Length -= MaxLLHeaderSize; + CharBuffer = ExAllocatePool(NonPagedPool, Length); + Length = CopyPacketToBuffer(CharBuffer, IPPacket->NdisPacket, MaxLLHeaderSize, Length); + DisplayIPHeader(CharBuffer, Length); + ExFreePool(CharBuffer); + } else { + CharBuffer = IPPacket->Header; + Length = IPPacket->ContigSize; + DisplayIPHeader(CharBuffer, Length); + } } @@ -537,32 +578,31 @@ static VOID DisplayTCPHeader( { /* FIXME: IPv4 only */ PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header; - PTCP_HEADER TCPHeader; + PTCPv4_HEADER TCPHeader; if (IPHeader->Protocol != IPPROTO_TCP) { DbgPrint("This is not a TCP datagram. Protocol is %d\n", IPHeader->Protocol); return; } - DbgPrint("VerIHL: 0x%x\n", IPHeader->VerIHL); - TCPHeader = (PTCP_HEADER)((PUCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4); + TCPHeader = (PTCPv4_HEADER)((PUCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4); DbgPrint("TCP header:\n"); DbgPrint(" SourcePort: %d\n", WN2H(TCPHeader->SourcePort)); - DbgPrint(" DestPort: %d\n", WN2H(TCPHeader->DestPort)); - DbgPrint(" SeqNum: %d\n", WN2H(TCPHeader->SeqNum)); - DbgPrint(" AckNum: %d\n", WN2H(TCPHeader->AckNum)); - DbgPrint(" DataOfs: %d (%d)\n", TCPHeader->DataOfs, TCPHeader->DataOfs & 0x0F); + DbgPrint(" DestinationPort: %d\n", WN2H(TCPHeader->DestinationPort)); + DbgPrint(" SequenceNumber: 0x%x\n", DN2H(TCPHeader->SequenceNumber)); + DbgPrint(" AckNumber: 0x%x\n", DN2H(TCPHeader->AckNumber)); + DbgPrint(" DataOffset: 0x%x (0x%x) 32-bit words\n", TCPHeader->DataOffset, TCPHeader->DataOffset >> 4); DbgPrint(" Flags: 0x%x (0x%x)\n", TCPHeader->Flags, TCPHeader->Flags & 0x3F); if ((TCPHeader->Flags & TCP_URG) > 0) DbgPrint(" TCP_URG - Urgent Pointer field significant\n"); - if ((TCPHeader->Flags & TCP_ACK) > 0) DbgPrint(" TCP_ACK - Acknowledgment field significant\n"); + if ((TCPHeader->Flags & TCP_ACK) > 0) DbgPrint(" TCP_ACK - Acknowledgement field significant\n"); if ((TCPHeader->Flags & TCP_PSH) > 0) DbgPrint(" TCP_PSH - Push Function\n"); if ((TCPHeader->Flags & TCP_RST) > 0) DbgPrint(" TCP_RST - Reset the connection\n"); if ((TCPHeader->Flags & TCP_SYN) > 0) DbgPrint(" TCP_SYN - Synchronize sequence numbers\n"); if ((TCPHeader->Flags & TCP_FIN) > 0) DbgPrint(" TCP_FIN - No more data from sender\n"); - DbgPrint(" Window: %d\n", WN2H(TCPHeader->Window)); - DbgPrint(" Checksum: %d\n", WN2H(TCPHeader->Checksum)); - DbgPrint(" Urgent: %d\n", WN2H(TCPHeader->Urgent)); + DbgPrint(" Window: 0x%x\n", WN2H(TCPHeader->Window)); + DbgPrint(" Checksum: 0x%x\n", WN2H(TCPHeader->Checksum)); + DbgPrint(" Urgent: 0x%x\n", WN2H(TCPHeader->Urgent)); } @@ -592,8 +632,9 @@ VOID DisplayTCPPacket( if (IPPacket->NdisPacket) { NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length); + Length -= MaxLLHeaderSize; Buffer = ExAllocatePool(NonPagedPool, Length); - Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, 0, Length); + Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, MaxLLHeaderSize, Length); DisplayTCPHeader(Buffer, Length); ExFreePool(Buffer); } else { diff --git a/reactos/drivers/net/tcpip/transport/tcp/tcp.c b/reactos/drivers/net/tcpip/transport/tcp/tcp.c index deacb35368b..2de651ec2b0 100644 --- a/reactos/drivers/net/tcpip/transport/tcp/tcp.c +++ b/reactos/drivers/net/tcpip/transport/tcp/tcp.c @@ -12,36 +12,159 @@ #include #include #include +#include #include static BOOLEAN TCPInitialized = FALSE; +static LONG IPIdentification = 0; +static NPAGED_LOOKASIDE_LIST TCPSegmentList; + + +PTCP_SEGMENT TCPCreateSegment( + PIP_PACKET IPPacket, + ULONG SequenceNumber, + ULONG SegmentLength) +/* + * FUNCTION: Creates a TCP segment object + * ARGUMENTS: + * IPPacket = Pointer to IP packet containing segment data + * SequenceNumber = Sequence number of first byte in the segment + * SegmentLength = Number of bytes in the segment + * RETURNS: + * Pointer to the created TCP segment. NULL if there was not enough free resources. + */ +{ + PTCP_SEGMENT Segment; + + ASSERT(IPPacket); + + Segment = ExAllocateFromNPagedLookasideList(&TCPSegmentList); + if (Segment == NULL) + return NULL; + + Segment->IPPacket = IPPacket; + Segment->SequenceNumber = SequenceNumber; + Segment->Length = SegmentLength; + + TI_DbgPrint(DEBUG_TCP, ("Created TCP segment (SequenceNumber %d, Length %d)\n", + Segment->SequenceNumber, Segment->Length)); + + return Segment; +} + + +VOID TCPFreeSegment( + PTCP_SEGMENT Segment) +/* + * FUNCTION: Frees a TCP segment object + * ARGUMENTS: + * Segment = Pointer to an TCP segment structure + */ +{ + ASSERT(Segment); + + ExFreeToNPagedLookasideList(&TCPSegmentList, Segment); +} + + +VOID TCPAddSegment( + PCONNECTION_ENDPOINT Connection, + PTCP_SEGMENT Segment) +/* + * FUNCTION: Adds a TCP segment object to the receive queue of a connection + * ARGUMENTS: + * Connection = Pointer to connection endpoint + * Segment = Pointer to TCP segment object + * RETURNS: + * Nothing. + */ +{ + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PTCP_SEGMENT Current; + + ASSERT(Connection); + ASSERT(Segment); + + /* FIXME: Handle sequence number wraparound */ + + /* If all segments arrive in-order then all segments will be put last in the + receive queue when they arrive */ + + if (IsListEmpty(&Connection->ReceivedSegments)) + { + /* This is the first segment received since the connection was created + or since all data is delivered to the client */ + InsertTailList(&Connection->ReceivedSegments, &Segment->ListEntry); + return; + } + + CurrentEntry = Connection->ReceivedSegments.Blink; + Current = CONTAINING_RECORD(CurrentEntry, TCP_SEGMENT, ListEntry); + if (Segment->SequenceNumber >= Current->SequenceNumber) + { + /* This segment has the highest sequence number yet received since the + connection was created */ + InsertTailList(&Connection->ReceivedSegments, &Segment->ListEntry); + return; + } + + + TI_DbgPrint(MIN_TRACE, ("FIXME: Cannot handle segments that arrive out-of-order.\n")); + +#if 0 + do + { + if (SequenceNumber + Length...) + { + } + + CurrentEntry = CurrentEntry->Blink; + Current = CONTAINING_RECORD(CurrentEntry, TCP_SEGMENT, ListEntry); + } + while (CurrentEntry != &Connection->ReceivedSegments); +#endif +} NTSTATUS TCPiAddHeaderIPv4( PDATAGRAM_SEND_REQUEST SendRequest, + PCONNECTION_ENDPOINT Connection, PIP_ADDRESS LocalAddress, USHORT LocalPort, - PIP_PACKET IPPacket) + PIP_PACKET IPPacket, + PTCPv4_HEADER *pTcpHeader, + PULONG pTcpHeaderLength) /* * FUNCTION: Adds an IPv4 and TCP header to an IP packet * ARGUMENTS: - * SendRequest = Pointer to send request - * LocalAddress = Pointer to our local address - * LocalPort = The port we send this segment from - * IPPacket = Pointer to IP packet + * SendRequest = Pointer to send request + * Connection = Pointer to connection endpoint + * LocalAddress = Pointer to our local address + * LocalPort = The port we send this segment from + * IPPacket = Pointer to IP packet + * TcpHeader = Address of pointer to TCPv4 header (out) + * pTcpHeaderLength = Address of buffer for length of TCP header * RETURNS: * Status of operation */ { PIPv4_HEADER IPHeader; - PTCP_HEADER TCPHeader; + PTCPv4_HEADER TCPHeader; PVOID Header; ULONG BufferSize; NDIS_STATUS NdisStatus; PNDIS_BUFFER HeaderBuffer; + PTCP_SEND_REQUEST TcpSendRequest = (PTCP_SEND_REQUEST)SendRequest->Context; - BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(TCP_HEADER); + ASSERT(SendRequest); + ASSERT(Connection); + ASSERT(LocalAddress); + ASSERT(IPPacket); + ASSERT(pTcpHeader); + + BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(TCPv4_HEADER); Header = ExAllocatePool(NonPagedPool, BufferSize); if (!Header) return STATUS_INSUFFICIENT_RESOURCES; @@ -61,7 +184,8 @@ NTSTATUS TCPiAddHeaderIPv4( /* Chain header at front of NDIS packet */ NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer); - + + IPPacket->ContigSize = BufferSize; IPPacket->Header = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize); IPPacket->HeaderSize = 20; @@ -74,7 +198,7 @@ NTSTATUS TCPiAddHeaderIPv4( /* Length of header and data */ IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize); /* Identification */ - IPHeader->Id = 0; + IPHeader->Id = WH2N((USHORT)InterlockedIncrement(&IPIdentification)); /* One fragment at offset 0 */ IPHeader->FlagsFragOfs = 0; /* Time-to-Live is 128 */ @@ -89,18 +213,23 @@ NTSTATUS TCPiAddHeaderIPv4( IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address; /* Build TCP header */ - TCPHeader = (PTCP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER)); + TCPHeader = (PTCPv4_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER)); /* Port values are already big-endian values */ - TCPHeader->SourcePort = LocalPort; - TCPHeader->DestPort = SendRequest->RemotePort; - TCPHeader->SeqNum = 0; - TCPHeader->AckNum = 0; - TCPHeader->DataOfs = 0; - TCPHeader->Flags = SendRequest->Flags; - TCPHeader->Window = 0; + TCPHeader->SourcePort = LocalPort; + TCPHeader->DestinationPort = SendRequest->RemotePort; + /* TcpSendRequest->SequenceNumber is already a big-endian value */ + TCPHeader->SequenceNumber = TcpSendRequest->SequenceNumber; + /* TcpSendRequest->AckNumber is already a big-endian value */ + TCPHeader->AckNumber = ((SendRequest->Flags & SRF_ACK) > 0) ? TcpSendRequest->AckNumber : 0; + TCPHeader->DataOffset = (sizeof(TCPv4_HEADER) / 4) << 4; + TCPHeader->Flags = SendRequest->Flags; + TCPHeader->Window = 0; /* FIXME: Calculate TCP checksum and put it in TCP header */ - TCPHeader->Checksum = 0; - TCPHeader->Urgent = 0; + TCPHeader->Checksum = 0; + TCPHeader->Urgent = 0; + + *pTcpHeader = TCPHeader; + *pTcpHeaderLength = sizeof(TCPv4_HEADER); return STATUS_SUCCESS; } @@ -121,7 +250,7 @@ NTSTATUS TCPiBuildPacket( * RETURNS: * Status of operation * NOTES: - * The ProcotolContext field in the send request structure (pointed to + * The Context field in the send request structure (pointed to * by the Context field) contains a pointer to the CONNECTION_ENDPOINT * structure for the connection */ @@ -129,19 +258,32 @@ NTSTATUS TCPiBuildPacket( NTSTATUS Status; PIP_PACKET Packet; NDIS_STATUS NdisStatus; - PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context; + PDATAGRAM_SEND_REQUEST SendRequest; + PCONNECTION_ENDPOINT Connection; + ULONG Checksum; + TCPv4_PSEUDO_HEADER TcpPseudoHeader; + PTCPv4_HEADER TcpHeader; + ULONG TcpHeaderLength; + + ASSERT(LocalAddress); + ASSERT(IPPacket); TI_DbgPrint(MAX_TRACE, ("Called.\n")); + SendRequest = (PDATAGRAM_SEND_REQUEST)Context; + ASSERT(SendRequest); + Connection = (PCONNECTION_ENDPOINT)SendRequest->Context; + ASSERT(Connection); + /* Prepare packet */ - /* FIXME: Assumes IPv4*/ + /* FIXME: Assumes IPv4 */ Packet = IPCreatePacket(IP_ADDRESS_V4); - if (!Packet) + if (Packet == NULL) return STATUS_INSUFFICIENT_RESOURCES; Packet->TotalSize = sizeof(IPv4_HEADER) + - sizeof(TCP_HEADER) + + sizeof(TCPv4_HEADER) + SendRequest->BufferSize; /* Allocate NDIS packet */ @@ -153,7 +295,8 @@ NTSTATUS TCPiBuildPacket( switch (SendRequest->RemoteAddress->Type) { case IP_ADDRESS_V4: - Status = TCPiAddHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet); + Status = TCPiAddHeaderIPv4(SendRequest, Connection, LocalAddress, + LocalPort, Packet, &TcpHeader, &TcpHeaderLength); break; case IP_ADDRESS_V6: /* FIXME: Support IPv6 */ @@ -169,10 +312,40 @@ NTSTATUS TCPiBuildPacket( return Status; } - /* Chain data after header */ - NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer); + /* Build pseudo TCP header which is used to prevent misrouted segments */ + TcpPseudoHeader.SourceAddress = LocalAddress->Address.IPv4Address; + TcpPseudoHeader.DestinationAddress = SendRequest->RemoteAddress->Address.IPv4Address; + TcpPseudoHeader.Zero = 0; + TcpPseudoHeader.Protocol = IPPROTO_TCP; + /* Length of TCP header and segment data */ + TcpPseudoHeader.TCPLength = WH2N(TcpHeaderLength + SendRequest->BufferSize); + Checksum = TCPv4Checksum((PUCHAR)&TcpPseudoHeader, sizeof(TCPv4_PSEUDO_HEADER), 0); - //DISPLAY_IP_PACKET(Packet); + /* Add checksum for TCP header */ + Checksum = TCPv4Checksum((PUCHAR)TcpHeader, TcpHeaderLength, ~Checksum); + + /* Chain data after header if it exists */ + if (SendRequest->Buffer != NULL) + { + PVOID Data; + UINT Size; + PNDIS_BUFFER NdisBuffer = SendRequest->Buffer; + NdisChainBufferAtBack(Packet->NdisPacket, NdisBuffer); + /* Add checksum for segment data */ + /* FIXME: Verify that there is no problem for chained buffers with an odd length */ + while (NdisBuffer != NULL) + { + NdisQueryBuffer(NdisBuffer, &Data, &Size); + DbgPrint("Checksum7:(%d bytes)\n", Size); + Checksum = TCPv4Checksum(Data, Size, ~Checksum); + NdisGetNextBuffer(NdisBuffer, &NdisBuffer); + } + } + + TcpHeader->Checksum = Checksum; + DbgPrint("Checksum8: (0x%x)\n", Checksum); + + DISPLAY_TCP_PACKET(Packet); *IPPacket = Packet; @@ -196,14 +369,19 @@ VOID TCPiSendRequestComplete( PVOID CompleteContext; PTCP_SEND_REQUEST SendRequest = (PTCP_SEND_REQUEST)Context; + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + Complete = SendRequest->Complete; CompleteContext = SendRequest->Context; ExFreePool(SendRequest); - TI_DbgPrint(MAX_TRACE, ("Calling completion routine.\n")); + if (Complete != NULL) + { + TI_DbgPrint(MAX_TRACE, ("Calling completion routine.\n")); - /* Call upper level completion routine */ - (*Complete)(CompleteContext, Status, Count); + /* Call upper level completion routine */ + (*Complete)(CompleteContext, Status, Count); + } TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); } @@ -237,7 +415,7 @@ inline NTSTATUS TCPBuildSendRequest( * Connection = Connection endpoint * Complete = Completion routine * Context = Pointer to context information - * Buffer = Pointer to NDIS buffer to send + * Buffer = Pointer to NDIS buffer to send (optional) * BufferSize = Size of Buffer * Flags = Protocol specific flags * RETURNS: @@ -247,6 +425,9 @@ inline NTSTATUS TCPBuildSendRequest( PDATAGRAM_SEND_REQUEST DGSendReq; NTSTATUS Status; + ASSERT(SendRequest); + ASSERT(Connection); + Status = BuildTCPSendRequest( SendRequest, Complete, @@ -261,7 +442,8 @@ inline NTSTATUS TCPBuildSendRequest( Connection->RemotePort, /* Port of remote peer */ Buffer, /* Buffer */ BufferSize, /* Size of buffer */ - TCPiSendRequestComplete, /* Completion function */ + (DATAGRAM_COMPLETION_ROUTINE) + TCPiSendRequestComplete, /* Completion function */ *SendRequest, /* Context for completion function */ TCPiBuildPacket, /* Packet build function */ Flags); /* Protocol specific flags */ @@ -288,9 +470,9 @@ inline NTSTATUS TCPBuildAndTransmitSendRequest( * FUNCTION: Allocates and intializes a TCP send request * ARGUMENTS: * Connection = Connection endpoint - * Complete = Completion routine + * Complete = Completion routine (optional) * Context = Pointer to context information - * Buffer = Pointer to NDIS buffer to send + * Buffer = Pointer to NDIS buffer to send (optional) * BufferSize = Size of Buffer * Flags = Protocol specific flags * RETURNS: @@ -301,6 +483,10 @@ inline NTSTATUS TCPBuildAndTransmitSendRequest( PTCP_SEND_REQUEST TCPSendRequest; NTSTATUS Status; + ASSERT(Connection); + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + Status = TCPBuildSendRequest( &TCPSendRequest, &DGSendRequest, @@ -326,6 +512,67 @@ inline NTSTATUS TCPBuildAndTransmitSendRequest( } +inline NTSTATUS TCPBuildAndTransmitSendRequest2( + PCONNECTION_ENDPOINT Connection, + DATAGRAM_COMPLETION_ROUTINE Complete, + PVOID Context, + PNDIS_BUFFER Buffer, + DWORD BufferSize, + ULONG Flags, + ULONG SequenceNumber, + ULONG AckNumber) +/* + * FUNCTION: Allocates and intializes a TCP send request + * ARGUMENTS: + * Connection = Connection endpoint + * Complete = Completion routine (optional) + * Context = Pointer to context information + * Buffer = Pointer to NDIS buffer to send + * BufferSize = Size of Buffer + * Flags = Protocol specific flags + * SequenceNumber = Sequence number (host byte order) + * AckNumber = Acknowledgement number (host byte order) + * RETURNS: + * Status of operation + */ +{ + PDATAGRAM_SEND_REQUEST DGSendRequest; + PTCP_SEND_REQUEST TCPSendRequest; + NTSTATUS Status; + + ASSERT(Connection); + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + Status = TCPBuildSendRequest( + &TCPSendRequest, + &DGSendRequest, + Connection, /* Connection endpoint */ + Complete, /* Completion routine */ + Context, /* Completion routine context */ + Buffer, /* Buffer */ + BufferSize, /* Size of buffer */ + Flags); /* Protocol specific flags */ + if (!NT_SUCCESS(Status)) + return Status; + + /* Set extra information and convert to network byte order if necessary */ + TCPSendRequest->SequenceNumber = DH2N(SequenceNumber); + TCPSendRequest->AckNumber = DH2N(AckNumber); + + Status = DGTransmit( + Connection->AddressFile, + DGSendRequest); + if (!NT_SUCCESS(Status)) { + ExFreePool(DGSendRequest); + ExFreePool(TCPSendRequest); + return Status; + } + + return STATUS_SUCCESS; +} + + NTSTATUS TCPConnect( PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo, @@ -335,7 +582,7 @@ NTSTATUS TCPConnect( * ARGUMENTS: * Request = Pointer to TDI request * ConnInfo = Pointer to connection information - * ReturnInfo = Pointer to structure for return information + * ReturnInfo = Pointer to structure for return information (optional) * RETURNS: * Status of operation * NOTES: @@ -353,6 +600,9 @@ NTSTATUS TCPConnect( PVOID DataBuffer; ULONG Size; + ASSERT(Request); + ASSERT(ConnInfo); + TI_DbgPrint(MID_TRACE, ("Called.\n")); Connection = Request->Handle.ConnectionContext; @@ -427,7 +677,7 @@ NTSTATUS TCPListen( * ARGUMENTS: * Request = Pointer to TDI request * ConnInfo = Pointer to connection information - * ReturnInfo = Pointer to structure for return information + * ReturnInfo = Pointer to structure for return information (optional) * RETURNS: * Status of operation * NOTES: @@ -441,6 +691,9 @@ NTSTATUS TCPListen( NTSTATUS Status; KIRQL OldIrql; + ASSERT(Request); + ASSERT(ConnInfo); + TI_DbgPrint(MID_TRACE, ("Called.\n")); Connection = Request->Handle.ConnectionContext; @@ -453,8 +706,9 @@ NTSTATUS TCPListen( return STATUS_UNSUCCESSFUL; } - Connection->LocalAddress = Connection->AddressFile->ADE->Address; - Connection->LocalPort = Connection->AddressFile->Port; + Connection->LocalAddress = Connection->AddressFile->ADE->Address; + Connection->LocalPort = Connection->AddressFile->Port; + Connection->ListenRequest = Request; TI_DbgPrint(MIN_TRACE, ("Connection->LocalAddress (%s).\n", A2S(Connection->LocalAddress))); TI_DbgPrint(MIN_TRACE, ("Connection->LocalPort (%d).\n", Connection->LocalPort)); @@ -488,22 +742,510 @@ NTSTATUS TCPSendDatagram( * Status of operation */ { + ASSERT(Request); + ASSERT(ConnInfo); + ASSERT(Buffer); + return STATUS_SUCCESS; } -static VOID TCPiReceive( +static inline ULONG TCPiSelectISS( + PCONNECTION_ENDPOINT Connection) +{ + ASSERT(Connection); + + TI_DbgPrint(MIN_TRACE, ("Select ISS.\n")); + return 0x10000; +} + + +static inline VOID TCPiReceiveListen( PADDRESS_FILE AddrFile, PIP_PACKET IPPacket, - PTCP_HEADER TCPHeader) + PTCPv4_HEADER TCPHeader) +{ + ASSERT(AddrFile); + ASSERT(IPPacket); + ASSERT(TCPHeader); + + /* FIXME: Protect AddrFile->Connection */ + + if ((TCPHeader->Flags & TCP_RST) > 0) + { + /* Discard */ + TI_DbgPrint(DEBUG_TCP, ("Discard.\n")); + return; + } + + if ((TCPHeader->Flags & TCP_ACK) > 0) + { + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + if ((TCPHeader->Flags & TCP_SYN) > 0) + { + PCONNECTION_ENDPOINT Connection = AddrFile->Connection; + register UCHAR DelayedControls; + register NTSTATUS Status; + + /* FIXME: If the SEG.PRC is greater than the TCB.PRC then if allowed by + the user and the system set TCB.PRC<-SEG.PRC, if not allowed + send a reset and return. */ + if (FALSE) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + /* Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other + control or text should be queued for processing later. ISS + should be selected and a SYN segment sent of the form: + + + + SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection + state should be changed to SYN-RECEIVED. Note that any other + incoming control or data (combined with SYN) will be processed + in the SYN-RECEIVED state, but processing of SYN and ACK should + not be repeated. If the listen was not fully specified (i.e., + the foreign socket was not fully specified), then the + unspecified fields should be filled in now. + */ + TI_DbgPrint(DEBUG_TCP, ("Go to ctSynReceived connection state.\n")); + + Connection->RemotePort = TCPHeader->SourcePort; + /* FIXME: IPv4 only */ + Connection->RemoteAddress = AddrCloneAddress(&IPPacket->SrcAddr); + if (Connection->RemoteAddress == NULL) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + Connection->ReceiveNext = DN2H(TCPHeader->SequenceNumber) + 1; + Connection->ReceiveIRS = DN2H(TCPHeader->SequenceNumber); + Connection->State = ctSynReceived; + + Connection->SendISS = TCPiSelectISS(Connection); + Connection->SendNext = Connection->SendISS + 1; + Connection->SendUnacknowledged = Connection->SendISS; + + DelayedControls = TCPHeader->Flags & (~(TCP_SYN | TCP_ACK)); + if (DelayedControls > 0) + { + TI_DbgPrint(MIN_TRACE, ("FIXME: Queue controls (0x%x) for later processing.\n", DelayedControls)); + } + + TI_DbgPrint(MIN_TRACE, ("IPPacket->HeaderSize: %d\n", IPPacket->HeaderSize)); + TI_DbgPrint(MIN_TRACE, ("TCPHeader->DataOffset: %d\n", TCPHeader->DataOffset)); + TI_DbgPrint(MIN_TRACE, ("IPPacket->TotalSize: %d\n", IPPacket->TotalSize)); + + if (IPPacket->HeaderSize + (TCPHeader->DataOffset & 0x0F) > IPPacket->TotalSize) + { + TI_DbgPrint(MIN_TRACE, ("FIXME: Queue segment data (%d bytes) for later processing.\n", + (IPPacket->HeaderSize + (TCPHeader->DataOffset & 0x0F)) - IPPacket->TotalSize)); + } + + /* Issue SYN/ACK segment */ + Status = TCPBuildAndTransmitSendRequest2( + Connection, /* Connection endpoint */ + NULL, /* Completion routine */ + NULL, /* Completion routine context */ + NULL, /* Buffer */ + 0, /* Size of buffer */ + SRF_SYN | SRF_ACK, /* Protocol specific flags */ + Connection->SendISS, /* Sequence number */ + Connection->ReceiveNext); /* Acknowledgement number */ + if (!NT_SUCCESS(Status)) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + ASSERT(Connection->ListenRequest != NULL); + + TI_DbgPrint(DEBUG_TCP, ("Completing listen request at %p.\n", Connection->ListenRequest)); + + /* Complete the listen request */ + (*((DATAGRAM_COMPLETION_ROUTINE)Connection->ListenRequest->RequestNotifyObject))( + Connection->ListenRequest->RequestContext, + STATUS_SUCCESS, + 0); + return; + } + + /* Discard the segment as it is invalid */ + TI_DbgPrint(DEBUG_TCP, ("Discard.\n")); +} + + +static inline VOID TCPiReceiveSynSent( + PADDRESS_FILE AddrFile, + PIP_PACKET IPPacket, + PTCPv4_HEADER TCPHeader) +{ + ASSERT(AddrFile); + ASSERT(IPPacket); + ASSERT(TCPHeader); + + /* FIXME: Protect AddrFile->Connection */ + + if ((TCPHeader->Flags & TCP_ACK) > 0) + { + /* FIXME: If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless + the RST bit is set, if so drop the segment and return) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + /* FIXME: If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. */ + + if ((TCPHeader->Flags & TCP_RST) > 0) + { + if (TRUE /* ACK is acceptable */) + { + AddrFile->Connection->State = ctClosed; + /* FIXME: Signal client */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Signal client.\n")); + } + else + { + /* Discard segment */ + TI_DbgPrint(DEBUG_TCP, ("Discard.\n")); + } + return; + } + + /* FIXME: If the security/compartment in the segment does not exactly + match the security/compartment in the TCB */ + if (FALSE) + { + if ((TCPHeader->Flags & TCP_ACK) > 0) + { + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + } + else + { + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + } + return; + } + + if ((TCPHeader->Flags & TCP_ACK) > 0) + { + /* FIXME: If the precedence in the segment does not match the precedence in the TCB */ + if (FALSE) + { + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + else + { + /* FIXME: If the precedence in the segment is higher than the precedence + in the TCB then if allowed by the user and the system raise + the precedence in the TCB to that in the segment, if not + allowed to raise the prec then send a reset. */ + if (FALSE) + { + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + else + { + /* Continue */ + } + } + TI_DbgPrint(MIN_TRACE, ("?.\n")); + return; /* ??? */ + } + + /* The ACK is ok, or there is no ACK, and it the segment did not contain a RST */ + + if ((TCPHeader->Flags & TCP_SYN) > 0) + { + /* FIXME: The security/compartment and precedence are acceptable */ + if (TRUE) + { + PCONNECTION_ENDPOINT Connection = AddrFile->Connection; + register NTSTATUS Status; + + /* FIXME: RCV.NXT is set to SEG.SEQ+1, IRS is set to + SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there + is an ACK), and any segments on the retransmission queue which + are thereby acknowledged should be removed. + + If SND.UNA > ISS (our SYN has been ACKed), change the connection + state to ESTABLISHED, form an ACK segment + + + + Data or controls which were queued for + transmission may be included. If there are other controls or + text in the segment then continue processing at the sixth step + below where the URG bit is checked, otherwise return. + + Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + + + + and send it. If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. */ + + Connection->ReceiveNext = DN2H(TCPHeader->SequenceNumber) + 1; + Connection->ReceiveIRS = DN2H(TCPHeader->SequenceNumber); + + if ((TCPHeader->Flags & TCP_ACK) > 0) + { + /* FIXME: Remove any outstanding segments on the retransmission queue that is acknowledged by this */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Maybe remove outstanding segments on the retransmission queue.\n")); + Connection->SendUnacknowledged = TCPHeader->AckNumber; + } + + if (Connection->SendUnacknowledged > Connection->SendISS) + { + TI_DbgPrint(DEBUG_TCP, ("Go to ctEstablished connection state.\n")); + Connection->State = ctEstablished; + + TI_DbgPrint(MIN_TRACE, ("FIXME: Controls or segment data queued for transmission may be sent.\n")); + + /* Issue ACK segment */ + Status = TCPBuildAndTransmitSendRequest2( + Connection, /* Connection endpoint */ + NULL, /* Completion routine */ + NULL, /* Completion routine context */ + NULL, /* Buffer */ + 0, /* Size of buffer */ + SRF_ACK, /* Protocol specific flags */ + Connection->SendNext, /* Sequence number */ + Connection->ReceiveNext); /* Acknowledgement number */ + if (!NT_SUCCESS(Status)) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + } + else + { + TI_DbgPrint(MIN_TRACE, ("Go to ctSynReceived connection state.\n")); + Connection->State = ctSynReceived; + + TI_DbgPrint(MIN_TRACE, ("FIXME: Controls or segment data queued for transmission may be sent.\n")); + + /* Issue SYN/ACK segment */ + Status = TCPBuildAndTransmitSendRequest2( + Connection, /* Connection endpoint */ + NULL, /* Completion routine */ + NULL, /* Completion routine context */ + NULL, /* Buffer */ + 0, /* Size of buffer */ + SRF_SYN | SRF_ACK, /* Protocol specific flags */ + Connection->SendISS, /* Sequence number */ + Connection->ReceiveNext); /* Acknowledgement number */ + if (!NT_SUCCESS(Status)) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + } + } + else + { + /* FIXME: What happens here? */ + } + } + + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); +} + +/* + * Returns TRUE if processing should be continued, FALSE if not + */ +static inline BOOLEAN TCPiReceiveSynReceived( + PADDRESS_FILE AddrFile, + PIP_PACKET IPPacket, + PTCPv4_HEADER TCPHeader) +{ + PCONNECTION_ENDPOINT Connection = AddrFile->Connection; + + ASSERT(AddrFile); + ASSERT(IPPacket); + ASSERT(TCPHeader); + + /* FIXME: Protect AddrFile->Connection */ + + /* FIXME: If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state + and continue processing. + + If the segment acknowledgment is not acceptable, form a + reset segment, + + + + and send it. */ + + if ((Connection->SendUnacknowledged <= DN2H(TCPHeader->AckNumber)) + && (DN2H(TCPHeader->AckNumber) <= Connection->SendNext)) + { + Connection->State = ctEstablished; + TI_DbgPrint(DEBUG_TCP, ("Go to ctEstablished connection state.\n")); + return TRUE; + } + + /* FIXME: Send RST (if no RST) + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + + return FALSE; +} + + +static inline VOID TCPiReceiveData( + PADDRESS_FILE AddrFile, + PIP_PACKET IPPacket, + PTCPv4_HEADER TCPHeader, + ULONG Payload) +{ + PCONNECTION_ENDPOINT Connection = AddrFile->Connection; + PTCP_SEGMENT Segment; + NTSTATUS Status; + ULONG Acknowledged; + + ASSERT(AddrFile); + ASSERT(IPPacket); + ASSERT(TCPHeader); + + TI_DbgPrint(DEBUG_TCP, ("Called (Payload %d bytes).\n", Payload)); + + /* FIXME: Protect AddrFile->Connection */ + + /* FIXME: Once in the ESTABLISHED state, it is possible to deliver segment + text to user RECEIVE buffers. Text from segments can be moved + into buffers until either the buffer is full or the segment is + empty. If the segment empties and carries an PUSH flag, then + the user is informed, when the buffer is returned, that a PUSH + has been received. + + When the TCP takes responsibility for delivering the data to the + user it must also acknowledge the receipt of the data. + + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. + + Please note the window management suggestions in section 3.7. + + Send an acknowledgment of the form: + + + + This acknowledgment should be piggybacked on a segment being + transmitted if possible without incurring undue delay. */ + + /* FIXME: If the segment is not expected, drop the segment + + A segment is judged to occupy a portion of valid receive sequence + space if + + RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + + or + + RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND + */ + + Segment = TCPCreateSegment(IPPacket, + DN2H(TCPHeader->SequenceNumber), + Payload); + if (Segment == NULL) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + TCPAddSegment(Connection, Segment /*, &Acknowledged */); + + //Connection->ReceiveNext += ; + + /* Issue ACK segment */ + Status = TCPBuildAndTransmitSendRequest2( + Connection, /* Connection endpoint */ + NULL, /* Completion routine */ + NULL, /* Completion routine context */ + NULL, /* Buffer */ + 0, /* Size of buffer */ + SRF_ACK, /* Protocol specific flags */ + Connection->SendNext, /* Sequence number */ + Connection->ReceiveNext); /* Acknowledgement number */ + if (!NT_SUCCESS(Status)) + { + /* FIXME: Send RST (if no RST) + * + */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); + return; + } + + if ((TCPHeader->Flags & TCP_PSH) > 0) + { + TI_DbgPrint(MIN_TRACE, ("FIXME: Handle PUSH flag.\n")); + } + + TI_DbgPrint(MAX_TRACE, ("\n")); +} + + +static inline VOID TCPiReceive( + PADDRESS_FILE AddrFile, + PIP_PACKET IPPacket, + PTCPv4_HEADER TCPHeader, + ULONG Payload) { register CONNECTION_STATE State; + ASSERT(AddrFile); + ASSERT(IPPacket); + ASSERT(TCPHeader); + if (AddrFile->Connection == NULL || AddrFile->Connection->State == ctClosed) { if ((TCPHeader->Flags & TCP_RST) == 0) { - /* FIXME: Send RST + /* FIXME: Send RST (if no RST) * If the ACK bit is off, sequence number zero is used, * * @@ -514,181 +1256,19 @@ static VOID TCPiReceive( */ TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); } + TI_DbgPrint(DEBUG_TCP, ("Discard.\n")); return; } if (AddrFile->Connection->State == ctListen) { - if ((TCPHeader->Flags & TCP_RST) > 0) - { - /* Discard */ - return; - } - - if ((TCPHeader->Flags & TCP_ACK) > 0) - { - /* FIXME: Send RST - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - return; - } - - if ((TCPHeader->Flags & TCP_SYN) > 0) - { - /* FIXME: If the SEG.PRC is greater than the TCB.PRC then if allowed by - the user and the system set TCB.PRC<-SEG.PRC, if not allowed - send a reset and return. */ - if (FALSE) - { - /* FIXME: Send RST - * - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - return; - } - - /* Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other - control or text should be queued for processing later. ISS - should be selected and a SYN segment sent of the form: - - - - SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection - state should be changed to SYN-RECEIVED. Note that any other - incoming control or data (combined with SYN) will be processed - in the SYN-RECEIVED state, but processing of SYN and ACK should - not be repeated. If the listen was not fully specified (i.e., - the foreign socket was not fully specified), then the - unspecified fields should be filled in now. - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Go to ctSynReceived connection state.\n")); - return; - } - - /* Discard the segment as it is invalid */ + TCPiReceiveListen(AddrFile, IPPacket, TCPHeader); return; } if (AddrFile->Connection->State == ctSynSent) { - if ((TCPHeader->Flags & TCP_ACK) > 0) - { - /* FIXME: If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless - the RST bit is set, if so drop the segment and return) - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - return; - } - - /* FIXME: If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. */ - - if ((TCPHeader->Flags & TCP_RST) > 0) - { - if (TRUE /* ACK is acceptable */) - { - AddrFile->Connection->State = ctClosed; - /* FIXME: Signal client */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Signal client.\n")); - } - else - { - /* Discard segment */ - } - return; - } - - /* FIXME: If the security/compartment in the segment does not exactly - match the security/compartment in the TCB */ - if (FALSE) - { - if ((TCPHeader->Flags & TCP_ACK) > 0) - { - /* FIXME: Send RST - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - } - else - { - /* FIXME: Send RST - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - } - return; - } - - if ((TCPHeader->Flags & TCP_ACK) > 0) - { - /* FIXME: If the precedence in the segment does not match the precedence in the TCB */ - if (FALSE) - { - /* FIXME: Send RST - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - return; - } - else - { - /* FIXME: If the precedence in the segment is higher than the precedence - in the TCB then if allowed by the user and the system raise - the precedence in the TCB to that in the segment, if not - allowed to raise the prec then send a reset. */ - if (FALSE) - { - /* FIXME: Send RST - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - return; - } - else - { - /* Continue */ - } - } - return; - } - - /* The ACK is ok, or there is no ACK, and it the segment did not contain a RST */ - - if ((TCPHeader->Flags & TCP_SYN) > 0) - { - /* FIXME: The security/compartment and precedence are acceptable */ - if (TRUE) - { - /* FIXME: RCV.NXT is set to SEG.SEQ+1, IRS is set to - SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there - is an ACK), and any segments on the retransmission queue which - are thereby acknowledged should be removed. - - If SND.UNA > ISS (our SYN has been ACKed), change the connection - state to ESTABLISHED, form an ACK segment - - - - Data or controls which were queued for - transmission may be included. If there are other controls or - text in the segment then continue processing at the sixth step - below where the URG bit is checked, otherwise return. - - Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - - - - and send it. If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. */ - - TI_DbgPrint(MIN_TRACE, ("FIXME: Maybe go to ctEstablished connection state.\n")); - } - else - { - /* FIXME: What happens here? */ - } - } - - /* FIXME: Send RST - */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Send RST.\n")); - return; + TCPiReceiveSynSent(AddrFile, IPPacket, TCPHeader); } State = AddrFile->Connection->State; @@ -774,9 +1354,9 @@ static VOID TCPiReceive( || State == ctTimeWait) { AddrFile->Connection->State = ctClosed; + TI_DbgPrint(DEBUG_TCP, ("Go to ctClosed connection state.\n")); return; } - } /* FIXME: check security and precedence */ @@ -786,6 +1366,7 @@ static VOID TCPiReceive( /* FIXME: If the security/compartment and precedence in the segment do not exactly match the security/compartment and precedence in the TCB then send a reset, and return. */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Check security/compartment and precedence.\n")); } if (AddrFile->Connection->State == ctSynReceived) @@ -797,6 +1378,7 @@ static VOID TCPiReceive( flushed. Users should also receive an unsolicited general "connection reset" signal. Enter the CLOSED state, delete the TCB, and return. */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Check security/compartment and precedence.\n")); } /* Note the previous check is placed following the sequence check to prevent @@ -834,28 +1416,24 @@ static VOID TCPiReceive( if ((TCPHeader->Flags & TCP_ACK) == 0) { /* Discard the segment */ + TI_DbgPrint(DEBUG_TCP, ("Discard.\n")); return; } if (AddrFile->Connection->State == ctSynReceived) { - /* FIXME: If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state - and continue processing. - - If the segment acknowledgment is not acceptable, form a - reset segment, - - - - and send it. */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Maybe go to ctEstablished connection state.\n")); - return; + if (TCPiReceiveSynReceived(AddrFile, IPPacket, TCPHeader) == FALSE) + { + return; + } } State = AddrFile->Connection->State; if (State == ctEstablished || State == ctCloseWait) { + PCONNECTION_ENDPOINT Connection = AddrFile->Connection; + /* FIXME: If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. Any segments on the retransmission queue which are thereby entirely acknowledged are removed. Users should receive @@ -876,7 +1454,33 @@ static VOID TCPiReceive( SND.WND, and that SND.WL2 records the acknowledgment number of the last segment used to update SND.WND. The check here prevents using old segments to update the window. */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Maybe send ACK.\n")); + + if ((Connection->SendUnacknowledged <= DN2H(TCPHeader->AckNumber)) + && (DN2H(TCPHeader->AckNumber) <= Connection->SendNext)) + { + TI_DbgPrint(MIN_TRACE, ("FIXME: Maybe remove segments on retransmission queue.\n")); + Connection->SendUnacknowledged = DN2H(TCPHeader->AckNumber); + } + + if ((Connection->SendUnacknowledged < DN2H(TCPHeader->AckNumber)) + && (DN2H(TCPHeader->AckNumber) <= Connection->SendNext)) + { + TI_DbgPrint(MIN_TRACE, ("FIXME: Update send window.\n")); + } + + if ((Connection->SendWL1 < DN2H(TCPHeader->SequenceNumber)) + || (Connection->SendWL1 == (DN2H(TCPHeader->SequenceNumber)) + && (Connection->SendWL2 <= (DN2H(TCPHeader->AckNumber))))) + { + TI_DbgPrint(DEBUG_TCP, ("Updating SendWindow, SendWL1 and SendWL2.\n")); + Connection->SendWindow = DN2H(TCPHeader->Window); + Connection->SendWL1 = DN2H(TCPHeader->SequenceNumber); + Connection->SendWL2 = DN2H(TCPHeader->AckNumber); + } + + /* Process any available data in the segment */ + TCPiReceiveData(AddrFile, IPPacket, TCPHeader, Payload); + return; } @@ -958,30 +1562,8 @@ static VOID TCPiReceive( || State == ctFinWait1 || State == ctFinWait2) { - /* FIXME: Once in the ESTABLISHED state, it is possible to deliver segment - text to user RECEIVE buffers. Text from segments can be moved - into buffers until either the buffer is full or the segment is - empty. If the segment empties and carries an PUSH flag, then - the user is informed, when the buffer is returned, that a PUSH - has been received. - - When the TCP takes responsibility for delivering the data to the - user it must also acknowledge the receipt of the data. - - Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. - - Please note the window management suggestions in section 3.7. - - Send an acknowledgment of the form: - - - - This acknowledgment should be piggybacked on a segment being - transmitted if possible without incurring undue delay. */ - TI_DbgPrint(MIN_TRACE, ("FIXME: Handle data.\n")); + /* Process any available data in the segment */ + TCPiReceiveData(AddrFile, IPPacket, TCPHeader, Payload); return; } @@ -1006,6 +1588,7 @@ static VOID TCPiReceive( || State == ctSynSent) { /* Discard segment */ + TI_DbgPrint(DEBUG_TCP, ("Discard.\n")); return; } @@ -1024,6 +1607,7 @@ static VOID TCPiReceive( case ctEstablished: { /* FIXME: Enter ctClosed state */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Go to ctClosed connection state.\n")); break; } case ctFinWait1: @@ -1031,12 +1615,14 @@ static VOID TCPiReceive( /* FIXME: If our FIN has been ACKed (perhaps in this segment), then enter TIME-WAIT, start the time-wait timer, turn off the other timers; otherwise enter the CLOSING state. */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Maybe go to ctClosing connection state.\n")); break; } case ctFinWait2: { /* FIXME: Enter the TIME-WAIT state. Start the time-wait timer, turn off the other timers. */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Go to ctTimeWait connection state.\n")); break; } case ctCloseWait: @@ -1048,8 +1634,9 @@ static VOID TCPiReceive( } case ctTimeWait: { - /* Remain in ctTimeWait connection state. Restart the 2 MSL time-wait + /* FIXME: Remain in ctTimeWait connection state. Restart the 2 MSL time-wait timeout */ + TI_DbgPrint(MIN_TRACE, ("FIXME: Restart the 2 MSL time-wait timeout.\n")); return; } default: @@ -1057,6 +1644,7 @@ static VOID TCPiReceive( return; } } + TI_DbgPrint(MIN_TRACE, ("Return.\n")); return; } } @@ -1077,9 +1665,14 @@ VOID TCPReceive( AF_SEARCH SearchContext; PIPv4_HEADER IPv4Header; PADDRESS_FILE AddrFile; - PTCP_HEADER TCPHeader; + PTCPv4_HEADER TCPHeader; PIP_ADDRESS DstAddress; UINT DataSize, i; + TCPv4_PSEUDO_HEADER TcpPseudoHeader; + KIRQL OldIrql; + + ASSERT(NTE); + ASSERT(IPPacket); TI_DbgPrint(MAX_TRACE, ("Called.\n")); @@ -1104,9 +1697,25 @@ VOID TCPReceive( DISPLAY_TCP_PACKET(IPPacket); - TCPHeader = (PTCP_HEADER)IPPacket->Data; + TCPHeader = (PTCPv4_HEADER)IPPacket->Data; - /* FIXME: Calculate and validate TCP checksum */ +#if 0 + /* Build pseudo TCP header which is used to prevent misrouted segments */ + TcpPseudoHeader.SourceAddress = IPPacket->SrcAddr.Address.IPv4Address; + TcpPseudoHeader.DestinationAddress = IPPacket->DstAddr.Address.IPv4Address;; + TcpPseudoHeader.Zero = 0; + TcpPseudoHeader.Protocol = 0; + /* Length of TCP header and segment data */ + TcpPseudoHeader.TCPLength = IPv4Header->TotalLength; + + /* Checksum TCP header and segment data */ + if (!TCPCorrectChecksum(&TcpPseudoHeader, IPPacket->Header, IPPacket->TotalSize)) { + TI_DbgPrint(MIN_TRACE, ("Segment received with bad checksum. Checksum field (0x%X)\n", + WN2H(TCPHeader->Checksum))); + /* Discard packet */ + return; + } +#endif /* FIXME: Sanity checks */ @@ -1115,14 +1724,28 @@ VOID TCPReceive( found, drop the packet */ AddrFile = AddrSearchFirst(DstAddress, - TCPHeader->DestPort, + TCPHeader->DestinationPort, IPPROTO_TCP, &SearchContext); if (AddrFile) { + ULONG TotalLength; + ULONG DataOffset; + ULONG Payload; + + TotalLength = WN2H(IPv4Header->TotalLength); + DataOffset = (TCPHeader->DataOffset & 0xF0) >> (4 << 2); /* Left-most 4 bits (in 32-bit words)*/ + Payload = TotalLength - DataOffset; + + TI_DbgPrint(DEBUG_TCP, ("TotalLength %d, DataOffset %d (%d bytes payload)\n", + TotalLength, DataOffset, Payload)); + /* There can be only one client */ TI_DbgPrint(MID_TRACE, ("Found address file object for IPv4 TCP datagram to address (0x%X).\n", DN2H(DstAddress->Address.IPv4Address))); - TCPiReceive(AddrFile, IPPacket, TCPHeader); + /* FIXME: Slow but effective synchronization */ + KeAcquireSpinLock(&AddrFile->Connection->Lock, &OldIrql); + TCPiReceive(AddrFile, IPPacket, TCPHeader, Payload); + KeReleaseSpinLock(&AddrFile->Connection->Lock, OldIrql); } else { /* There are no open address files that will take this datagram */ /* FIXME: IPv4 only */ @@ -1149,6 +1772,15 @@ NTSTATUS TCPStartup( /* 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 */ + TAG('T','C','P','S'), /* Tag */ + 0); /* Depth */ + TCPInitialized = TRUE; return STATUS_SUCCESS; @@ -1169,6 +1801,8 @@ NTSTATUS TCPShutdown( /* Deregister this protocol with IP layer */ IPRegisterProtocol(IPPROTO_TCP, NULL); + ExDeleteNPagedLookasideList(&TCPSegmentList); + TCPInitialized = FALSE; return STATUS_SUCCESS; diff --git a/reactos/lib/msafd/include/msafd.h b/reactos/lib/msafd/include/msafd.h index 6e18d4998dd..d7bfd1bcfe7 100644 --- a/reactos/lib/msafd/include/msafd.h +++ b/reactos/lib/msafd/include/msafd.h @@ -18,6 +18,13 @@ #include #include +/*typedef _MSAFD_LISTEN_REQUEST +{ + LIST_ENTRY ListEntry; + HANDLE Socket; +} MSAFD_LISTEN_REQUEST, *PMSAFD_LISTEN_REQUEST;*/ + + extern HANDLE GlobalHeap; extern WSPUPCALLTABLE Upcalls; extern LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest; diff --git a/reactos/lib/msafd/misc/dllmain.c b/reactos/lib/msafd/misc/dllmain.c index 9f23b9291fd..feab9fef992 100644 --- a/reactos/lib/msafd/misc/dllmain.c +++ b/reactos/lib/msafd/misc/dllmain.c @@ -23,6 +23,9 @@ DWORD DebugTraceLevel = MIN_TRACE; /* To make the linker happy */ VOID STDCALL KeBugCheck (ULONG BugCheckCode) {} +/* FIXME: Protect me */ +static LIST_ENTRY MsAfdListenRequests; /* Queue of listen reqests */ + HANDLE GlobalHeap; WSPUPCALLTABLE Upcalls; @@ -358,6 +361,7 @@ WSPListen( * 0, or SOCKET_ERROR if the socket could not be bound */ { + //PAFD_LISTEN_REQUEST MsafdRequest; FILE_REQUEST_LISTEN Request; FILE_REPLY_LISTEN Reply; IO_STATUS_BLOCK Iosb; @@ -365,28 +369,38 @@ WSPListen( AFD_DbgPrint(MAX_TRACE, ("s (0x%X) backlog (%d).\n", s, backlog)); +/* MsafdRequest = (PMSAFD_LISTEN_REQUEST)HeapAlloc( + GlobalHeap, 0, sizeof(MSAFD_LISTEN_REQUEST)); + if (MsafdRequest == NULL) + { + AFD_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + *lpErrno = WSAENOBUFS; + return SOCKET_ERROR; + }*/ + Request.Backlog = backlog; Status = NtDeviceIoControlFile( (HANDLE)s, NULL, - NULL, - NULL, - &Iosb, - IOCTL_AFD_LISTEN, - &Request, - sizeof(FILE_REQUEST_LISTEN), - &Reply, - sizeof(FILE_REPLY_LISTEN)); - if (Status == STATUS_PENDING) { - AFD_DbgPrint(MAX_TRACE, ("Waiting on transport.\n")); - /* FIXME: Wait only for blocking sockets */ - Status = NtWaitForSingleObject((HANDLE)s, FALSE, NULL); - } - - if (!NT_SUCCESS(Status)) { + NULL, + NULL, + &Iosb, + IOCTL_AFD_LISTEN, + &Request, + sizeof(FILE_REQUEST_LISTEN), + &Reply, + sizeof(FILE_REPLY_LISTEN)); + if (Status == STATUS_PENDING) + { + //AFD_DbgPrint(MAX_TRACE, ("Waiting on transport.\n")); + //InsertTailList(&MsAfdListenRequests, &MsafdRequest->ListEntry); + } + else if (!NT_SUCCESS(Status)) + { + //HeapFree(GlobalHeap, 0, MsafdRequest); *lpErrno = Reply.Status; - return SOCKET_ERROR; + return SOCKET_ERROR; } return 0; @@ -841,10 +855,13 @@ WSPStartup( */ { HMODULE hWS2_32; - INT Status; + NTSTATUS Status; + INT Error; AFD_DbgPrint(MAX_TRACE, ("wVersionRequested (0x%X) \n", wVersionRequested)); + Status = NO_ERROR; + EnterCriticalSection(&InitCriticalSection); Upcalls = UpcallTable; @@ -859,17 +876,22 @@ WSPStartup( lpWPUCompleteOverlappedRequest = (LPWPUCOMPLETEOVERLAPPEDREQUEST) GetProcAddress(hWS2_32, "WPUCompleteOverlappedRequest"); if (lpWPUCompleteOverlappedRequest != NULL) { - Status = NO_ERROR; StartupCount++; + } else { + AFD_DbgPrint(MIN_TRACE, ("GetProcAddress() failed for WPUCompleteOverlappedRequest\n")); + CloseCommandChannel(); + Error = WSASYSNOTREADY; } } else { AFD_DbgPrint(MIN_TRACE, ("GetModuleHandle() failed for ws2_32.dll\n")); + CloseCommandChannel(); + Error = WSASYSNOTREADY; } } else { AFD_DbgPrint(MIN_TRACE, ("Cannot open afd.sys\n")); + Error = WSASYSNOTREADY; } } else { - Status = NO_ERROR; StartupCount++; } @@ -969,6 +991,8 @@ DllMain(HANDLE hInstDll, InitializeCriticalSection(&InitCriticalSection); + InitializeListHead(&MsAfdListenRequests); + GlobalHeap = GetProcessHeap(); CreateHelperDLLDatabase();