- Merge the Google Summer of Code TcpIpDriver project to replace our current TCP implementation
- Remove oskittcp
- Big thanks to Claudiu Mihail for his work on the project
svn path=/trunk/; revision=53122
--- /dev/null
- /* TCPv4 header flags */
- #define TCP_URG 0x20
- #define TCP_ACK 0x10
- #define TCP_PSH 0x08
- #define TCP_RST 0x04
- #define TCP_SYN 0x02
- #define TCP_FIN 0x01
-
-
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: include/tcp.h
+ * PURPOSE: Transmission Control Protocol definitions
+ */
+
+#pragma once
+
+typedef VOID
+(*PTCP_COMPLETION_ROUTINE)( PVOID Context, NTSTATUS Status, ULONG Count );
+
+/* TCPv4 header structure */
+#include <pshpack1.h>
+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 */
+} TCPv4_HEADER, *PTCPv4_HEADER;
+
- NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
- PCONNECTION_ENDPOINT Connection,
- PTDI_REQUEST_KERNEL Request );
+#define TCPOPT_END_OF_LIST 0x0
+#define TCPOPT_NO_OPERATION 0x1
+#define TCPOPT_MAX_SEG_SIZE 0x2
+
+#define TCPOPTLEN_MAX_SEG_SIZE 0x4
+
+/* Data offset; 32-bit words (leftmost 4 bits); convert to bytes */
+#define TCP_DATA_OFFSET(DataOffset)(((DataOffset) & 0xF0) >> (4-2))
+
+
+/* TCPv4 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 */
+} TCPv4_PSEUDO_HEADER, *PTCPv4_PSEUDO_HEADER;
+#include <poppack.h>
+
+typedef struct _SLEEPING_THREAD {
+ LIST_ENTRY Entry;
+ PVOID SleepToken;
+ KEVENT Event;
+} SLEEPING_THREAD, *PSLEEPING_THREAD;
+
+typedef struct _CLIENT_DATA {
+ BOOLEAN Unlocked;
+ KSPIN_LOCK Lock;
+ KIRQL OldIrql;
+} CLIENT_DATA, *PCLIENT_DATA;
+
+/* Retransmission timeout constants */
+
+/* Lower bound for retransmission timeout in TCP timer ticks */
+#define TCP_MIN_RETRANSMISSION_TIMEOUT 1*1000 /* 1 tick */
+
+/* Upper bound for retransmission timeout in TCP timer ticks */
+#define TCP_MAX_RETRANSMISSION_TIMEOUT 1*60*1000 /* 1 tick */
+
+/* Smoothing factor */
+#define TCP_ALPHA_RETRANSMISSION_TIMEOUT(x)(((x)*8)/10) /* 0.8 */
+
+/* Delay variance factor */
+#define TCP_BETA_RETRANSMISSION_TIMEOUT(x)(((x)*16)/10) /* 1.6 */
+
++#define SEL_CONNECT 1
++#define SEL_FIN 2
++#define SEL_RST 4
++#define SEL_ABRT 8
++#define SEL_READ 16
++#define SEL_WRITE 32
++#define SEL_ACCEPT 64
++#define SEL_OOB 128
++#define SEL_ERROR 256
++#define SEL_FINOUT 512
++
++#define FREAD 0x0001
++#define FWRITE 0x0002
+
+/* Datagram/segment send request flags */
+
+#define SRF_URG TCP_URG
+#define SRF_ACK TCP_ACK
+#define SRF_PSH TCP_PSH
+#define SRF_RST TCP_RST
+#define SRF_SYN TCP_SYN
+#define SRF_FIN TCP_FIN
+
+extern LONG TCP_IPIdentification;
+extern CLIENT_DATA ClientInfo;
+
+/* accept.c */
- NTSTATUS TCPTranslateError( int OskitError );
++NTSTATUS TCPCheckPeerForAccept(PVOID Context,
++ PTDI_REQUEST_KERNEL Request);
+NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog );
+BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
+ PCONNECTION_ENDPOINT Connection );
+NTSTATUS TCPAccept
+( PTDI_REQUEST Request,
+ PCONNECTION_ENDPOINT Listener,
+ PCONNECTION_ENDPOINT Connection,
+ PTCP_COMPLETION_ROUTINE Complete,
+ PVOID Context );
+
+/* tcp.c */
+PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext );
+VOID TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection );
+
+NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
+ UINT Family, UINT Type, UINT Proto );
+
+VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection);
+
+PTCP_SEGMENT TCPCreateSegment(
+ PIP_PACKET IPPacket,
+ PTCPv4_HEADER TCPHeader,
+ ULONG SegmentLength);
+
+VOID TCPFreeSegment(
+ PTCP_SEGMENT Segment);
+
+VOID TCPAddSegment(
+ PCONNECTION_ENDPOINT Connection,
+ PTCP_SEGMENT Segment,
+ PULONG Acknowledged);
+
+NTSTATUS TCPConnect(
+ PCONNECTION_ENDPOINT Connection,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo,
+ PTCP_COMPLETION_ROUTINE Complete,
+ PVOID Context);
+
+NTSTATUS TCPDisconnect(
+ PCONNECTION_ENDPOINT Connection,
+ UINT Flags,
+ PLARGE_INTEGER Timeout,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo,
+ PTCP_COMPLETION_ROUTINE Complete,
+ PVOID Context);
+
+NTSTATUS TCPReceiveData(
+ PCONNECTION_ENDPOINT Connection,
+ PNDIS_BUFFER Buffer,
+ ULONG ReceiveLength,
+ PULONG BytesReceived,
+ ULONG ReceiveFlags,
+ PTCP_COMPLETION_ROUTINE Complete,
+ PVOID Context);
+
+NTSTATUS TCPSendData(
+ PCONNECTION_ENDPOINT Connection,
+ PCHAR Buffer,
+ ULONG DataSize,
+ PULONG DataUsed,
+ ULONG Flags,
+ PTCP_COMPLETION_ROUTINE Complete,
+ PVOID Context);
+
+NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection );
+
- UINT TCPAllocatePort( UINT HintPort );
++NTSTATUS TCPTranslateError( const INT8 err );
+
- VOID TCPFreePort( UINT Port );
++UINT TCPAllocatePort( const UINT HintPort );
+
++VOID TCPFreePort( const UINT Port );
+
+NTSTATUS TCPGetSockAddress
+( PCONNECTION_ENDPOINT Connection,
+ PTRANSPORT_ADDRESS TransportAddress,
+ BOOLEAN RemoteAddress );
+
+NTSTATUS TCPStartup(
+ VOID);
+
+NTSTATUS TCPShutdown(
+ VOID);
+
+BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Connection, PIRP Irp );
++
++VOID
++TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF);
++
++VOID
++TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF);
++
++VOID
++FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status);
++
++VOID
++FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status);
++
++VOID
++FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked);
++
++VOID
++FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked);
++
++VOID
++FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked);
++
++VOID
++FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status);
++
++VOID CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous);
--- /dev/null
- /* Signals */
- UINT SignalState; /* Active signals from oskit */
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: include/titypes.h
+ * PURPOSE: TCP/IP protocol driver types
+ */
+
+#pragma once
+
+/*
+ * VOID ReferenceObject(
+ * PVOID Object)
+ */
+#define ReferenceObject(Object) \
+{ \
+ InterlockedIncrement(&((Object)->RefCount)); \
+}
+
+/*
+ * VOID DereferenceObject(
+ * PVOID Object)
+ */
+#define DereferenceObject(Object) \
+{ \
+ if (InterlockedDecrement(&((Object)->RefCount)) == 0) \
+ (((Object)->Free)(Object)); \
+}
+
+/*
+ * VOID LockObject(PVOID Object, PKIRQL OldIrql)
+ */
+#define LockObject(Object, Irql) \
+{ \
+ ReferenceObject(Object); \
+ KeAcquireSpinLock(&((Object)->Lock), Irql); \
+ memcpy(&(Object)->OldIrql, Irql, sizeof(KIRQL)); \
+}
+
+/*
+ * VOID LockObjectAtDpcLevel(PVOID Object)
+ */
+#define LockObjectAtDpcLevel(Object) \
+{ \
+ ReferenceObject(Object); \
+ KeAcquireSpinLockAtDpcLevel(&((Object)->Lock)); \
+ (Object)->OldIrql = DISPATCH_LEVEL; \
+}
+
+/*
+ * VOID UnlockObject(PVOID Object, KIRQL OldIrql)
+ */
+#define UnlockObject(Object, OldIrql) \
+{ \
+ KeReleaseSpinLock(&((Object)->Lock), OldIrql); \
+ DereferenceObject(Object); \
+}
+
+/*
+ * VOID UnlockObjectFromDpcLevel(PVOID Object)
+ */
+#define UnlockObjectFromDpcLevel(Object) \
+{ \
+ KeReleaseSpinLockFromDpcLevel(&((Object)->Lock)); \
+ DereferenceObject(Object); \
+}
+
+
+
+#include <ip.h>
+
+struct _ADDRESS_FILE;
+
+/***************************************************
+* Connection-less communication support structures *
+***************************************************/
+
+typedef NTSTATUS (*DATAGRAM_SEND_ROUTINE)(
+ struct _ADDRESS_FILE *AddrFile,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PCHAR Buffer,
+ ULONG DataSize,
+ PULONG DataUsed);
+
+/* Datagram completion handler prototype */
+typedef VOID (*DATAGRAM_COMPLETION_ROUTINE)(
+ PVOID Context,
+ NDIS_STATUS Status,
+ ULONG Count);
+
+typedef DATAGRAM_COMPLETION_ROUTINE PDATAGRAM_COMPLETION_ROUTINE;
+
+typedef struct _DATAGRAM_RECEIVE_REQUEST {
+ struct _ADDRESS_FILE *AddressFile; /* AddressFile on behalf of */
+ LIST_ENTRY ListEntry; /* Entry on list */
+ IP_ADDRESS RemoteAddress; /* Remote address we receive from (NULL means any) */
+ USHORT RemotePort; /* Remote port we receive from (0 means any) */
+ PTDI_CONNECTION_INFORMATION ReturnInfo;/* Return information */
+ PCHAR Buffer; /* Pointer to receive buffer */
+ ULONG BufferSize; /* Size of Buffer */
+ DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */
+ PVOID Context; /* Pointer to context information */
+ DATAGRAM_COMPLETION_ROUTINE UserComplete; /* Completion routine */
+ PVOID UserContext; /* Pointer to context information */
+ PIRP Irp; /* IRP on behalf of */
+} DATAGRAM_RECEIVE_REQUEST, *PDATAGRAM_RECEIVE_REQUEST;
+
+/* Datagram build routine prototype */
+typedef NTSTATUS (*DATAGRAM_BUILD_ROUTINE)(
+ PVOID Context,
+ PIP_ADDRESS LocalAddress,
+ USHORT LocalPort,
+ PIP_PACKET *IPPacket);
+
+typedef struct _DATAGRAM_SEND_REQUEST {
+ LIST_ENTRY ListEntry;
+ PNDIS_PACKET PacketToSend;
+ DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */
+ PVOID Context; /* Pointer to context information */
+ IP_PACKET Packet;
+ UINT BufferSize;
+ IP_ADDRESS RemoteAddress;
+ USHORT RemotePort;
+ ULONG Flags; /* Protocol specific flags */
+} DATAGRAM_SEND_REQUEST, *PDATAGRAM_SEND_REQUEST;
+
+/* Transport address file context structure. The FileObject->FsContext2
+ field holds a pointer to this structure */
+typedef struct _ADDRESS_FILE {
+ LIST_ENTRY ListEntry; /* Entry on list */
+ LONG RefCount; /* Reference count */
+ OBJECT_FREE_ROUTINE Free; /* Routine to use to free resources for the object */
+ KSPIN_LOCK Lock; /* Spin lock to manipulate this structure */
+ KIRQL OldIrql; /* Currently not used */
+ IP_ADDRESS Address; /* Address of this address file */
+ USHORT Family; /* Address family */
+ USHORT Protocol; /* Protocol number */
+ USHORT Port; /* Network port (network byte order) */
+ UCHAR TTL; /* Time to live stored in packets sent from this address file */
+ UINT DF; /* Don't fragment */
+ UINT BCast; /* Receive broadcast packets */
+ UINT HeaderIncl; /* Include header in RawIP packets */
+ WORK_QUEUE_ITEM WorkItem; /* Work queue item handle */
+ DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine for delete request */
+ PVOID Context; /* Delete request context */
+ DATAGRAM_SEND_ROUTINE Send; /* Routine to send a datagram */
+ LIST_ENTRY ReceiveQueue; /* List of outstanding receive requests */
+ LIST_ENTRY TransmitQueue; /* List of outstanding transmit requests */
+ struct _CONNECTION_ENDPOINT *Connection;
+ /* Associated connection or NULL if no associated connection exist */
+ struct _CONNECTION_ENDPOINT *Listener;
+ /* Associated listener (see transport/tcp/accept.c) */
+ IP_ADDRESS AddrCache; /* One entry address cache (destination
+ address of last packet transmitted) */
+
+ /* The following members are used to control event notification */
+
+ /* Connection indication handler */
+ PTDI_IND_CONNECT ConnectHandler;
+ PVOID ConnectHandlerContext;
+ BOOLEAN RegisteredConnectHandler;
+ /* Disconnect indication handler */
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PVOID DisconnectHandlerContext;
+ BOOLEAN RegisteredDisconnectHandler;
+ /* Error indication handler */
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+ PVOID ErrorHandlerOwner;
+ BOOLEAN RegisteredErrorHandler;
+ /* Receive indication handler */
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PVOID ReceiveHandlerContext;
+ BOOLEAN RegisteredReceiveHandler;
+ /* Receive datagram indication handler */
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ /* Expedited receive indication handler */
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedReceiveHandler;
+ PVOID ExpeditedReceiveHandlerContext;
+ BOOLEAN RegisteredExpeditedReceiveHandler;
+ /* Chained receive indication handler */
+ PTDI_IND_CHAINED_RECEIVE ChainedReceiveHandler;
+ PVOID ChainedReceiveHandlerContext;
+ BOOLEAN RegisteredChainedReceiveHandler;
+ /* Chained receive datagram indication handler */
+ PTDI_IND_CHAINED_RECEIVE_DATAGRAM ChainedReceiveDatagramHandler;
+ PVOID ChainedReceiveDatagramHandlerContext;
+ BOOLEAN RegisteredChainedReceiveDatagramHandler;
+ /* Chained expedited receive indication handler */
+ PTDI_IND_CHAINED_RECEIVE_EXPEDITED ChainedReceiveExpeditedHandler;
+ PVOID ChainedReceiveExpeditedHandlerContext;
+ BOOLEAN RegisteredChainedReceiveExpeditedHandler;
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+/* Structure used to search through Address Files */
+typedef struct _AF_SEARCH {
+ PLIST_ENTRY Next; /* Next address file to check */
+ PIP_ADDRESS Address; /* Pointer to address to be found */
+ USHORT Port; /* Network port */
+ USHORT Protocol; /* Protocol number */
+} AF_SEARCH, *PAF_SEARCH;
+
+/*******************************************************
+* Connection-oriented communication support structures *
+*******************************************************/
+
+typedef struct _TCP_RECEIVE_REQUEST {
+ LIST_ENTRY ListEntry; /* Entry on list */
+ PNDIS_BUFFER Buffer; /* Pointer to receive buffer */
+ ULONG BufferSize; /* Size of Buffer */
+ DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */
+ PVOID Context; /* Pointer to context information */
+} TCP_RECEIVE_REQUEST, *PTCP_RECEIVE_REQUEST;
+
+/* Connection states */
+typedef enum {
+ ctListen = 0, /* Waiting for incoming connection requests */
+ ctSynSent, /* Waiting for matching connection request */
+ ctSynReceived, /* Waiting for connection request acknowledgment */
+ ctEstablished, /* Connection is open for data transfer */
+ ctFinWait1, /* Waiting for termination request or ack. for same */
+ ctFinWait2, /* Waiting for termination request from remote TCP */
+ ctCloseWait, /* Waiting for termination request from local user */
+ ctClosing, /* Waiting for termination ack. from remote TCP */
+ ctLastAck, /* Waiting for termination request ack. from remote TCP */
+ ctTimeWait, /* Waiting for enough time to pass to be sure the remote TCP
+ received the ack. of its connection termination request */
+ ctClosed /* Represents a closed connection */
+} CONNECTION_STATE, *PCONNECTION_STATE;
+
+
+/* Structure for an TCP segment */
+typedef struct _TCP_SEGMENT {
+ LIST_ENTRY ListEntry;
+ PIP_PACKET IPPacket; /* Pointer to IP packet */
+ PVOID SegmentData; /* Pointer to segment data */
+ ULONG SequenceNumber; /* Sequence number of first byte in segment */
+ ULONG Length; /* Number of bytes in segment */
+ ULONG BytesDelivered; /* Number of bytes already delivered to the client */
+} TCP_SEGMENT, *PTCP_SEGMENT;
+
+typedef struct _TDI_BUCKET {
+ LIST_ENTRY Entry;
+ struct _CONNECTION_ENDPOINT *AssociatedEndpoint;
+ TDI_REQUEST Request;
+ NTSTATUS Status;
+ ULONG Information;
+} TDI_BUCKET, *PTDI_BUCKET;
+
+/* Transport connection context structure A.K.A. Transmission Control Block
+ (TCB) in TCP terminology. The FileObject->FsContext2 field holds a pointer
+ to this structure */
+typedef struct _CONNECTION_ENDPOINT {
+ PVOID SocketContext; /* Context for lower layer (MUST be first member in struct) */
+ LIST_ENTRY ListEntry; /* Entry on list */
+ LONG RefCount; /* Reference count */
+ OBJECT_FREE_ROUTINE Free; /* Routine to use to free resources for the object */
+ KSPIN_LOCK Lock; /* Spin lock to protect this structure */
+ KIRQL OldIrql; /* The old irql is stored here for use in HandleSignalledConnection */
+ PVOID ClientContext; /* Pointer to client context information */
+ PADDRESS_FILE AddressFile; /* Associated address file object (NULL if none) */
+
+ /* Requests */
+ LIST_ENTRY ConnectRequest; /* Queued connect rqueusts */
+ LIST_ENTRY ListenRequest; /* Queued listen requests */
+ LIST_ENTRY ReceiveRequest; /* Queued receive requests */
+ LIST_ENTRY SendRequest; /* Queued send requests */
+ LIST_ENTRY ShutdownRequest;/* Queued shutdown requests */
+
++ LIST_ENTRY PacketQueue; /* Queued received packets waiting to be processed */
+
+ /* Disconnect Timer */
+ KTIMER DisconnectTimer;
+ KDPC DisconnectDpc;
+
++ /* Socket state */
++ BOOLEAN SendShutdown;
++ BOOLEAN ReceiveShutdown;
++
+ struct _CONNECTION_ENDPOINT *Next; /* Next connection in address file list */
+} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;
+
+
+
+/*************************
+* TDI support structures *
+*************************/
+
+/* Transport control channel context structure. The FileObject->FsContext2
+ field holds a pointer to this structure */
+typedef struct _CONTROL_CHANNEL {
+ LIST_ENTRY ListEntry; /* Entry on list */
+ LONG RefCount; /* Reference count */
+ OBJECT_FREE_ROUTINE Free; /* Routine to use to free resources for the object */
+ KSPIN_LOCK Lock; /* Spin lock to protect this structure */
+} CONTROL_CHANNEL, *PCONTROL_CHANNEL;
+
+/* Transport (TCP/UDP) endpoint context structure. The FileObject->FsContext
+ field holds a pointer to this structure */
+typedef struct _TRANSPORT_CONTEXT {
+ union {
+ HANDLE AddressHandle;
+ CONNECTION_CONTEXT ConnectionContext;
+ HANDLE ControlChannel;
+ } Handle;
+ BOOLEAN CancelIrps;
+ KEVENT CleanupEvent;
+} TRANSPORT_CONTEXT, *PTRANSPORT_CONTEXT;
+
+typedef struct _TI_QUERY_CONTEXT {
+ PIRP Irp;
+ PMDL InputMdl;
+ PMDL OutputMdl;
+ TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
+} TI_QUERY_CONTEXT, *PTI_QUERY_CONTEXT;
+
+/* EOF */
--- /dev/null
- <include base="oskittcp">include</include>
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<module name="tcpip" type="kernelmodedriver" installbase="system32/drivers" installname="tcpip.sys">
+ <importlibrary definition="tcpip.spec" />
+ <include base="tcpip">include</include>
- <library>oskittcp</library>
++ <include base="lwip">src/include</include>
++ <include base="lwip">src/include/ipv4</include>
+ <define name="NDIS40" />
+ <define name="_NTDRIVER_" />
+ <library>ip</library>
++ <library>lwip</library>
+ <library>ndis</library>
+ <library>pseh</library>
+ <library>chew</library>
+ <library>ntoskrnl</library>
+ <library>hal</library>
+ <directory name="include">
+ <pch>precomp.h</pch>
+ </directory>
+ <directory name="datalink">
+ <file>lan.c</file>
+ </directory>
+ <directory name="tcpip">
+ <file>ainfo.c</file>
+ <file>buffer.c</file>
+ <file>dispatch.c</file>
+ <file>fileobjs.c</file>
+ <file>iinfo.c</file>
+ <file>info.c</file>
+ <file>lock.c</file>
+ <file>main.c</file>
+ <file>ninfo.c</file>
+ <file>proto.c</file>
+ <file>tinfo.c</file>
+ <file>wait.c</file>
+ </directory>
+ <file>tcpip.rc</file>
+</module>
--- /dev/null
- PCONNECTION_ENDPOINT Connection, LastConnection;
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: tcpip/dispatch.h
+ * PURPOSE: TDI dispatch routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ * TODO: Validate device object in all dispatch routines
+ */
+
+#include "precomp.h"
+
+NTSTATUS IRPFinish( PIRP Irp, NTSTATUS Status ) {
+ KIRQL OldIrql;
+
+ Irp->IoStatus.Status = Status;
+
+ if( Status == STATUS_PENDING )
+ IoMarkIrpPending( Irp );
+ else {
+ IoAcquireCancelSpinLock(&OldIrql);
+ (void)IoSetCancelRoutine( Irp, NULL );
+ IoReleaseCancelSpinLock(OldIrql);
+
+ IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+ }
+
+ return Status;
+}
+
+NTSTATUS DispPrepareIrpForCancel(
+ PTRANSPORT_CONTEXT Context,
+ PIRP Irp,
+ PDRIVER_CANCEL CancelRoutine)
+/*
+ * FUNCTION: Prepare an IRP for cancellation
+ * ARGUMENTS:
+ * Context = Pointer to context information
+ * Irp = Pointer to an I/O request packet
+ * CancelRoutine = Routine to be called when I/O request is cancelled
+ * RETURNS:
+ * Status of operation
+ */
+{
+ KIRQL OldIrql;
+ PIO_STACK_LOCATION IrpSp;
+ PTRANSPORT_CONTEXT TransContext;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ TransContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+
+ IoAcquireCancelSpinLock(&OldIrql);
+
+ if (!Irp->Cancel && !TransContext->CancelIrps) {
+ (void)IoSetCancelRoutine(Irp, CancelRoutine);
+ IoReleaseCancelSpinLock(OldIrql);
+
+ TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp));
+
+ return STATUS_SUCCESS;
+ }
+
+ /* IRP has already been cancelled */
+
+ IoReleaseCancelSpinLock(OldIrql);
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+
+ TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n"));
+
+ return Irp->IoStatus.Status;
+}
+
+VOID DispDataRequestComplete(
+ PVOID Context,
+ NTSTATUS Status,
+ ULONG Count)
+/*
+ * FUNCTION: Completes a send/receive IRP
+ * ARGUMENTS:
+ * Context = Pointer to context information (IRP)
+ * Status = Status of the request
+ * Count = Number of bytes sent or received
+ */
+{
+ PIRP Irp = Context;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called for irp %x (%x, %d).\n",
+ Irp, Status, Count));
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Count;
+
+ TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Status = %x\n",
+ Irp->IoStatus.Status));
+ TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Information = %d\n",
+ Irp->IoStatus.Information));
+ TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+ IRPFinish(Irp, Status);
+
+ TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n"));
+}
+
+VOID NTAPI DispCancelRequest(
+ PDEVICE_OBJECT Device,
+ PIRP Irp)
+/*
+ * FUNCTION: Cancels an IRP
+ * ARGUMENTS:
+ * Device = Pointer to device object
+ * Irp = Pointer to an I/O request packet
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ PTRANSPORT_CONTEXT TranContext;
+ PFILE_OBJECT FileObject;
+ UCHAR MinorFunction;
+ PCONNECTION_ENDPOINT Connection;
+ BOOLEAN DequeuedIrp = TRUE;
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ FileObject = IrpSp->FileObject;
+ TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;
+ MinorFunction = IrpSp->MinorFunction;
+
+ TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X) MinorFunction (0x%X) IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+
+#if DBG
+ if (!Irp->Cancel)
+ TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
+#endif
+
+ /* Try canceling the request */
+ switch(MinorFunction) {
+ case TDI_SEND:
+ case TDI_RECEIVE:
+ DequeuedIrp = TCPRemoveIRP( TranContext->Handle.ConnectionContext, Irp );
+ break;
+
+ case TDI_SEND_DATAGRAM:
+ if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));
+ break;
+ }
+
+ DequeuedIrp = DGRemoveIRP(TranContext->Handle.AddressHandle, Irp);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));
+ break;
+ }
+
+ DequeuedIrp = DGRemoveIRP(TranContext->Handle.AddressHandle, Irp);
+ break;
+
+ case TDI_CONNECT:
+ DequeuedIrp = TCPRemoveIRP(TranContext->Handle.ConnectionContext, Irp);
+ break;
+
+ case TDI_DISCONNECT:
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+
+ DequeuedIrp = TCPRemoveIRP(TranContext->Handle.ConnectionContext, Irp);
+ if (DequeuedIrp)
+ {
+ if (KeCancelTimer(&Connection->DisconnectTimer))
+ {
+ DereferenceObject(Connection);
+ }
+ }
+ break;
+
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction));
+ ASSERT(FALSE);
+ break;
+ }
+
+ if (DequeuedIrp)
+ IRPFinish(Irp, STATUS_CANCELLED);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+VOID NTAPI DispCancelListenRequest(
+ PDEVICE_OBJECT Device,
+ PIRP Irp)
+/*
+ * FUNCTION: Cancels a listen IRP
+ * ARGUMENTS:
+ * Device = Pointer to device object
+ * Irp = Pointer to an I/O request packet
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ PTRANSPORT_CONTEXT TranContext;
+ PFILE_OBJECT FileObject;
+ PCONNECTION_ENDPOINT Connection;
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ FileObject = IrpSp->FileObject;
+ TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;
+ ASSERT( TDI_LISTEN == IrpSp->MinorFunction);
+
+ TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X).\n", Irp));
+
+#if DBG
+ if (!Irp->Cancel)
+ TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
+#endif
+
+ /* Try canceling the request */
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+
+ if (TCPAbortListenForSocket(Connection->AddressFile->Listener,
+ Connection))
+ {
+ Irp->IoStatus.Information = 0;
+ IRPFinish(Irp, STATUS_CANCELLED);
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+NTSTATUS DispTdiAccept(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_ACCEPT handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiAssociateAddress(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_ASSOCIATE_ADDRESS handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
+ PCONNECTION_ENDPOINT Connection, LastConnection;
+ PFILE_OBJECT FileObject;
+ PADDRESS_FILE AddrFile = NULL;
+ NTSTATUS Status;
+ KIRQL OldIrql;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* 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_PARAMETER;
+ }
+
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+ if (!Connection) {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
+
+ Status = ObReferenceObjectByHandle(
+ Parameters->AddressHandle,
+ 0,
+ IoFileObjectType,
+ KernelMode,
+ (PVOID*)&FileObject,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+ TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X): %x.\n",
+ Parameters->AddressHandle, Status));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ LockObject(Connection, &OldIrql);
+
+ if (Connection->AddressFile) {
+ ObDereferenceObject(FileObject);
+ UnlockObject(Connection, OldIrql);
+ TI_DbgPrint(MID_TRACE, ("An address file is already asscociated.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ ObDereferenceObject(FileObject);
+ UnlockObject(Connection, OldIrql);
+ TI_DbgPrint(MID_TRACE, ("Bad address file object. Magic (0x%X).\n",
+ FileObject->FsContext2));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Get associated address file object. Quit if none exists */
+
+ TranContext = FileObject->FsContext;
+ if (!TranContext) {
+ ObDereferenceObject(FileObject);
+ UnlockObject(Connection, OldIrql);
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
+ if (!AddrFile) {
+ UnlockObject(Connection, OldIrql);
+ ObDereferenceObject(FileObject);
+ TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ LockObjectAtDpcLevel(AddrFile);
+
+ ReferenceObject(AddrFile);
+ Connection->AddressFile = AddrFile;
+
+ /* Add connection endpoint to the address file */
+ ReferenceObject(Connection);
+ if (AddrFile->Connection == NULL)
+ AddrFile->Connection = Connection;
+ else
+ {
+ LastConnection = AddrFile->Connection;
+ while (LastConnection->Next != NULL)
+ LastConnection = LastConnection->Next;
+ LastConnection->Next = Connection;
+ }
+
+ ObDereferenceObject(FileObject);
+
+ UnlockObjectFromDpcLevel(AddrFile);
+ UnlockObject(Connection, OldIrql);
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS DispTdiConnect(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_CONNECT handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PCONNECTION_ENDPOINT Connection;
+ PTDI_REQUEST_KERNEL Parameters;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* Get associated connection endpoint file object. Quit if none exists */
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (!TranContext) {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+ if (!Connection) {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
+
+ Status = DispPrepareIrpForCancel(TranContext->Handle.ConnectionContext,
+ Irp,
+ DispCancelRequest);
+
+ if (NT_SUCCESS(Status)) {
+ Status = TCPConnect(
+ TranContext->Handle.ConnectionContext,
+ Parameters->RequestConnectionInformation,
+ Parameters->ReturnConnectionInformation,
+ DispDataRequestComplete,
+ Irp );
+ }
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, 0);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiDisassociateAddress(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_DISASSOCIATE_ADDRESS handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
- KIRQL OldIrql;
- NTSTATUS Status;
++ PCONNECTION_ENDPOINT Connection;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
- LockObject(Connection, &OldIrql);
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* 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_PARAMETER;
+ }
+
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+ if (!Connection) {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
- if (!Connection->AddressFile) {
- UnlockObject(Connection, OldIrql);
- TI_DbgPrint(MID_TRACE, ("No address file is asscociated.\n"));
- return STATUS_INVALID_PARAMETER;
- }
-
- LockObjectAtDpcLevel(Connection->AddressFile);
-
- /* Unlink this connection from the address file */
- if (Connection->AddressFile->Connection == Connection)
- {
- Connection->AddressFile->Connection = Connection->Next;
- DereferenceObject(Connection);
- Status = STATUS_SUCCESS;
- }
- else
- {
- LastConnection = Connection->AddressFile->Connection;
- while (LastConnection->Next != Connection && LastConnection->Next != NULL)
- LastConnection = LastConnection->Next;
- if (LastConnection->Next == Connection)
- {
- LastConnection->Next = Connection->Next;
- DereferenceObject(Connection);
- Status = STATUS_SUCCESS;
- }
- else
- {
- Status = STATUS_INVALID_PARAMETER;
- }
- }
-
- UnlockObjectFromDpcLevel(Connection->AddressFile);
-
- if (Status == STATUS_SUCCESS)
- {
- /* Remove the address file from this connection */
- DereferenceObject(Connection->AddressFile);
- Connection->AddressFile = NULL;
- }
-
- UnlockObject(Connection, OldIrql);
-
- return Status;
++ /* NO-OP because we need the address to deallocate the port when the connection closes */
+
++ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS DispTdiDisconnect(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_DISCONNECT handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ NTSTATUS Status;
+ PTDI_REQUEST_KERNEL_DISCONNECT DisReq;
+ PCONNECTION_ENDPOINT Connection;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ DisReq = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
+
+ /* Get associated connection endpoint file object. Quit if none exists */
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (!TranContext) {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+ if (!Connection) {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Status = DispPrepareIrpForCancel
+ (TranContext->Handle.ConnectionContext,
+ Irp,
+ (PDRIVER_CANCEL)DispCancelRequest);
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = TCPDisconnect(TranContext->Handle.ConnectionContext,
+ DisReq->RequestFlags,
+ DisReq->RequestSpecific,
+ DisReq->RequestConnectionInformation,
+ DisReq->ReturnConnectionInformation,
+ DispDataRequestComplete,
+ Irp);
+ }
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, 0);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(MAX_TRACE, ("TCP Disconnect returned %08x\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiListen(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_LISTEN handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PCONNECTION_ENDPOINT Connection;
+ PTDI_REQUEST_KERNEL Parameters;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status = STATUS_SUCCESS;
+ KIRQL OldIrql;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* Get associated connection endpoint file object. Quit if none exists */
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (TranContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+ if (Connection == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
+
+ Status = DispPrepareIrpForCancel
+ (TranContext->Handle.ConnectionContext,
+ Irp,
+ (PDRIVER_CANCEL)DispCancelListenRequest);
+
+ LockObject(Connection, &OldIrql);
+
+ if (Connection->AddressFile == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("No associated address file\n"));
+ UnlockObject(Connection, OldIrql);
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ LockObjectAtDpcLevel(Connection->AddressFile);
+
+ /* Listening will require us to create a listening socket and store it in
+ * the address file. It will be signalled, and attempt to complete an irp
+ * when a new connection arrives. */
+ /* The important thing to note here is that the irp we'll complete belongs
+ * to the socket to be accepted onto, not the listener */
+ if( NT_SUCCESS(Status) && !Connection->AddressFile->Listener ) {
+ Connection->AddressFile->Listener =
+ TCPAllocateConnectionEndpoint( NULL );
+
+ if( !Connection->AddressFile->Listener )
+ Status = STATUS_NO_MEMORY;
+
+ if( NT_SUCCESS(Status) ) {
++ ReferenceObject(Connection->AddressFile);
+ Connection->AddressFile->Listener->AddressFile =
+ Connection->AddressFile;
+
+ Status = TCPSocket( Connection->AddressFile->Listener,
+ Connection->AddressFile->Family,
+ SOCK_STREAM,
+ Connection->AddressFile->Protocol );
+ }
+
+ if( NT_SUCCESS(Status) )
+ Status = TCPListen( Connection->AddressFile->Listener, 1024 );
+ /* BACKLOG */
+ }
+
+ if( NT_SUCCESS(Status) ) {
+ Status = TCPAccept
+ ( (PTDI_REQUEST)Parameters,
+ Connection->AddressFile->Listener,
+ Connection,
+ DispDataRequestComplete,
+ Irp );
+ }
+
+ UnlockObjectFromDpcLevel(Connection->AddressFile);
+ UnlockObject(Connection, OldIrql);
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, 0);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiQueryInformation(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_QUERY_INFORMATION handler
+ * ARGUMENTS:
+ * DeviceObject = Pointer to device object structure
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ Parameters = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (!TranContext) {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (Parameters->QueryType)
+ {
+ case TDI_QUERY_ADDRESS_INFO:
+ {
+ PTDI_ADDRESS_INFO AddressInfo;
+ PADDRESS_FILE AddrFile;
+ PTA_IP_ADDRESS Address;
+ PCONNECTION_ENDPOINT Endpoint = NULL;
+
+
+ if (MmGetMdlByteCount(Irp->MdlAddress) <
+ (FIELD_OFFSET(TDI_ADDRESS_INFO, Address.Address[0].Address) +
+ sizeof(TDI_ADDRESS_IP))) {
+ TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ AddressInfo = (PTDI_ADDRESS_INFO)MmGetSystemAddressForMdl(Irp->MdlAddress);
+ Address = (PTA_IP_ADDRESS)&AddressInfo->Address;
+
+ switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
+
+ Address->TAAddressCount = 1;
+ Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+ Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ Address->Address[0].Address[0].sin_port = AddrFile->Port;
+ Address->Address[0].Address[0].in_addr = AddrFile->Address.Address.IPv4Address;
+ RtlZeroMemory(
+ &Address->Address[0].Address[0].sin_zero,
+ sizeof(Address->Address[0].Address[0].sin_zero));
+ return STATUS_SUCCESS;
+
+ case TDI_CONNECTION_FILE:
+ Endpoint =
+ (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+
+ Address->TAAddressCount = 1;
+ Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+ Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ Address->Address[0].Address[0].sin_port = Endpoint->AddressFile->Port;
+ Address->Address[0].Address[0].in_addr = Endpoint->AddressFile->Address.Address.IPv4Address;
+ RtlZeroMemory(
+ &Address->Address[0].Address[0].sin_zero,
+ sizeof(Address->Address[0].Address[0].sin_zero));
+ return STATUS_SUCCESS;
+
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ case TDI_QUERY_CONNECTION_INFO:
+ {
+ PTDI_CONNECTION_INFO ConnectionInfo;
+ PCONNECTION_ENDPOINT Endpoint;
+
+ if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*ConnectionInfo)) {
+ TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ConnectionInfo = (PTDI_CONNECTION_INFO)
+ MmGetSystemAddressForMdl(Irp->MdlAddress);
+
+ switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
+ case TDI_CONNECTION_FILE:
+ Endpoint =
+ (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+ RtlZeroMemory(ConnectionInfo, sizeof(*ConnectionInfo));
+ return STATUS_SUCCESS;
+
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ case TDI_QUERY_MAX_DATAGRAM_INFO:
+ {
+ PTDI_MAX_DATAGRAM_INFO MaxDatagramInfo;
+
+ if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*MaxDatagramInfo)) {
+ TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ MaxDatagramInfo = (PTDI_MAX_DATAGRAM_INFO)
+ MmGetSystemAddressForMdl(Irp->MdlAddress);
+
+ MaxDatagramInfo->MaxDatagramSize = 0xFFFF;
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiReceive(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_RECEIVE handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveInfo;
+ PTRANSPORT_CONTEXT TranContext;
+ NTSTATUS Status;
+ ULONG BytesReceived = 0;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ ReceiveInfo = (PTDI_REQUEST_KERNEL_RECEIVE)&(IrpSp->Parameters);
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (TranContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (TranContext->Handle.ConnectionContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* Initialize a receive request */
+ Status = DispPrepareIrpForCancel
+ (TranContext->Handle.ConnectionContext,
+ Irp,
+ (PDRIVER_CANCEL)DispCancelRequest);
+
+ TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
+ if (NT_SUCCESS(Status))
+ {
+ Status = TCPReceiveData(
+ TranContext->Handle.ConnectionContext,
+ (PNDIS_BUFFER)Irp->MdlAddress,
+ ReceiveInfo->ReceiveLength,
+ &BytesReceived,
+ ReceiveInfo->ReceiveFlags,
+ DispDataRequestComplete,
+ Irp);
+ }
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, BytesReceived);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiReceiveDatagram(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_RECEIVE_DATAGRAM handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo;
+ PTRANSPORT_CONTEXT TranContext;
+ TDI_REQUEST Request;
+ NTSTATUS Status;
+ ULONG BytesReceived = 0;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (TranContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* Initialize a receive request */
+ Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+ Request.RequestNotifyObject = DispDataRequestComplete;
+ Request.RequestContext = Irp;
+
+ Status = DispPrepareIrpForCancel(
+ IrpSp->FileObject->FsContext,
+ Irp,
+ (PDRIVER_CANCEL)DispCancelRequest);
+
+ if (NT_SUCCESS(Status))
+ {
+ PVOID DataBuffer;
+ UINT BufferSize;
+
+ NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
+ &DataBuffer,
+ &BufferSize );
+
+ Status = DGReceiveDatagram(
+ Request.Handle.AddressHandle,
+ DgramInfo->ReceiveDatagramInformation,
+ DataBuffer,
+ DgramInfo->ReceiveLength,
+ DgramInfo->ReceiveFlags,
+ DgramInfo->ReturnDatagramInformation,
+ &BytesReceived,
+ (PDATAGRAM_COMPLETION_ROUTINE)DispDataRequestComplete,
+ Irp,
+ Irp);
+ }
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, BytesReceived);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiSend(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_SEND handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_SEND SendInfo;
+ PTRANSPORT_CONTEXT TranContext;
+ NTSTATUS Status;
+ ULONG BytesSent = 0;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ SendInfo = (PTDI_REQUEST_KERNEL_SEND)&(IrpSp->Parameters);
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (TranContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (TranContext->Handle.ConnectionContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ Status = DispPrepareIrpForCancel(
+ IrpSp->FileObject->FsContext,
+ Irp,
+ (PDRIVER_CANCEL)DispCancelRequest);
+
+ TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
+ if (NT_SUCCESS(Status))
+ {
+ PVOID Data;
+ UINT Len;
+
+ NdisQueryBuffer( Irp->MdlAddress, &Data, &Len );
+
+ TI_DbgPrint(MID_TRACE,("About to TCPSendData\n"));
+ Status = TCPSendData(
+ TranContext->Handle.ConnectionContext,
+ Data,
+ SendInfo->SendLength,
+ &BytesSent,
+ SendInfo->SendFlags,
+ DispDataRequestComplete,
+ Irp);
+ }
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, BytesSent);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiSendDatagram(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_SEND_DATAGRAM handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PIO_STACK_LOCATION IrpSp;
+ TDI_REQUEST Request;
+ PTDI_REQUEST_KERNEL_SENDDG DgramInfo;
+ PTRANSPORT_CONTEXT TranContext;
+ NTSTATUS Status;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ DgramInfo = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters);
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (TranContext == NULL)
+ {
+ TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* Initialize a send request */
+ Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+ Request.RequestNotifyObject = DispDataRequestComplete;
+ Request.RequestContext = Irp;
+
+ Status = DispPrepareIrpForCancel(
+ IrpSp->FileObject->FsContext,
+ Irp,
+ (PDRIVER_CANCEL)DispCancelRequest);
+
+ if (NT_SUCCESS(Status)) {
+ PVOID DataBuffer;
+ UINT BufferSize;
+
+ TI_DbgPrint(MID_TRACE,("About to query buffer %x\n", Irp->MdlAddress));
+
+ NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
+ &DataBuffer,
+ &BufferSize );
+
+ /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress
+ must be of type PTDI_ADDRESS_IP */
+ TI_DbgPrint(MID_TRACE,
+ ("About to call send routine %x\n",
+ (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)));
+
+ if( (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send != NULL) )
+ {
+ ULONG DataUsed = 0;
+ Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
+ Request.Handle.AddressHandle,
+ DgramInfo->SendDatagramInformation,
+ DataBuffer,
+ BufferSize,
+ &DataUsed);
+ Irp->IoStatus.Information = DataUsed;
+ }
+ else {
+ Status = STATUS_UNSUCCESSFUL;
+ ASSERT(FALSE);
+ }
+ }
+
+done:
+ if (Status != STATUS_PENDING) {
+ DispDataRequestComplete(Irp, Status, Irp->IoStatus.Information);
+ } else
+ IoMarkIrpPending(Irp);
+
+ TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiSetEventHandler(PIRP Irp)
+/*
+ * FUNCTION: TDI_SET_EVENT_HANDER handler
+ * ARGUMENTS:
+ * Irp = Pointer to a I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PTRANSPORT_CONTEXT TranContext;
+ PIO_STACK_LOCATION IrpSp;
+ PADDRESS_FILE AddrFile;
+ NTSTATUS Status;
+ KIRQL OldIrql;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /* Get associated address file object. Quit if none exists */
+
+ TranContext = IrpSp->FileObject->FsContext;
+ if (!TranContext) {
+ TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
+ if (!AddrFile) {
+ TI_DbgPrint(MIN_TRACE, ("No address file object.\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
+ Status = STATUS_SUCCESS;
+
+ LockObject(AddrFile, &OldIrql);
+
+ /* Set the event handler. if an event handler is associated with
+ a specific event, it's flag (RegisteredXxxHandler) is TRUE.
+ If an event handler is not used it's flag is FALSE */
+ switch (Parameters->EventType) {
+ case TDI_EVENT_CONNECT:
+ if (!Parameters->EventHandler) {
+ AddrFile->ConnectHandlerContext = NULL;
+ AddrFile->RegisteredConnectHandler = FALSE;
+ } else {
+ AddrFile->ConnectHandler =
+ (PTDI_IND_CONNECT)Parameters->EventHandler;
+ AddrFile->ConnectHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredConnectHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+ if (!Parameters->EventHandler) {
+ AddrFile->DisconnectHandlerContext = NULL;
+ AddrFile->RegisteredDisconnectHandler = FALSE;
+ } else {
+ AddrFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)Parameters->EventHandler;
+ AddrFile->DisconnectHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredDisconnectHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_ERROR:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ErrorHandlerContext = NULL;
+ AddrFile->RegisteredErrorHandler = FALSE;
+ } else {
+ AddrFile->ErrorHandler =
+ (PTDI_IND_ERROR)Parameters->EventHandler;
+ AddrFile->ErrorHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredErrorHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_RECEIVE:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ReceiveHandlerContext = NULL;
+ AddrFile->RegisteredReceiveHandler = FALSE;
+ } else {
+ AddrFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)Parameters->EventHandler;
+ AddrFile->ReceiveHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredReceiveHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ReceiveDatagramHandlerContext = NULL;
+ AddrFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ AddrFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddrFile->ReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ExpeditedReceiveHandlerContext = NULL;
+ AddrFile->RegisteredExpeditedReceiveHandler = FALSE;
+ } else {
+ AddrFile->ExpeditedReceiveHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler;
+ AddrFile->ExpeditedReceiveHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredExpeditedReceiveHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_CHAINED_RECEIVE:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ChainedReceiveHandlerContext = NULL;
+ AddrFile->RegisteredChainedReceiveHandler = FALSE;
+ } else {
+ AddrFile->ChainedReceiveHandler =
+ (PTDI_IND_CHAINED_RECEIVE)Parameters->EventHandler;
+ AddrFile->ChainedReceiveHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredChainedReceiveHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ChainedReceiveDatagramHandlerContext = NULL;
+ AddrFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ } else {
+ AddrFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddrFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredChainedReceiveDatagramHandler = TRUE;
+ }
+ break;
+
+ case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
+ if (Parameters->EventHandler == NULL) {
+ AddrFile->ChainedReceiveExpeditedHandlerContext = NULL;
+ AddrFile->RegisteredChainedReceiveExpeditedHandler = FALSE;
+ } else {
+ AddrFile->ChainedReceiveExpeditedHandler =
+ (PTDI_IND_CHAINED_RECEIVE_EXPEDITED)Parameters->EventHandler;
+ AddrFile->ChainedReceiveExpeditedHandlerContext = Parameters->EventContext;
+ AddrFile->RegisteredChainedReceiveExpeditedHandler = TRUE;
+ }
+ break;
+
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Unknown event type (0x%X).\n",
+ Parameters->EventType));
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ UnlockObject(AddrFile, OldIrql);
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiSetInformation(
+ PIRP Irp)
+/*
+ * FUNCTION: TDI_SET_INFORMATION handler
+ * ARGUMENTS:
+ * Irp = Pointer to an I/O request packet
+ * RETURNS:
+ * Status of operation
+ */
+{
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+VOID DispTdiQueryInformationExComplete(
+ PVOID Context,
+ ULONG Status,
+ UINT ByteCount)
+/*
+ * FUNCTION: Completes a TDI QueryInformationEx request
+ * ARGUMENTS:
+ * Context = Pointer to the IRP for the request
+ * Status = TDI status of the request
+ * ByteCount = Number of bytes returned in output buffer
+ */
+{
+ PTI_QUERY_CONTEXT QueryContext;
+
+ QueryContext = (PTI_QUERY_CONTEXT)Context;
+ if (NT_SUCCESS(Status)) {
+ CopyBufferToBufferChain(
+ QueryContext->InputMdl,
+ FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
+ (PCHAR)&QueryContext->QueryInfo.Context,
+ CONTEXT_SIZE);
+ }
+
+ MmUnlockPages(QueryContext->InputMdl);
+ IoFreeMdl(QueryContext->InputMdl);
+ if( QueryContext->OutputMdl ) {
+ MmUnlockPages(QueryContext->OutputMdl);
+ IoFreeMdl(QueryContext->OutputMdl);
+ }
+
+ QueryContext->Irp->IoStatus.Information = ByteCount;
+ QueryContext->Irp->IoStatus.Status = Status;
+
+ ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
+}
+
+
+NTSTATUS DispTdiQueryInformationEx(
+ PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+/*
+ * FUNCTION: TDI QueryInformationEx handler
+ * ARGUMENTS:
+ * Irp = Pointer to I/O request packet
+ * IrpSp = Pointer to current stack location of Irp
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
+ PTRANSPORT_CONTEXT TranContext;
+ PTI_QUERY_CONTEXT QueryContext;
+ PVOID OutputBuffer;
+ TDI_REQUEST Request;
+ UINT Size;
+ UINT InputBufferLength;
+ UINT OutputBufferLength;
+ BOOLEAN InputMdlLocked = FALSE;
+ BOOLEAN OutputMdlLocked = FALSE;
+ PMDL InputMdl = NULL;
+ PMDL OutputMdl = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+
+ switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+ break;
+
+ case TDI_CONNECTION_FILE:
+ Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+ Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
+ break;
+
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ /* Validate parameters */
+ if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
+ (OutputBufferLength != 0)) {
+
+ InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
+ IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ OutputBuffer = Irp->UserBuffer;
+
+ QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
+ if (QueryContext) {
+ _SEH2_TRY {
+ InputMdl = IoAllocateMdl(InputBuffer,
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+ FALSE, TRUE, NULL);
+
+ OutputMdl = IoAllocateMdl(OutputBuffer,
+ OutputBufferLength, FALSE, TRUE, NULL);
+
+ if (InputMdl && OutputMdl) {
+
+ MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
+ IoModifyAccess);
+
+ InputMdlLocked = TRUE;
+
+ MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,
+ IoWriteAccess);
+
+ OutputMdlLocked = TRUE;
+
+ RtlCopyMemory(&QueryContext->QueryInfo,
+ InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
+ } else
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+ Status = _SEH2_GetExceptionCode();
+ } _SEH2_END;
+
+ if (NT_SUCCESS(Status)) {
+ Size = MmGetMdlByteCount(OutputMdl);
+
+ QueryContext->Irp = Irp;
+ QueryContext->InputMdl = InputMdl;
+ QueryContext->OutputMdl = OutputMdl;
+
+ Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
+ Request.RequestContext = QueryContext;
+ Status = InfoTdiQueryInformationEx(&Request,
+ &QueryContext->QueryInfo.ID, OutputMdl,
+ &Size, &QueryContext->QueryInfo.Context);
+ DispTdiQueryInformationExComplete(QueryContext, Status, Size);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
+
+ return Status;
+ }
+
+ /* An error occurred if we get here */
+
+ if (InputMdl) {
+ if (InputMdlLocked)
+ MmUnlockPages(InputMdl);
+ IoFreeMdl(InputMdl);
+ }
+
+ if (OutputMdl) {
+ if (OutputMdlLocked)
+ MmUnlockPages(OutputMdl);
+ IoFreeMdl(OutputMdl);
+ }
+
+ ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
+ } else
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ } else if( InputBufferLength ==
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) ) {
+ /* Handle the case where the user is probing the buffer for length */
+ TI_DbgPrint(MAX_TRACE, ("InputBufferLength %d OutputBufferLength %d\n",
+ InputBufferLength, OutputBufferLength));
+ InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
+ IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ Size = 0;
+
+ QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
+ if (!QueryContext) return STATUS_INSUFFICIENT_RESOURCES;
+
+ _SEH2_TRY {
+ InputMdl = IoAllocateMdl(InputBuffer,
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+ FALSE, TRUE, NULL);
+
+ MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
+ IoModifyAccess);
+
+ InputMdlLocked = TRUE;
+ Status = STATUS_SUCCESS;
+ } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+ TI_DbgPrint(MAX_TRACE, ("Failed to acquire client buffer\n"));
+ Status = _SEH2_GetExceptionCode();
+ } _SEH2_END;
+
+ if( !NT_SUCCESS(Status) || !InputMdl ) {
+ if( InputMdl ) IoFreeMdl( InputMdl );
+ ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
+ return Status;
+ }
+
+ RtlCopyMemory(&QueryContext->QueryInfo,
+ InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
+
+ QueryContext->Irp = Irp;
+ QueryContext->InputMdl = InputMdl;
+ QueryContext->OutputMdl = NULL;
+
+ Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
+ Request.RequestContext = QueryContext;
+ Status = InfoTdiQueryInformationEx(&Request,
+ &QueryContext->QueryInfo.ID,
+ NULL,
+ &Size,
+ &QueryContext->QueryInfo.Context);
+ DispTdiQueryInformationExComplete(QueryContext, Status, Size);
+ TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
+ } else Status = STATUS_INVALID_PARAMETER;
+
+ TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));
+
+ return Status;
+}
+
+
+NTSTATUS DispTdiSetInformationEx(
+ PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+/*
+ * FUNCTION: TDI SetInformationEx handler
+ * ARGUMENTS:
+ * Irp = Pointer to I/O request packet
+ * IrpSp = Pointer to current stack location of Irp
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PTRANSPORT_CONTEXT TranContext;
+ PTCP_REQUEST_SET_INFORMATION_EX Info;
+ TDI_REQUEST Request;
+ TDI_STATUS Status;
+
+ TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+ TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+ Info = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
+
+ switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+ break;
+
+ case TDI_CONNECTION_FILE:
+ Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+ Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
+ break;
+
+ default:
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+
+ TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+ return Irp->IoStatus.Status;
+ }
+
+ Status = DispPrepareIrpForCancel(TranContext, Irp, NULL);
+ if (NT_SUCCESS(Status)) {
+ Request.RequestNotifyObject = DispDataRequestComplete;
+ Request.RequestContext = Irp;
+
+ Status = InfoTdiSetInformationEx(&Request, &Info->ID,
+ &Info->Buffer, Info->BufferSize);
+ }
+
+ return Status;
+}
+
+/* TODO: Support multiple addresses per interface.
+ * For now just set the nte context to the interface index.
+ *
+ * Later on, create an NTE context and NTE instance
+ */
+
+NTSTATUS DispTdiSetIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
+ NTSTATUS Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ PIP_SET_ADDRESS IpAddrChange =
+ (PIP_SET_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
+ IF_LIST_ITER(IF);
+
+ TI_DbgPrint(MID_TRACE,("Setting IP Address for adapter %d\n",
+ IpAddrChange->NteIndex));
+
+ ForEachInterface(IF) {
+ TI_DbgPrint(MID_TRACE,("Looking at adapter %d\n", IF->Index));
+
+ if( IF->Unicast.Address.IPv4Address == IpAddrChange->Address ) {
+ Status = STATUS_DUPLICATE_OBJECTID;
+ break;
+ }
+ if( IF->Index == IpAddrChange->NteIndex ) {
+ IPRemoveInterfaceRoute( IF );
+
+ IF->Unicast.Type = IP_ADDRESS_V4;
+ IF->Unicast.Address.IPv4Address = IpAddrChange->Address;
+ IF->Netmask.Type = IP_ADDRESS_V4;
+ IF->Netmask.Address.IPv4Address = IpAddrChange->Netmask;
+ IF->Broadcast.Type = IP_ADDRESS_V4;
+ IF->Broadcast.Address.IPv4Address =
+ IF->Unicast.Address.IPv4Address |
+ ~IF->Netmask.Address.IPv4Address;
+
+ TI_DbgPrint(MID_TRACE,("New Unicast Address: %x\n",
+ IF->Unicast.Address.IPv4Address));
+ TI_DbgPrint(MID_TRACE,("New Netmask : %x\n",
+ IF->Netmask.Address.IPv4Address));
+
+ IPAddInterfaceRoute( IF );
+
+ IpAddrChange->Address = IF->Index;
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = IF->Index;
+ break;
+ }
+ } EndFor(IF);
+
+ Irp->IoStatus.Status = Status;
+ return Status;
+}
+
+NTSTATUS DispTdiDeleteIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PUSHORT NteIndex = Irp->AssociatedIrp.SystemBuffer;
+ IF_LIST_ITER(IF);
+
+ ForEachInterface(IF) {
+ if( IF->Index == *NteIndex ) {
+ IPRemoveInterfaceRoute( IF );
+ IF->Unicast.Type = IP_ADDRESS_V4;
+ IF->Unicast.Address.IPv4Address = 0;
+ IF->Netmask.Type = IP_ADDRESS_V4;
+ IF->Netmask.Address.IPv4Address = 0;
+ IF->Broadcast.Type = IP_ADDRESS_V4;
+ IF->Broadcast.Address.IPv4Address = 0;
+ Status = STATUS_SUCCESS;
+ }
+ } EndFor(IF);
+
+ Irp->IoStatus.Status = Status;
+ return Status;
+}
+
+/* EOF */
--- /dev/null
- AddrFile->Listener->AddressFile = NULL;
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: tcpip/fileobjs.c
+ * PURPOSE: Routines for handling file objects
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+
+/* List of all address file objects managed by this driver */
+LIST_ENTRY AddressFileListHead;
+KSPIN_LOCK AddressFileListLock;
+
+/* List of all connection endpoint file objects managed by this driver */
+LIST_ENTRY ConnectionEndpointListHead;
+KSPIN_LOCK ConnectionEndpointListLock;
+
+/*
+ * FUNCTION: Searches through address file entries to find the first match
+ * ARGUMENTS:
+ * Address = IP address
+ * Port = Port number
+ * Protocol = Protocol number
+ * SearchContext = Pointer to search context
+ * RETURNS:
+ * Pointer to address file, NULL if none was found
+ */
+PADDRESS_FILE AddrSearchFirst(
+ PIP_ADDRESS Address,
+ USHORT Port,
+ USHORT Protocol,
+ PAF_SEARCH SearchContext)
+{
+ SearchContext->Address = Address;
+ SearchContext->Port = Port;
+ SearchContext->Next = AddressFileListHead.Flink;
+ SearchContext->Protocol = Protocol;
+
+ return AddrSearchNext(SearchContext);
+}
+
+BOOLEAN AddrIsBroadcastMatch(
+ PIP_ADDRESS UnicastAddress,
+ PIP_ADDRESS BroadcastAddress ) {
+ IF_LIST_ITER(IF);
+
+ ForEachInterface(IF) {
+ if ((AddrIsUnspecified(UnicastAddress) ||
+ AddrIsEqual(&IF->Unicast, UnicastAddress)) &&
+ (AddrIsEqual(&IF->Broadcast, BroadcastAddress)))
+ return TRUE;
+ } EndFor(IF);
+
+ return FALSE;
+}
+
+BOOLEAN AddrReceiveMatch(
+ PIP_ADDRESS LocalAddress,
+ PIP_ADDRESS RemoteAddress)
+{
+ if (AddrIsEqual(LocalAddress, RemoteAddress))
+ {
+ /* Unicast address match */
+ return TRUE;
+ }
+
+ if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress))
+ {
+ /* Broadcast address match */
+ return TRUE;
+ }
+
+ if (AddrIsUnspecified(LocalAddress))
+ {
+ /* Local address unspecified */
+ return TRUE;
+ }
+
+ if (AddrIsUnspecified(RemoteAddress))
+ {
+ /* Remote address unspecified */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * FUNCTION: Searches through address file entries to find next match
+ * ARGUMENTS:
+ * SearchContext = Pointer to search context
+ * RETURNS:
+ * Pointer to address file, NULL if none was found
+ */
+PADDRESS_FILE AddrSearchNext(
+ PAF_SEARCH SearchContext)
+{
+ PLIST_ENTRY CurrentEntry;
+ PIP_ADDRESS IPAddress;
+ KIRQL OldIrql;
+ PADDRESS_FILE Current = NULL;
+ BOOLEAN Found = FALSE;
+
+ if (IsListEmpty(SearchContext->Next))
+ return NULL;
+
+ CurrentEntry = SearchContext->Next;
+
+ TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+
+ while (CurrentEntry != &AddressFileListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
+
+ IPAddress = &Current->Address;
+
+ TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
+ WN2H(Current->Port),
+ Current->Protocol,
+ A2S(IPAddress),
+ WN2H(SearchContext->Port),
+ SearchContext->Protocol,
+ A2S(SearchContext->Address)));
+
+ /* See if this address matches the search criteria */
+ if ((Current->Port == SearchContext->Port) &&
+ (Current->Protocol == SearchContext->Protocol) &&
+ (AddrReceiveMatch(IPAddress, SearchContext->Address))) {
+ /* We've found a match */
+ Found = TRUE;
+ break;
+ }
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+ if (Found) {
+ SearchContext->Next = CurrentEntry->Flink;
+ return Current;
+ } else
+ return NULL;
+}
+
+VOID AddrFileFree(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an address file object
+ * ARGUMENTS:
+ * Object = Pointer to address file object to free
+ */
+{
+ PADDRESS_FILE AddrFile = Object;
+ KIRQL OldIrql;
+ PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
+ PDATAGRAM_SEND_REQUEST SendRequest;
+ PLIST_ENTRY CurrentEntry;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ /* We should not be associated with a connection here */
+ ASSERT(!AddrFile->Connection);
+
+ /* Remove address file from the global list */
+ TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+ RemoveEntryList(&AddrFile->ListEntry);
+ TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+ /* FIXME: Kill TCP connections on this address file object */
+
+ /* Return pending requests with error */
+
+ TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
+
+ /* Go through pending receive request list and cancel them all */
+ while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
+ ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
+ (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0);
+ /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
+ }
+
+ TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
+
+ /* Go through pending send request list and cancel them all */
+ while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
+ SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+ (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0);
+ ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG);
+ }
+
+ /* Protocol specific handling */
+ switch (AddrFile->Protocol) {
+ case IPPROTO_TCP:
+ if (AddrFile->Port)
+ {
+ TCPFreePort(AddrFile->Port);
+ }
+ break;
+
+ case IPPROTO_UDP:
+ UDPFreePort( AddrFile->Port );
+ break;
+ }
+
+ RemoveEntityByContext(AddrFile);
+
+ ExFreePoolWithTag(Object, ADDR_FILE_TAG);
+}
+
+
+VOID ControlChannelFree(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an address file object
+ * ARGUMENTS:
+ * Object = Pointer to address file object to free
+ */
+{
+ ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG);
+}
+
+
+/*
+ * FUNCTION: Open an address file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * Address = Pointer to address to be opened
+ * Protocol = Protocol on which to open the address
+ * Options = Pointer to option buffer
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileOpenAddress(
+ PTDI_REQUEST Request,
+ PTA_IP_ADDRESS Address,
+ USHORT Protocol,
+ PVOID Options)
+{
+ PADDRESS_FILE AddrFile;
+
+ TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
+
+ AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE),
+ ADDR_FILE_TAG);
+ if (!AddrFile) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
+
+ AddrFile->RefCount = 1;
+ AddrFile->Free = AddrFileFree;
+
+ /* Set our default options */
+ AddrFile->TTL = 128;
+ AddrFile->DF = 0;
+ AddrFile->BCast = 1;
+ AddrFile->HeaderIncl = 1;
+
+ /* Make sure address is a local unicast address or 0 */
+ /* FIXME: IPv4 only */
+ AddrFile->Family = Address->Address[0].AddressType;
+ AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr;
+ AddrFile->Address.Type = IP_ADDRESS_V4;
+
+ if (!AddrIsUnspecified(&AddrFile->Address) &&
+ !AddrLocateInterface(&AddrFile->Address)) {
+ ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+ TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address)));
+ return STATUS_INVALID_ADDRESS;
+ }
+
+ TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
+ A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
+
+ /* Protocol specific handling */
+ switch (Protocol) {
+ case IPPROTO_TCP:
+ if (Address->Address[0].Address[0].sin_port)
+ {
+ /* The client specified an explicit port so we force a bind to this */
+ AddrFile->Port = TCPAllocatePort(Address->Address[0].Address[0].sin_port);
+
+ /* Check for bind success */
+ if (AddrFile->Port == 0xffff)
+ {
+ ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+ return STATUS_ADDRESS_ALREADY_EXISTS;
+ }
+
+ /* Sanity check */
+ ASSERT(Address->Address[0].Address[0].sin_port == AddrFile->Port);
+ }
+ else if (!AddrIsUnspecified(&AddrFile->Address))
+ {
+ /* The client is trying to bind to a local address so allocate a port now too */
+ AddrFile->Port = TCPAllocatePort(0);
+
+ /* Check for bind success */
+ if (AddrFile->Port == 0xffff)
+ {
+ ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+ return STATUS_ADDRESS_ALREADY_EXISTS;
+ }
+ }
+ else
+ {
+ /* The client wants an unspecified port with an unspecified address so we wait to see what the TCP library gives us */
+ AddrFile->Port = 0;
+ }
+
+ AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP);
+
+ AddrFile->Send = NULL; /* TCPSendData */
+ break;
+
+ case IPPROTO_UDP:
+ TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
+ AddrFile->Port =
+ UDPAllocatePort(Address->Address[0].Address[0].sin_port);
+
+ if ((Address->Address[0].Address[0].sin_port &&
+ AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
+ AddrFile->Port == 0xffff)
+ {
+ ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+ return STATUS_ADDRESS_ALREADY_EXISTS;
+ }
+
+ TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
+ AddrFile->Port,
+ Address->Address[0].Address[0].sin_port));
+
+ AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP);
+
+ AddrFile->Send = UDPSendDatagram;
+ break;
+
+ case IPPROTO_ICMP:
+ AddrFile->Port = 0;
+ AddrFile->Send = ICMPSendDatagram;
+
+ /* FIXME: Verify this */
+ AddEntity(ER_ENTITY, AddrFile, ER_ICMP);
+ break;
+
+ default:
+ /* Use raw IP for all other protocols */
+ AddrFile->Port = 0;
+ AddrFile->Send = RawIPSendDatagram;
+
+ /* FIXME: Verify this */
+ AddEntity(CL_TL_ENTITY, AddrFile, 0);
+ break;
+ }
+
+ TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
+ Protocol));
+
+ TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
+ WN2H(AddrFile->Port)));
+
+ /* Set protocol */
+ AddrFile->Protocol = Protocol;
+
+ /* Initialize receive and transmit queues */
+ InitializeListHead(&AddrFile->ReceiveQueue);
+ InitializeListHead(&AddrFile->TransmitQueue);
+
+ /* Initialize spin lock that protects the address file object */
+ KeInitializeSpinLock(&AddrFile->Lock);
+
+ /* Return address file object */
+ Request->Handle.AddressHandle = AddrFile;
+
+ /* Add address file to global list */
+ ExInterlockedInsertTailList(
+ &AddressFileListHead,
+ &AddrFile->ListEntry,
+ &AddressFileListLock);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+/*
+ * FUNCTION: Closes an address file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileCloseAddress(
+ PTDI_REQUEST Request)
+{
+ PADDRESS_FILE AddrFile = Request->Handle.AddressHandle;
+ KIRQL OldIrql;
+
+ if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER;
+
+ LockObject(AddrFile, &OldIrql);
+
+ /* We have to close this listener because we started it */
+ if( AddrFile->Listener )
+ {
+ TCPClose( AddrFile->Listener );
+ }
+
+ UnlockObject(AddrFile, OldIrql);
+
+ DereferenceObject(AddrFile);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+/*
+ * FUNCTION: Opens a connection file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * ClientContext = Pointer to client context information
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileOpenConnection(
+ PTDI_REQUEST Request,
+ PVOID ClientContext)
+{
+ NTSTATUS Status;
+ PCONNECTION_ENDPOINT Connection;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ Connection = TCPAllocateConnectionEndpoint( ClientContext );
+
+ if( !Connection ) return STATUS_NO_MEMORY;
+
+ Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
+
+ if( !NT_SUCCESS(Status) ) {
+ DereferenceObject( Connection );
+ return Status;
+ }
+
+ /* Return connection endpoint file object */
+ Request->Handle.ConnectionContext = Connection;
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Closes an connection file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileCloseConnection(
+ PTDI_REQUEST Request)
+{
+ PCONNECTION_ENDPOINT Connection;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ Connection = Request->Handle.ConnectionContext;
+
+ if (!Connection) return STATUS_INVALID_PARAMETER;
+
+ TCPClose( Connection );
+
+ Request->Handle.ConnectionContext = NULL;
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Opens a control channel file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileOpenControlChannel(
+ PTDI_REQUEST Request)
+{
+ PCONTROL_CHANNEL ControlChannel;
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel),
+ CONTROL_CHANNEL_TAG);
+
+ if (!ControlChannel) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
+
+ /* Make sure address is a local unicast address or 0 */
+
+ /* Locate address entry. If specified address is 0, a random address is chosen */
+
+ /* Initialize receive and transmit queues */
+ InitializeListHead(&ControlChannel->ListEntry);
+
+ /* Initialize spin lock that protects the address file object */
+ KeInitializeSpinLock(&ControlChannel->Lock);
+
+ ControlChannel->RefCount = 1;
+ ControlChannel->Free = ControlChannelFree;
+
+ /* Return address file object */
+ Request->Handle.ControlChannel = ControlChannel;
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Closes a control channel file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileCloseControlChannel(
+ PTDI_REQUEST Request)
+{
+ if (!Request->Handle.ControlChannel) return STATUS_INVALID_PARAMETER;
+
+ DereferenceObject((PCONTROL_CHANNEL)Request->Handle.ControlChannel);
+
+ Request->Handle.ControlChannel = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
- <directory name="oskittcp">
- <xi:include href="oskittcp/oskittcp.rbuild" />
+<?xml version="1.0"?>
+<!DOCTYPE group SYSTEM "../../tools/rbuild/project.dtd">
+<group xmlns:xi="http://www.w3.org/2001/XInclude">
+ <directory name="csq">
+ <xi:include href="csq/csq.rbuild" />
+ </directory>
+ <directory name="ip">
+ <xi:include href="ip/ip.rbuild" />
+ </directory>
++ <directory name="lwip">
++ <xi:include href="lwip/lwip.rbuild" />
+ </directory>
+ <directory name="chew">
+ <xi:include href="chew/chew.rbuild" />
+ </directory>
+ <directory name="sound">
+ <xi:include href="sound/sound.rbuild" />
+ </directory>
+</group>
--- /dev/null
- <include base="oskittcp">include</include>
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<module name="ip" type="staticlibrary">
+ <define name="__NTDRIVER__"/>
+ <include base="tcpip">include</include>
++ <include base="lwip">src/include</include>
++ <include base="lwip">src/include/ipv4</include>
+ <directory name="network">
+ <if property="ARCH" value="i386">
+ <directory name="i386">
+ <file>checksum.S</file>
+ </directory>
+ </if>
+ <file>address.c</file>
+ <file>arp.c</file>
+ <file>checksum.c</file>
+ <file>icmp.c</file>
+ <file>interface.c</file>
+ <file>ip.c</file>
+ <file>loopback.c</file>
+ <file>neighbor.c</file>
+ <file>ports.c</file>
+ <file>receive.c</file>
+ <file>router.c</file>
+ <file>routines.c</file>
+ <file>transmit.c</file>
+ </directory>
+ <directory name="transport">
+ <directory name="datagram">
+ <file>datagram.c</file>
+ </directory>
+ <directory name="rawip">
+ <file>rawip.c</file>
+ </directory>
+ <directory name="tcp">
+ <file>accept.c</file>
+ <file>event.c</file>
+ <file>if.c</file>
+ <file>tcp.c</file>
+ </directory>
+ <directory name="udp">
+ <file>udp.c</file>
+ </directory>
+ </directory>
+ <pch>precomp.h</pch>
+</module>
--- /dev/null
- static VOID DisplayTCPHeader(
- PCHAR Header,
- UINT Length)
- {
- /* FIXME: IPv4 only */
- PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header;
- PTCPv4_HEADER TCPHeader;
-
- if (IPHeader->Protocol != IPPROTO_TCP) {
- DbgPrint("This is not a TCP datagram. Protocol is %d\n", IPHeader->Protocol);
- return;
- }
-
- TCPHeader = (PTCPv4_HEADER)((PCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4);
-
- DbgPrint("TCP header:\n");
- DbgPrint(" SourcePort: %d\n", WN2H(TCPHeader->SourcePort));
- 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 - 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: 0x%x\n", WN2H(TCPHeader->Window));
- DbgPrint(" Checksum: 0x%x\n", WN2H(TCPHeader->Checksum));
- DbgPrint(" Urgent: 0x%x\n", WN2H(TCPHeader->Urgent));
- }
-
-
- VOID DisplayTCPPacket(
- PIP_PACKET IPPacket)
- {
- UINT Length;
- PCHAR Buffer;
-
- if ((DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_PBUFFER | DPFLTR_MASK) != TRUE) ||
- (DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_TCP | DPFLTR_MASK) != TRUE)) {
- return;
- }
-
- if (!IPPacket) {
- TI_DbgPrint(MIN_TRACE, ("Cannot display null packet.\n"));
- return;
- }
-
- DisplayIPPacket(IPPacket);
-
- TI_DbgPrint(MIN_TRACE, ("IPPacket is at (0x%X).\n", IPPacket));
- TI_DbgPrint(MIN_TRACE, ("Header buffer is at (0x%X).\n", IPPacket->Header));
- TI_DbgPrint(MIN_TRACE, ("Header size is (%d).\n", IPPacket->HeaderSize));
- TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
- TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
- TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
-
- if (IPPacket->NdisPacket) {
- NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length);
- Buffer = ExAllocatePool(NonPagedPool, Length);
- if (Buffer) {
- Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, 0, Length);
- DisplayTCPHeader(Buffer, Length);
- ExFreePool(Buffer);
- }
- } else {
- Buffer = IPPacket->Header;
- Length = IPPacket->ContigSize;
- DisplayTCPHeader(Buffer, Length);
- }
- }
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: tcpip/routines.c
+ * PURPOSE: Common routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+static UINT RandomNumber = 0x12345678;
+
+
+UINT Random(
+ VOID)
+/*
+ * FUNCTION: Returns a pseudo random number
+ * RETURNS:
+ * Pseudo random number
+ */
+{
+ RandomNumber ^= 0x78563412;
+
+ return RandomNumber;
+}
+
+#if DBG
+static VOID DisplayIPHeader(
+ PCHAR 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));
+}
+
+#endif
+
+VOID DisplayIPPacket(
+ PIP_PACKET IPPacket)
+{
+#if DBG
+ PCHAR p;
+ UINT Length;
+ PNDIS_BUFFER Buffer;
+ PNDIS_BUFFER NextBuffer;
+ PCHAR CharBuffer;
+
+ if ((DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_PBUFFER | DPFLTR_MASK) != TRUE) ||
+ (DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_IP | DPFLTR_MASK) != TRUE)) {
+ return;
+ }
+
+ if (!IPPacket) {
+ TI_DbgPrint(MIN_TRACE, ("Cannot display null packet.\n"));
+ return;
+ }
+
+ TI_DbgPrint(MIN_TRACE, ("IPPacket is at (0x%X).\n", IPPacket));
+ TI_DbgPrint(MIN_TRACE, ("Header buffer is at (0x%X).\n", IPPacket->Header));
+ TI_DbgPrint(MIN_TRACE, ("Header size is (%d).\n", IPPacket->HeaderSize));
+ TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
+ TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
+ TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
+
+ if (IPPacket->NdisPacket) {
+ NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, &Buffer, NULL);
+ for (; Buffer != NULL; Buffer = NextBuffer) {
+ NdisGetNextBuffer(Buffer, &NextBuffer);
+ NdisQueryBuffer(Buffer, (PVOID)&p, &Length);
+ //OskitDumpBuffer( p, Length );
+ }
+ } else {
+ p = IPPacket->Header;
+ Length = IPPacket->ContigSize;
+ //OskitDumpBuffer( p, Length );
+ }
+
+ CharBuffer = IPPacket->Header;
+ Length = IPPacket->ContigSize;
+ DisplayIPHeader(CharBuffer, Length);
+#endif
+}
+
--- /dev/null
- * PURPOSE: Transmission Control Protocol -- Events from oskittcp
- * PROGRAMMERS: Art Yerkes
- * REVISIONS:
- * CSH 01/08-2000 Created
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: transport/tcp/event.c
- int TCPSocketState(void *ClientData,
- void *WhichSocket,
- void *WhichConnection,
- OSK_UINT NewState ) {
- PCONNECTION_ENDPOINT Connection = WhichConnection;
-
- TI_DbgPrint(DEBUG_TCP,("Connection: %x Flags: %c%c%c%c%c\n",
- Connection,
- NewState & SEL_CONNECT ? 'C' : 'c',
- NewState & SEL_READ ? 'R' : 'r',
- NewState & SEL_FIN ? 'F' : 'f',
- NewState & SEL_ACCEPT ? 'A' : 'a',
- NewState & SEL_WRITE ? 'W' : 'w'));
-
- /* If this socket is missing its socket context, that means that it
- * has been created as a new connection in sonewconn but not accepted
- * yet. We can safely ignore event notifications on these sockets.
- * Once they are accepted, they will get a socket context and we will
- * be able to process them.
- */
- if (!Connection)
- return 0;
-
- TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n",
- NewState, Connection,
- Connection->SignalState ^ NewState,
- NewState));
-
- Connection->SignalState = NewState;
-
- HandleSignalledConnection(Connection);
-
- return 0;
++ * PURPOSE: Transmission Control Protocol
++ * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
+ */
+
+#include "precomp.h"
+
- void TCPPacketSendComplete( PVOID Context,
- PNDIS_PACKET NdisPacket,
- NDIS_STATUS NdisStatus ) {
- TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket));
- FreeNdisPacket(NdisPacket);
- TI_DbgPrint(DEBUG_TCP,("done\n"));
++#include "lwip/err.h"
++#include "lwip/sys.h"
++#include "lwip/pbuf.h"
++#include "lwip/tcp.h"
++#include "lwip/api.h"
++
++#include "rosip.h"
++
++static const char * const tcp_state_str[] = {
++ "CLOSED",
++ "LISTEN",
++ "SYN_SENT",
++ "SYN_RCVD",
++ "ESTABLISHED",
++ "FIN_WAIT_1",
++ "FIN_WAIT_2",
++ "CLOSE_WAIT",
++ "CLOSING",
++ "LAST_ACK",
++ "TIME_WAIT"
++};
++
++static
++VOID
++BucketCompletionWorker(PVOID Context)
++{
++ PTDI_BUCKET Bucket = (PTDI_BUCKET)Context;
++ PTCP_COMPLETION_ROUTINE Complete;
++
++ Complete = (PTCP_COMPLETION_ROUTINE)Bucket->Request.RequestNotifyObject;
++
++ Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
++
++ DereferenceObject(Bucket->AssociatedEndpoint);
++
++ ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
+}
+
- #define STRINGIFY(x) #x
++VOID
++CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous)
++{
++ ReferenceObject(Connection);
++ Bucket->AssociatedEndpoint = Connection;
++ if (Synchronous)
++ {
++ BucketCompletionWorker(Bucket);
++ }
++ else
++ {
++ ChewCreate(BucketCompletionWorker, Bucket);
++ }
+}
+
- int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
- NDIS_STATUS NdisStatus;
- PNEIGHBOR_CACHE_ENTRY NCE;
- IP_PACKET Packet = { 0 };
- IP_ADDRESS RemoteAddress, LocalAddress;
- PIPv4_HEADER Header;
++VOID
++FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
++{
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++
++ ReferenceObject(Connection);
++
++ if (interlocked)
++ {
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
++ {
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ TI_DbgPrint(DEBUG_TCP,
++ ("Completing Receive request: %x %x\n",
++ Bucket->Request, Status));
++
++ Bucket->Status = Status;
++ Bucket->Information = 0;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
++ }
++ else
++ {
++ while (!IsListEmpty(&Connection->ReceiveRequest))
++ {
++ Entry = RemoveHeadList(&Connection->ReceiveRequest);
++
++ Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
++
++ Bucket->Information = 0;
++ Bucket->Status = Status;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
++ }
++
++ DereferenceObject(Connection);
++}
+
- if( *data == 0x45 ) { /* IPv4 */
- Header = (PIPv4_HEADER)data;
- LocalAddress.Type = IP_ADDRESS_V4;
- LocalAddress.Address.IPv4Address = Header->SrcAddr;
- RemoteAddress.Type = IP_ADDRESS_V4;
- RemoteAddress.Address.IPv4Address = Header->DstAddr;
- } else {
- TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n"));
- OskitDumpBuffer( data, len );
- return OSK_EINVAL;
++VOID
++FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
++{
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++
++ ReferenceObject(Connection);
+
-
- if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
- TI_DbgPrint(MIN_TRACE,("Unable to get route to %s\n", A2S(&RemoteAddress)));
- return OSK_EADDRNOTAVAIL;
++ if (interlocked)
++ {
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
++ {
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ TI_DbgPrint(DEBUG_TCP,
++ ("Completing Send request: %x %x\n",
++ Bucket->Request, Status));
++
++ Bucket->Status = Status;
++ Bucket->Information = 0;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
+ }
- NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL, len );
++ else
++ {
++ while (!IsListEmpty(&Connection->SendRequest))
++ {
++ Entry = RemoveHeadList(&Connection->SendRequest);
++
++ Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
++
++ Bucket->Information = 0;
++ Bucket->Status = Status;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
+ }
+
- if (NdisStatus != NDIS_STATUS_SUCCESS) {
- TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus));
- return OSK_ENOBUFS;
- }
++ DereferenceObject(Connection);
++}
+
- GetDataPtr( Packet.NdisPacket, 0,
- (PCHAR *)&Packet.Header, &Packet.ContigSize );
++VOID
++FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
++{
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++
++ ReferenceObject(Connection);
+
- RtlCopyMemory( Packet.Header, data, len );
++ if (interlocked)
++ {
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->ShutdownRequest, &Connection->Lock)))
++ {
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Bucket->Status = Status;
++ Bucket->Information = 0;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
++ }
++ else
++ {
++ while (!IsListEmpty(&Connection->ShutdownRequest))
++ {
++ Entry = RemoveHeadList(&Connection->ShutdownRequest);
++
++ Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
++
++ Bucket->Information = 0;
++ Bucket->Status = Status;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
++ }
+
- Packet.HeaderSize = sizeof(IPv4_HEADER);
- Packet.TotalSize = len;
- Packet.SrcAddr = LocalAddress;
- Packet.DstAddr = RemoteAddress;
++ DereferenceObject(Connection);
++}
+
- if (!NT_SUCCESS(IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL )))
++VOID
++FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
++{
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++
++ ReferenceObject(Connection);
+
- FreeNdisPacket(Packet.NdisPacket);
- return OSK_EINVAL;
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
+ {
- return 0;
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Bucket->Status = Status;
++ Bucket->Information = 0;
++
++ CompleteBucket(Connection, Bucket, FALSE);
+ }
+
- /* Memory management routines
- *
- * By far the most requests for memory are either for 128 or 2049 byte blocks,
- * so we want to satisfy those from lookaside lists. Unfortunately, the
- * TCPFree() function doesn't pass the size of the block to be freed, so we
- * need to keep track of it ourselves. We do it by prepending each block with
- * 4 bytes, indicating if this is a 'L'arge (2049), 'S'mall (128) or 'O'ther
- * block.
- */
++ DereferenceObject(Connection);
+}
+
- /* Set to some non-zero value to get a profile of memory allocation sizes */
- #define MEM_PROFILE 0
++VOID
++FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
++{
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++
++ ReferenceObject(Connection);
+
- #define SMALL_SIZE 128
- #define LARGE_SIZE 2049
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
++ {
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Bucket->Status = Status;
++ Bucket->Information = 0;
++
++ DereferenceObject(Bucket->AssociatedEndpoint);
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
+
- #define SIGNATURE_LARGE 'LLLL'
- #define SIGNATURE_SMALL 'SSSS'
- #define SIGNATURE_OTHER 'OOOO'
- static NPAGED_LOOKASIDE_LIST LargeLookasideList;
- static NPAGED_LOOKASIDE_LIST SmallLookasideList;
++ DereferenceObject(Connection);
++}
+
- NTSTATUS
- TCPMemStartup( void )
- {
- ExInitializeNPagedLookasideList( &LargeLookasideList,
- NULL,
- NULL,
- 0,
- LARGE_SIZE + sizeof( ULONG ),
- OSK_LARGE_TAG,
- 0 );
- ExInitializeNPagedLookasideList( &SmallLookasideList,
- NULL,
- NULL,
- 0,
- SMALL_SIZE + sizeof( ULONG ),
- OSK_SMALL_TAG,
- 0 );
-
- return STATUS_SUCCESS;
++VOID
++FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
++{
++ ReferenceObject(Connection);
++
++ // flush receive queue
++ FlushReceiveQueue(Connection, Status, TRUE);
+
- void *TCPMalloc( void *ClientData,
- OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
- void *v;
- ULONG Signature;
-
- #if 0 != MEM_PROFILE
- static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0;
- static OSK_UINT ArrayUsed = 0, AllocationCount = 0;
- OSK_UINT i, NewSize, *NewArray;
- int Found;
-
- Found = 0;
- for ( i = 0; i < ArrayUsed && ! Found; i++ ) {
- Found = ( Sizes[i] == Bytes );
- if ( Found ) {
- Counts[i]++;
- }
- }
- if ( ! Found ) {
- if ( ArrayAllocated <= ArrayUsed ) {
- NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated );
- NewArray = exAllocatePool( NonPagedPool, 2 * NewSize * sizeof( OSK_UINT ) );
- if ( NULL != NewArray ) {
- if ( 0 != ArrayAllocated ) {
- memcpy( NewArray, Sizes,
- ArrayAllocated * sizeof( OSK_UINT ) );
- exFreePool( Sizes );
- memcpy( NewArray + NewSize, Counts,
- ArrayAllocated * sizeof( OSK_UINT ) );
- exFreePool( Counts );
++ /* We completed the reads successfully but we need to return failure now */
++ if (Status == STATUS_SUCCESS)
++ {
++ Status = STATUS_FILE_CLOSED;
++ }
++
++ // flush listen queue
++ FlushListenQueue(Connection, Status);
++
++ // flush send queue
++ FlushSendQueue(Connection, Status, TRUE);
++
++ // flush connect queue
++ FlushConnectQueue(Connection, Status);
++
++ // flush shutdown queue
++ FlushShutdownQueue(Connection, Status, TRUE);
++
++ DereferenceObject(Connection);
+}
+
- Sizes = NewArray;
- Counts = NewArray + NewSize;
- ArrayAllocated = NewSize;
- } else if ( 0 != ArrayAllocated ) {
- exFreePool( Sizes );
- exFreePool( Counts );
- ArrayAllocated = 0;
++VOID
++TCPFinEventHandler(void *arg, const err_t err)
++{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg, LastConnection;
++ const NTSTATUS Status = TCPTranslateError(err);
++ KIRQL OldIrql;
++
++ ASSERT(Connection->AddressFile);
++
++ /* Check if this was a partial socket closure */
++ if (err == ERR_OK && Connection->SocketContext)
++ {
++ /* Just flush the receive queue and get out of here */
++ FlushReceiveQueue(Connection, STATUS_SUCCESS, TRUE);
++ }
++ else
++ {
++ /* First off all, remove the PCB pointer */
++ Connection->SocketContext = NULL;
++
++ /* Complete all outstanding requests now */
++ FlushAllQueues(Connection, Status);
++
++ LockObject(Connection, &OldIrql);
++
++ LockObjectAtDpcLevel(Connection->AddressFile);
++
++ /* Unlink this connection from the address file */
++ if (Connection->AddressFile->Connection == Connection)
++ {
++ Connection->AddressFile->Connection = Connection->Next;
++ DereferenceObject(Connection);
+ }
- if ( ArrayUsed < ArrayAllocated ) {
- Sizes[ArrayUsed] = Bytes;
- Counts[ArrayUsed] = 1;
- ArrayUsed++;
- }
++ else if (Connection->AddressFile->Listener == Connection)
++ {
++ Connection->AddressFile->Listener = NULL;
++ DereferenceObject(Connection);
+ }
++ else
++ {
++ LastConnection = Connection->AddressFile->Connection;
++ while (LastConnection->Next != Connection && LastConnection->Next != NULL)
++ LastConnection = LastConnection->Next;
++ if (LastConnection->Next == Connection)
++ {
++ LastConnection->Next = Connection->Next;
++ DereferenceObject(Connection);
++ }
++ }
++
++ UnlockObjectFromDpcLevel(Connection->AddressFile);
++
++ /* Remove the address file from this connection */
++ DereferenceObject(Connection->AddressFile);
++ Connection->AddressFile = NULL;
++
++ UnlockObject(Connection, OldIrql);
+ }
- if ( 0 == (++AllocationCount % MEM_PROFILE) ) {
- TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n"));
- for ( i = 0; i < ArrayUsed; i++ ) {
++}
++
++VOID
++TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
++{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++ PIRP Irp;
++ NTSTATUS Status;
++ KIRQL OldIrql;
++
++ ReferenceObject(Connection);
++
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
++ {
++ PIO_STACK_LOCATION IrpSp;
++
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Irp = Bucket->Request.RequestContext;
++ IrpSp = IoGetCurrentIrpStackLocation( Irp );
++
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPAcceptEventHandler] Getting the socket\n"));
++
++ Status = TCPCheckPeerForAccept(newpcb,
++ (PTDI_REQUEST_KERNEL)&IrpSp->Parameters);
++
++ TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n", Status));
++
++ Bucket->Status = Status;
++ Bucket->Information = 0;
++
++ if (Status == STATUS_SUCCESS)
++ {
++ LockObject(Bucket->AssociatedEndpoint, &OldIrql);
++
++ /* sanity assert...this should never be in anything else but a CLOSED state */
++ ASSERT( ((PTCP_PCB)Bucket->AssociatedEndpoint->SocketContext)->state == CLOSED );
++
++ /* free socket context created in FileOpenConnection, as we're using a new one */
++ LibTCPClose(Bucket->AssociatedEndpoint, TRUE, FALSE);
++
++ /* free previously created socket context (we don't use it, we use newpcb) */
++ Bucket->AssociatedEndpoint->SocketContext = newpcb;
++
++ LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint);
++
++ UnlockObject(Bucket->AssociatedEndpoint, OldIrql);
++ }
++
++ DereferenceObject(Bucket->AssociatedEndpoint);
++
++ CompleteBucket(Connection, Bucket, FALSE);
+ }
++
++ DereferenceObject(Connection);
++}
+
- ("Size %4u Count %5u\n", Sizes[i], Counts[i]));
- }
- TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n"));
++VOID
++TCPSendEventHandler(void *arg, u16_t space)
++{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++ PIRP Irp;
++ NTSTATUS Status;
++ PMDL Mdl;
++
++ ReferenceObject(Connection);
++
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
++ {
++ UINT SendLen = 0;
++ PVOID SendBuffer = 0;
++
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Irp = Bucket->Request.RequestContext;
++ Mdl = Irp->MdlAddress;
++
+ TI_DbgPrint(DEBUG_TCP,
- #endif /* MEM_PROFILE */
++ ("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));
++ TI_DbgPrint
++ (DEBUG_TCP,
++ ("Connection->SocketContext: %x\n",
++ Connection->SocketContext));
++
++ Status = TCPTranslateError(LibTCPSend(Connection,
++ SendBuffer,
++ SendLen, TRUE));
++
++ TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", SendLen));
++
++ if( Status == STATUS_PENDING )
++ {
++ ExInterlockedInsertHeadList(&Connection->SendRequest,
++ &Bucket->Entry,
++ &Connection->Lock);
++ break;
++ }
++ else
++ {
++ TI_DbgPrint(DEBUG_TCP,
++ ("Completing Send request: %x %x\n",
++ Bucket->Request, Status));
++
++ Bucket->Status = Status;
++ Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? SendLen : 0;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
+ }
- if ( SMALL_SIZE == Bytes ) {
- v = ExAllocateFromNPagedLookasideList( &SmallLookasideList );
- Signature = SIGNATURE_SMALL;
- } else if ( LARGE_SIZE == Bytes ) {
- v = ExAllocateFromNPagedLookasideList( &LargeLookasideList );
- Signature = SIGNATURE_LARGE;
- } else {
- v = ExAllocatePoolWithTag( NonPagedPool, Bytes + sizeof(ULONG),
- OSK_OTHER_TAG );
- Signature = SIGNATURE_OTHER;
- }
- if( v ) {
- *((ULONG *) v) = Signature;
- v = (void *)((char *) v + sizeof(ULONG));
- }
+
- return v;
++ // If we completed all outstanding send requests then finish all pending shutdown requests,
++ // cancel the timer and dereference the connection
++ if (IsListEmpty(&Connection->SendRequest))
++ {
++ FlushShutdownQueue(Connection, STATUS_SUCCESS, FALSE);
+
- void TCPFree( void *ClientData,
- void *data, OSK_PCHAR File, OSK_UINT Line ) {
- ULONG Signature;
-
- data = (void *)((char *) data - sizeof(ULONG));
- Signature = *((ULONG *) data);
- if ( SIGNATURE_SMALL == Signature ) {
- ExFreeToNPagedLookasideList( &SmallLookasideList, data );
- } else if ( SIGNATURE_LARGE == Signature ) {
- ExFreeToNPagedLookasideList( &LargeLookasideList, data );
- } else if ( SIGNATURE_OTHER == Signature ) {
- ExFreePoolWithTag( data, OSK_OTHER_TAG );
- } else {
- ASSERT( FALSE );
++ if (KeCancelTimer(&Connection->DisconnectTimer))
++ {
++ DereferenceObject(Connection);
++ }
++ }
++
++ DereferenceObject(Connection);
+}
+
- void
- TCPMemShutdown( void )
++u32_t
++TCPRecvEventHandler(void *arg, struct pbuf *p)
++{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++ PIRP Irp;
++ PMDL Mdl;
++ UINT Received = 0;
++ UINT RecvLen;
++ PUCHAR RecvBuffer;
++
++ ASSERT(p);
++
++ ReferenceObject(Connection);
++
++ if ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
++ {
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Irp = Bucket->Request.RequestContext;
++ Mdl = Irp->MdlAddress;
++
++ TI_DbgPrint(DEBUG_TCP,
++ ("[IP, TCPRecvEventHandler] Getting the user buffer from %x\n", Mdl));
++
++ NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
++
++ TI_DbgPrint(DEBUG_TCP,
++ ("[IP, TCPRecvEventHandler] Reading %d bytes to %x\n", RecvLen, RecvBuffer));
++
++ TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
++ TI_DbgPrint(DEBUG_TCP, ("[IP, TCPRecvEventHandler] Connection->SocketContext: %x\n", Connection->SocketContext));
++ TI_DbgPrint(DEBUG_TCP, ("[IP, TCPRecvEventHandler] RecvBuffer: %x\n", RecvBuffer));
++
++ RecvLen = MIN(p->tot_len, RecvLen);
++
++ for (Received = 0; Received < RecvLen; Received += p->len, p = p->next)
++ {
++ RtlCopyMemory(RecvBuffer + Received, p->payload, p->len);
++ }
++
++ TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
++
++ Bucket->Status = STATUS_SUCCESS;
++ Bucket->Information = Received;
++
++ CompleteBucket(Connection, Bucket, FALSE);
+ }
++
++ DereferenceObject(Connection);
++
++ return Received;
+}
+
- ExDeleteNPagedLookasideList( &SmallLookasideList );
- ExDeleteNPagedLookasideList( &LargeLookasideList );
++VOID
++TCPConnectEventHandler(void *arg, err_t err)
+{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
++ PTDI_BUCKET Bucket;
++ PLIST_ENTRY Entry;
++
++ ReferenceObject(Connection);
++
++ while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
++ {
++
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++
++ Bucket->Status = TCPTranslateError(err);
++ Bucket->Information = 0;
++
++ CompleteBucket(Connection, Bucket, FALSE);
++ }
++
++ DereferenceObject(Connection);
+}
--- /dev/null
- static NPAGED_LOOKASIDE_LIST TCPSegmentList;
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: transport/tcp/tcp.c
+ * PURPOSE: Transmission Control Protocol
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * Art Yerkes (arty@users.sf.net)
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ * arty 12/21/2004 Added accept
+ */
+
+#include "precomp.h"
+
+LONG TCP_IPIdentification = 0;
+static BOOLEAN TCPInitialized = FALSE;
- CLIENT_DATA ClientInfo;
+PORT_SET TCPPorts;
- 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);
- }
+
- 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 "lwip/pbuf.h"
++#include "lwip/ip.h"
++#include "lwip/init.h"
++#include "lwip/arch.h"
+
- PCONNECTION_ENDPOINT Connection = DeferredContext;
++#include "rosip.h"
+
+VOID NTAPI
+DisconnectTimeoutDpc(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
- OskitTCPShutdown(Connection, FWRITE);
++ 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 */
- CompleteBucket(Connection, Bucket);
++ Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
+
+ while (!IsListEmpty(&Connection->SendRequest))
+ {
+ Entry = RemoveHeadList(&Connection->SendRequest);
+
+ Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
+
+ Bucket->Information = 0;
+ Bucket->Status = STATUS_FILE_CLOSED;
+
- while (!IsListEmpty(&Connection->ShutdownRequest)) {
++ CompleteBucket(Connection, Bucket, FALSE);
+ }
+
- CompleteBucket(Connection, Bucket);
++ while (!IsListEmpty(&Connection->ShutdownRequest))
++ {
+ Entry = RemoveHeadList( &Connection->ShutdownRequest );
+
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+
+ Bucket->Status = STATUS_TIMEOUT;
+ Bucket->Information = 0;
+
- VOID ConnectionFree(PVOID Object) {
- PCONNECTION_ENDPOINT Connection = Object;
++ CompleteBucket(Connection, Bucket, FALSE);
+ }
+
+ UnlockObjectFromDpcLevel(Connection);
+
+ DereferenceObject(Connection);
+}
+
- PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
- PCONNECTION_ENDPOINT Connection =
++VOID ConnectionFree(PVOID Object)
++{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object;
+ KIRQL OldIrql;
+
+ TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
+
+ TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
+ RemoveEntryList(&Connection->ListEntry);
+ TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
+
+ ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
+}
+
-
++PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext )
++{
++ PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT),
+ CONN_ENDPT_TAG);
+ if (!Connection)
+ return Connection;
+
+ TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
+
+ RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
+
+ /* Initialize spin lock that protects the connection endpoint file object */
+ KeInitializeSpinLock(&Connection->Lock);
+ InitializeListHead(&Connection->ConnectRequest);
+ InitializeListHead(&Connection->ListenRequest);
+ InitializeListHead(&Connection->ReceiveRequest);
+ InitializeListHead(&Connection->SendRequest);
+ InitializeListHead(&Connection->ShutdownRequest);
- Connection->RefCount = 2;
++ InitializeListHead(&Connection->PacketQueue);
++
++ /* Initialize disconnect timer */
+ KeInitializeTimer(&Connection->DisconnectTimer);
+ KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection);
+
+ /* Save client context pointer */
+ Connection->ClientContext = ClientContext;
+
- UINT Family, UINT Type, UINT Proto ) {
++ Connection->RefCount = 1;
+ Connection->Free = ConnectionFree;
+
+ /* Add connection endpoint to global list */
+ ExInterlockedInsertTailList(&ConnectionEndpointListHead,
+ &Connection->ListEntry,
+ &ConnectionEndpointListLock);
+
+ return Connection;
+}
+
+NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
- 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 ) );
++ UINT Family, UINT Type, UINT Proto )
++{
+ NTSTATUS Status;
+ KIRQL OldIrql;
+
+ LockObject(Connection, &OldIrql);
+
- ASSERT_KM_POINTER(Connection->SocketContext);
++ 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)));
+
- 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
- */
++ 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;
+}
+
- TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
- IPPacket->TotalSize,
- IPPacket->HeaderSize));
++NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection )
+{
+ KIRQL OldIrql;
++ PVOID Socket;
+
- KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql);
- ClientInfo.Unlocked = TRUE;
- ClientInfo.OldIrql = OldIrql;
++ LockObject(Connection, &OldIrql);
+
- OskitTCPReceiveDatagram( IPPacket->Header,
- IPPacket->TotalSize,
- IPPacket->HeaderSize );
++ Socket = Connection->SocketContext;
+
- ClientInfo.Unlocked = FALSE;
- KeReleaseSpinLock(&ClientInfo.Lock, OldIrql);
- }
++ FlushAllQueues(Connection, STATUS_CANCELLED);
+
- /* 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);
- }
++ LibTCPClose(Connection, FALSE, TRUE);
+
- TimerOskitTCP( Next == NextFast, Next == NextSlow );
++ UnlockObject(Connection, OldIrql);
+
- Current = Next;
- if (10 <= Current) {
- Current = 0;
- Next = 0;
- NextFast = 0;
- NextSlow = 0;
- }
- }
++ DereferenceObject(Connection);
+
- static VOID
- StartTimer(VOID)
++ return STATUS_SUCCESS;
+}
+
- KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
- PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
- TimerThread, NULL);
++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
++ */
+{
- Status = TCPMemStartup();
- if ( ! NT_SUCCESS(Status) ) {
- return Status;
- }
-
++ 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)
+/*
+ * FUNCTION: Initializes the TCP subsystem
+ * RETURNS:
+ * Status of operation
+ */
+{
+ NTSTATUS Status;
+
- if( !NT_SUCCESS(Status) ) {
- TCPMemShutdown();
+ Status = PortsStartup( &TCPPorts, 1, 0xfffe );
-
- KeInitializeSpinLock(&ClientInfo.Lock);
- ClientInfo.Unlocked = FALSE;
-
- RegisterOskitTCPEventHandlers( &EventHandlers );
- InitOskitTCP();
-
++ if (!NT_SUCCESS(Status))
++ {
+ return Status;
+ }
-
- ExInitializeNPagedLookasideList(
- &TCPSegmentList, /* Lookaside list */
- NULL, /* Allocate routine */
- NULL, /* Free routine */
- 0, /* Flags */
- sizeof(TCP_SEGMENT), /* Size of each entry */
- 'SPCT', /* Tag */
- 0); /* Depth */
-
- StartTimer();
-
++
++ /* Initialize our IP library */
++ LibIPInitialize();
++
+ /* Register this protocol with IP layer */
+ IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
- LARGE_INTEGER WaitForThread;
-
++
+ TCPInitialized = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS TCPShutdown(VOID)
+/*
+ * FUNCTION: Shuts down the TCP subsystem
+ * RETURNS:
+ * Status of operation
+ */
+{
-
- WaitForThread.QuadPart = -2500000; /* 250 ms */
- KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
- ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
+ if (!TCPInitialized)
+ return STATUS_SUCCESS;
- ExDeleteNPagedLookasideList(&TCPSegmentList);
-
++
++ LibIPShutdown();
+
+ /* Deregister this protocol with IP layer */
+ IPRegisterProtocol(IPPROTO_TCP, NULL);
+
- DeinitOskitTCP();
-
+ TCPInitialized = FALSE;
+
- TCPMemShutdown();
-
+ PortsShutdown( &TCPPorts );
+
- NTSTATUS TCPTranslateError( int OskitError ) {
+ return STATUS_SUCCESS;
+}
+
- 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;
++NTSTATUS TCPTranslateError(const err_t err)
++{
+ NTSTATUS Status;
+
- TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
++ 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);
+
- PVOID Context ) {
+ return Status;
+}
+
+NTSTATUS TCPConnect
+( PCONNECTION_ENDPOINT Connection,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo,
+ PTCP_COMPLETION_ROUTINE Complete,
- SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
++ PVOID Context )
++{
+ NTSTATUS Status;
- PNEIGHBOR_CACHE_ENTRY NCE = NULL;
++ struct ip_addr bindaddr, connaddr;
+ IP_ADDRESS RemoteAddress;
+ USHORT RemotePort;
+ TA_IP_ADDRESS LocalAddress;
+ PTDI_BUCKET Bucket;
- TI_DbgPrint(DEBUG_TCP,("TCPConnect: Called\n"));
++ PNEIGHBOR_CACHE_ENTRY NCE;
+ KIRQL OldIrql;
+
- if (!NT_SUCCESS(Status)) {
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n"));
+
+ Status = AddrBuildAddress
+ ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
+ &RemoteAddress,
+ &RemotePort);
+
- AddressToConnect.sin_family = AF_INET;
- AddressToBind = AddressToConnect;
-
++ if (!NT_SUCCESS(Status))
++ {
+ TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
+ return Status;
+ }
+
+ /* Freed in TCPSocketState */
+ TI_DbgPrint(DEBUG_TCP,
+ ("Connecting to address %x:%x\n",
+ RemoteAddress.Address.IPv4Address,
+ RemotePort));
+
- }
+ LockObject(Connection, &OldIrql);
+
+ if (!Connection->AddressFile)
+ {
+ UnlockObject(Connection, OldIrql);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (AddrIsUnspecified(&Connection->AddressFile->Address))
+ {
+ if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
+ {
+ 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)));
+
- /* An implicit bind will be performed */
- Status = STATUS_SUCCESS;
++ bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address;
+ }
+ else
+ {
- if (NT_SUCCESS(Status)) {
- if (NT_SUCCESS(Status))
++ bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address;
+ }
+
- memcpy( &AddressToConnect.sin_addr,
- &RemoteAddress.Address.IPv4Address,
- sizeof(AddressToConnect.sin_addr) );
- AddressToConnect.sin_port = RemotePort;
-
- Status = TCPTranslateError
- ( OskitTCPConnect( Connection,
- &AddressToConnect,
- sizeof(AddressToConnect) ) );
-
++ Status = TCPTranslateError(LibTCPBind(Connection,
++ &bindaddr,
++ Connection->AddressFile->Port));
++
++ if (NT_SUCCESS(Status))
++ {
++ /* Check if we had an unspecified port */
++ if (!Connection->AddressFile->Port)
+ {
- /* 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;
- }
++ /* We did, so we need to copy back the port */
++ Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
+ if (NT_SUCCESS(Status))
+ {
- if (Status == STATUS_PENDING)
++ /* 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);
+ }
++ }
+
- 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 );
++ if (NT_SUCCESS(Status))
++ {
++ connaddr.addr = RemoteAddress.Address.IPv4Address;
++
++ Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
++ if (!Bucket)
+ {
- PVOID Context ) {
++ 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;
+}
+
+NTSTATUS TCPDisconnect
+( PCONNECTION_ENDPOINT Connection,
+ UINT Flags,
+ PLARGE_INTEGER Timeout,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo,
+ PTCP_COMPLETION_ROUTINE Complete,
- PLIST_ENTRY Entry;
++ PVOID Context )
++{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+ PTDI_BUCKET Bucket;
+ KIRQL OldIrql;
- TI_DbgPrint(DEBUG_TCP,("started\n"));
+ LARGE_INTEGER ActualTimeout;
+
- if (Flags & TDI_DISCONNECT_RELEASE)
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));
+
+ LockObject(Connection, &OldIrql);
+
- /* See if we can satisfy this right now */
- if (IsListEmpty(&Connection->SendRequest))
++ if (Connection->SocketContext)
+ {
- /* 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 (Flags & TDI_DISCONNECT_RELEASE)
+ {
- Entry = RemoveHeadList(&Connection->SendRequest);
-
- Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
-
- Bucket->Information = 0;
- Bucket->Status = STATUS_FILE_CLOSED;
-
- CompleteBucket(Connection, Bucket);
++ if (IsListEmpty(&Connection->SendRequest))
+ {
-
- UnlockObject(Connection, OldIrql);
-
- return STATUS_TIMEOUT;
- }
-
- /* Otherwise we wait for the send queue to be empty */
- }
++ Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
+ }
- 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);
++ 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;
++ }
+
-
- while (!IsListEmpty(&Connection->ReceiveRequest))
++ /* 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;
++ }
+ }
- Entry = RemoveHeadList(&Connection->ReceiveRequest);
-
- Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
-
- Bucket->Information = 0;
- Bucket->Status = STATUS_FILE_CLOSED;
-
- CompleteBucket(Connection, Bucket);
++
++ if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
+ {
-
- /* 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;
++ FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE);
++ FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
++ FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE);
++ Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
+ }
- ActualTimeout.QuadPart = -1000000;
+ }
+ else
+ {
-
- ReferenceObject(Connection);
- KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc);
++ /* We already got closed by the other side so just return success */
++ Status = STATUS_SUCCESS;
+ }
- TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
-
- return STATUS_PENDING;
- }
+
+ UnlockObject(Connection, OldIrql);
+
- 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;
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));
+
- PVOID Context ) {
- PVOID DataBuffer;
- UINT DataLen, Received = 0;
- NTSTATUS Status;
++ return Status;
+}
+
+NTSTATUS TCPReceiveData
+( PCONNECTION_ENDPOINT Connection,
+ PNDIS_BUFFER Buffer,
+ ULONG ReceiveLength,
+ PULONG BytesReceived,
+ ULONG ReceiveFlags,
+ PTCP_COMPLETION_ROUTINE Complete,
- KIRQL OldIrql;
-
- NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
-
- TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
++ PVOID Context )
++{
+ PTDI_BUCKET Bucket;
- LockObject(Connection, &OldIrql);
++ PUCHAR DataBuffer;
++ UINT DataLen, Received;
++ NTSTATUS Status;
+
- Status = TCPTranslateError
- ( OskitTCPRecv
- ( Connection,
- DataBuffer,
- DataLen,
- &Received,
- ReceiveFlags ) );
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n",
++ ReceiveLength, Connection->SocketContext));
+
- TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
++ NdisQueryBuffer(Buffer, &DataBuffer, &DataLen);
+
- /* Keep this request around ... there was no data yet */
- if( Status == STATUS_PENDING ) {
++ Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received);
+
- Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
- if( !Bucket ) {
- TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
- UnlockObject(Connection, OldIrql);
++ if (Status == STATUS_PENDING)
++ {
++
+ /* Freed in TCPSocketState */
-
++ 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;
+ }
- *BytesReceived = 0;
++
+ Bucket->Request.RequestNotifyObject = Complete;
+ Bucket->Request.RequestContext = Context;
- 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;
- }
+
- UnlockObject(Connection, OldIrql);
++ ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n"));
+
- TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n"));
+
- PVOID Context ) {
- UINT Sent = 0;
++ (*BytesReceived) = 0;
++ }
++ else
++ {
++ (*BytesReceived) = Received;
++ }
+
+ return Status;
+}
+
+NTSTATUS TCPSendData
+( PCONNECTION_ENDPOINT Connection,
+ PCHAR BufferData,
+ ULONG SendLength,
+ PULONG BytesSent,
+ ULONG Flags,
+ PTCP_COMPLETION_ROUTINE Complete,
- TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection));
++ PVOID Context )
++{
+ NTSTATUS Status;
+ PTDI_BUCKET Bucket;
+ KIRQL OldIrql;
+
+ LockObject(Connection, &OldIrql);
+
- Status = TCPTranslateError
- ( OskitTCPSend( Connection,
- (OSK_PCHAR)BufferData, SendLength,
- &Sent, 0 ) );
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n",
++ SendLength, Connection->SocketContext));
+
- TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection));
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n",
++ Connection->SocketContext));
+
- if( Status == STATUS_PENDING ) {
++ 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( !Bucket ) {
++ if (Status == STATUS_PENDING)
++ {
+ /* Freed in TCPSocketState */
+ Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
- TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
++ if (!Bucket)
++ {
+ UnlockObject(Connection, OldIrql);
- 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] Failed to allocate bucket\n"));
+ return STATUS_NO_MEMORY;
+ }
+
+ Bucket->Request.RequestNotifyObject = Complete;
+ Bucket->Request.RequestContext = Context;
+ *BytesSent = 0;
+
+ InsertTailList( &Connection->SendRequest, &Bucket->Entry );
- TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
++ TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
++ }
++ else if (Status == STATUS_SUCCESS)
++ {
++ *BytesSent = SendLength;
++ }
++ else
++ {
++ *BytesSent = 0;
+ }
+
+ UnlockObject(Connection, OldIrql);
+
- 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"));
++ TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status));
+
+ return Status;
+}
+
- } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
++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;
+ }
- VOID TCPFreePort( UINT Port ) {
- DeallocatePort( &TCPPorts, Port );
++ }
++ else
++ return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
+}
+
- BOOLEAN GetRemote ) {
- OSK_UINT LocalAddress, RemoteAddress;
- OSK_UI16 LocalPort, RemotePort;
++VOID TCPFreePort(const UINT Port)
++{
++ DeallocatePort(&TCPPorts, Port);
+}
+
+NTSTATUS TCPGetSockAddress
+( PCONNECTION_ENDPOINT Connection,
+ PTRANSPORT_ADDRESS Address,
- Status = TCPTranslateError(OskitTCPGetAddress(Connection,
- &LocalAddress, &LocalPort,
- &RemoteAddress, &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);
+
-
- 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;
++ 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);
- BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
++
++ AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
+
+ return Status;
+}
+
++BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
++{
+ PLIST_ENTRY Entry;
+ PLIST_ENTRY ListHead[5];
+ KIRQL OldIrql;
+ PTDI_BUCKET Bucket;
+ UINT i = 0;
+ BOOLEAN Found = FALSE;
+
+ ListHead[0] = &Endpoint->SendRequest;
+ ListHead[1] = &Endpoint->ReceiveRequest;
+ ListHead[2] = &Endpoint->ConnectRequest;
+ ListHead[3] = &Endpoint->ListenRequest;
+ ListHead[4] = &Endpoint->ShutdownRequest;
+
+ LockObject(Endpoint, &OldIrql);
+
+ for( i = 0; i < 5; i++ )
+ {
+ for( Entry = ListHead[i]->Flink;
+ Entry != ListHead[i];
+ Entry = Entry->Flink )
+ {
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ if( Bucket->Request.RequestContext == Irp )
+ {
+ RemoveEntryList( &Bucket->Entry );
+ ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
+ Found = TRUE;
+ break;
+ }
+ }
+ }
+
+ UnlockObject(Endpoint, OldIrql);
+
+ return Found;
+}
+
+/* EOF */
--- /dev/null
--- /dev/null
++<?xml version="1.0"?>
++<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
++<module name="lwip" type="staticlibrary" allowwarnings="true">
++ <include base="lwip">src/include</include>
++ <include base="lwip">src/include/ipv4</include>
++ <include base="tcpip">include</include>
++ <directory name="src">
++ <file>rosip.c</file>
++ <file>rostcp.c</file>
++ <file>rosmem.c</file>
++ <file>sys_arch.c</file>
++ <directory name="api">
++ <file>api_lib.c</file>
++ <file>api_msg.c</file>
++ <file>err.c</file>
++ <file>netbuf.c</file>
++ <file>netdb.c</file>
++ <file>netifapi.c</file>
++ <file>sockets.c</file>
++ <file>tcpip.c</file>
++ </directory>
++ <directory name="core">
++ <file>def.c</file>
++ <file>dhcp.c</file>
++ <file>dns.c</file>
++ <file>init.c</file>
++ <file>mem.c</file>
++ <file>memp.c</file>
++ <file>netif.c</file>
++ <file>pbuf.c</file>
++ <file>raw.c</file>
++ <file>stats.c</file>
++ <file>sys.c</file>
++ <file>tcp_in.c</file>
++ <file>tcp_out.c</file>
++ <file>tcp.c</file>
++ <file>timers.c</file>
++ <file>udp.c</file>
++ <directory name="ipv4">
++ <file>autoip.c</file>
++ <file>icmp.c</file>
++ <file>igmp.c</file>
++ <file>inet_chksum.c</file>
++ <file>inet.c</file>
++ <file>ip.c</file>
++ <file>ip_addr.c</file>
++ <file>ip_frag.c</file>
++ </directory>
++ <!--directory name="ipv6">
++ <file>icmp6.c</file>
++ <file>inet6.c</file>
++ <file>ip6_addr.c</file>
++ <file>ip6.c</file>
++ </directory-->
++ <directory name="snmp">
++ <file>asn1_dec.c</file>
++ <file>asn1_enc.c</file>
++ <file>mib_structs.c</file>
++ <file>mib2.c</file>
++ <file>msg_in.c</file>
++ <file>msg_out.c</file>
++ </directory>
++ </directory>
++ </directory>
++</module>
--- /dev/null
--- /dev/null
++/**
++ * @file
++ * Transmission Control Protocol, incoming traffic
++ *
++ * The input processing functions of the TCP layer.
++ *
++ * These functions are generally called in the order (ip_input() ->)
++ * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
++ *
++ */
++
++/*
++ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without modification,
++ * are permitted provided that the following conditions are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright notice,
++ * this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright notice,
++ * this list of conditions and the following disclaimer in the documentation
++ * and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
++ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
++ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
++ * OF SUCH DAMAGE.
++ *
++ * This file is part of the lwIP TCP/IP stack.
++ *
++ * Author: Adam Dunkels <adam@sics.se>
++ *
++ */
++
++#include "lwip/opt.h"
++
++#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
++
++#include "lwip/tcp_impl.h"
++#include "lwip/def.h"
++#include "lwip/ip_addr.h"
++#include "lwip/netif.h"
++#include "lwip/mem.h"
++#include "lwip/memp.h"
++#include "lwip/inet_chksum.h"
++#include "lwip/stats.h"
++#include "lwip/snmp.h"
++#include "arch/perf.h"
++
++/* These variables are global to all functions involved in the input
++ processing of TCP segments. They are set by the tcp_input()
++ function. */
++static struct tcp_seg inseg;
++static struct tcp_hdr *tcphdr;
++static struct ip_hdr *iphdr;
++static u32_t seqno, ackno;
++static u8_t flags;
++static u16_t tcplen;
++
++static u8_t recv_flags;
++static struct pbuf *recv_data;
++
++struct tcp_pcb *tcp_input_pcb;
++
++/* Forward declarations. */
++static err_t tcp_process(struct tcp_pcb *pcb);
++static void tcp_receive(struct tcp_pcb *pcb);
++static void tcp_parseopt(struct tcp_pcb *pcb);
++
++static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
++static err_t tcp_timewait_input(struct tcp_pcb *pcb);
++
++static const char * const tcp_state_str[] = {
++ "CLOSED",
++ "LISTEN",
++ "SYN_SENT",
++ "SYN_RCVD",
++ "ESTABLISHED",
++ "FIN_WAIT_1",
++ "FIN_WAIT_2",
++ "CLOSE_WAIT",
++ "CLOSING",
++ "LAST_ACK",
++ "TIME_WAIT"
++};
++
++/**
++ * The initial input processing of TCP. It verifies the TCP header, demultiplexes
++ * the segment between the PCBs and passes it on to tcp_process(), which implements
++ * the TCP finite state machine. This function is called by the IP layer (in
++ * ip_input()).
++ *
++ * @param p received TCP segment to process (p->payload pointing to the IP header)
++ * @param inp network interface on which this segment was received
++ */
++void
++tcp_input(struct pbuf *p, struct netif *inp)
++{
++ struct tcp_pcb *pcb, *prev;
++ struct tcp_pcb_listen *lpcb;
++#if SO_REUSE
++ struct tcp_pcb *lpcb_prev = NULL;
++ struct tcp_pcb_listen *lpcb_any = NULL;
++#endif /* SO_REUSE */
++ u8_t hdrlen;
++ err_t err;
++
++ PERF_START;
++
++ TCP_STATS_INC(tcp.recv);
++ snmp_inc_tcpinsegs();
++
++ iphdr = (struct ip_hdr *)p->payload;
++ tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
++
++#if TCP_INPUT_DEBUG
++ tcp_debug_print(tcphdr);
++#endif
++
++ /* remove header from payload */
++ if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
++ /* drop short packets */
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
++ TCP_STATS_INC(tcp.lenerr);
++ TCP_STATS_INC(tcp.drop);
++ snmp_inc_tcpinerrs();
++ pbuf_free(p);
++ return;
++ }
++
++ /* Don't even process incoming broadcasts/multicasts. */
++ if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) ||
++ ip_addr_ismulticast(¤t_iphdr_dest)) {
++ TCP_STATS_INC(tcp.proterr);
++ TCP_STATS_INC(tcp.drop);
++ snmp_inc_tcpinerrs();
++ pbuf_free(p);
++ return;
++ }
++
++#if CHECKSUM_CHECK_TCP
++ /* Verify TCP checksum. */
++ if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
++ IP_PROTO_TCP, p->tot_len) != 0) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
++ inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
++ IP_PROTO_TCP, p->tot_len)));
++#if TCP_DEBUG
++ tcp_debug_print(tcphdr);
++#endif /* TCP_DEBUG */
++ TCP_STATS_INC(tcp.chkerr);
++ TCP_STATS_INC(tcp.drop);
++ snmp_inc_tcpinerrs();
++ pbuf_free(p);
++ return;
++ }
++#endif
++
++ /* Move the payload pointer in the pbuf so that it points to the
++ TCP data instead of the TCP header. */
++ hdrlen = TCPH_HDRLEN(tcphdr);
++ if(pbuf_header(p, -(hdrlen * 4))){
++ /* drop short packets */
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
++ TCP_STATS_INC(tcp.lenerr);
++ TCP_STATS_INC(tcp.drop);
++ snmp_inc_tcpinerrs();
++ pbuf_free(p);
++ return;
++ }
++
++ /* Convert fields in TCP header to host byte order. */
++ tcphdr->src = ntohs(tcphdr->src);
++ tcphdr->dest = ntohs(tcphdr->dest);
++ seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
++ ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
++ tcphdr->wnd = ntohs(tcphdr->wnd);
++
++ flags = TCPH_FLAGS(tcphdr);
++ tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
++
++ /* Demultiplex an incoming segment. First, we check if it is destined
++ for an active connection. */
++ prev = NULL;
++
++
++ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
++ LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
++ LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
++ LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
++ if (pcb->remote_port == tcphdr->src &&
++ pcb->local_port == tcphdr->dest &&
++ ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
++ ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
++
++ /* Move this PCB to the front of the list so that subsequent
++ lookups will be faster (we exploit locality in TCP segment
++ arrivals). */
++ LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
++ if (prev != NULL) {
++ prev->next = pcb->next;
++ pcb->next = tcp_active_pcbs;
++ tcp_active_pcbs = pcb;
++ }
++ LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
++ break;
++ }
++ prev = pcb;
++ }
++
++ if (pcb == NULL) {
++ /* If it did not go to an active connection, we check the connections
++ in the TIME-WAIT state. */
++ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
++ LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
++ if (pcb->remote_port == tcphdr->src &&
++ pcb->local_port == tcphdr->dest &&
++ ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
++ ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
++ /* We don't really care enough to move this PCB to the front
++ of the list since we are not very likely to receive that
++ many segments for connections in TIME-WAIT. */
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
++ tcp_timewait_input(pcb);
++ pbuf_free(p);
++ return;
++ }
++ }
++
++ /* Finally, if we still did not get a match, we check all PCBs that
++ are LISTENing for incoming connections. */
++ prev = NULL;
++ for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
++ if (lpcb->local_port == tcphdr->dest) {
++#if SO_REUSE
++ if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) {
++ /* found an exact match */
++ break;
++ } else if(ip_addr_isany(&(lpcb->local_ip))) {
++ /* found an ANY-match */
++ lpcb_any = lpcb;
++ lpcb_prev = prev;
++ }
++#else /* SO_REUSE */
++ if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) ||
++ ip_addr_isany(&(lpcb->local_ip))) {
++ /* found a match */
++ break;
++ }
++#endif /* SO_REUSE */
++ }
++ prev = (struct tcp_pcb *)lpcb;
++ }
++#if SO_REUSE
++ /* first try specific local IP */
++ if (lpcb == NULL) {
++ /* only pass to ANY if no specific local IP has been found */
++ lpcb = lpcb_any;
++ prev = lpcb_prev;
++ }
++#endif /* SO_REUSE */
++ if (lpcb != NULL) {
++ /* Move this PCB to the front of the list so that subsequent
++ lookups will be faster (we exploit locality in TCP segment
++ arrivals). */
++ if (prev != NULL) {
++ ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
++ /* our successor is the remainder of the listening list */
++ lpcb->next = tcp_listen_pcbs.listen_pcbs;
++ /* put this listening pcb at the head of the listening list */
++ tcp_listen_pcbs.listen_pcbs = lpcb;
++ }
++
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
++ tcp_listen_input(lpcb);
++ pbuf_free(p);
++ return;
++ }
++ }
++
++#if TCP_INPUT_DEBUG
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
++ tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
++#endif /* TCP_INPUT_DEBUG */
++
++
++ if (pcb != NULL) {
++ /* The incoming segment belongs to a connection. */
++#if TCP_INPUT_DEBUG
++#if TCP_DEBUG
++ tcp_debug_print_state(pcb->state);
++#endif /* TCP_DEBUG */
++#endif /* TCP_INPUT_DEBUG */
++
++ /* Set up a tcp_seg structure. */
++ inseg.next = NULL;
++ inseg.len = p->tot_len;
++ inseg.p = p;
++ inseg.tcphdr = tcphdr;
++
++ recv_data = NULL;
++ recv_flags = 0;
++
++ /* If there is data which was previously "refused" by upper layer */
++ if (pcb->refused_data != NULL) {
++ /* Notify again application with data previously received. */
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
++ TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
++ if (err == ERR_OK) {
++ pcb->refused_data = NULL;
++ } else if ((err == ERR_ABRT) || (tcplen > 0)) {
++ /* if err == ERR_ABRT, 'pcb' is already deallocated */
++ /* Drop incoming packets because pcb is "full" (only if the incoming
++ segment contains data). */
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
++ TCP_STATS_INC(tcp.drop);
++ snmp_inc_tcpinerrs();
++ pbuf_free(p);
++ return;
++ }
++ }
++ tcp_input_pcb = pcb;
++ err = tcp_process(pcb);
++ /* A return value of ERR_ABRT means that tcp_abort() was called
++ and that the pcb has been freed. If so, we don't do anything. */
++ if (err != ERR_ABRT) {
++ if (recv_flags & TF_RESET) {
++ /* TF_RESET means that the connection was reset by the other
++ end. We then call the error callback to inform the
++ application that the connection is dead before we
++ deallocate the PCB. */
++ TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
++ tcp_pcb_remove(&tcp_active_pcbs, pcb);
++ memp_free(MEMP_TCP_PCB, pcb);
++ } else if (recv_flags & TF_CLOSED) {
++ /* The connection has been closed and we will deallocate the
++ PCB. */
++ TCP_EVENT_CLOSED(pcb, err);
++ if (err == ERR_ABRT) {
++ goto aborted;
++ }
++ tcp_pcb_remove(&tcp_active_pcbs, pcb);
++ memp_free(MEMP_TCP_PCB, pcb);
++ } else {
++ err = ERR_OK;
++ /* If the application has registered a "sent" function to be
++ called when new send buffer space is available, we call it
++ now. */
++ if (pcb->acked > 0) {
++ TCP_EVENT_SENT(pcb, pcb->acked, err);
++ if (err == ERR_ABRT) {
++ goto aborted;
++ }
++ }
++
++ if (recv_data != NULL) {
++ LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
++ if (pcb->flags & TF_RXCLOSED) {
++ /* received data although already closed -> abort (send RST) to
++ notify the remote host that not all data has been processed */
++ pbuf_free(recv_data);
++ tcp_abort(pcb);
++ goto aborted;
++ }
++ if (flags & TCP_PSH) {
++ recv_data->flags |= PBUF_FLAG_PUSH;
++ }
++
++ /* Notify application that data has been received. */
++ TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
++ if (err == ERR_ABRT) {
++ goto aborted;
++ }
++
++ /* If the upper layer can't receive this data, store it */
++ if (err != ERR_OK) {
++ pcb->refused_data = recv_data;
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
++ }
++ }
++
++ /* If a FIN segment was received, we call the callback
++ function with a NULL buffer to indicate EOF. */
++ if (recv_flags & TF_GOT_FIN) {
++ /* correct rcv_wnd as the application won't call tcp_recved()
++ for the FIN's seqno */
++ if (pcb->rcv_wnd != TCP_WND) {
++ pcb->rcv_wnd++;
++ }
++ TCP_EVENT_CLOSED(pcb, err);
++ if (err == ERR_ABRT) {
++ goto aborted;
++ }
++ }
++
++ tcp_input_pcb = NULL;
++ /* Try to send something out. */
++ tcp_output(pcb);
++#if TCP_INPUT_DEBUG
++#if TCP_DEBUG
++ tcp_debug_print_state(pcb->state);
++#endif /* TCP_DEBUG */
++#endif /* TCP_INPUT_DEBUG */
++ }
++ }
++ /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
++ Below this line, 'pcb' may not be dereferenced! */
++aborted:
++ tcp_input_pcb = NULL;
++ recv_data = NULL;
++
++ /* give up our reference to inseg.p */
++ if (inseg.p != NULL)
++ {
++ pbuf_free(inseg.p);
++ inseg.p = NULL;
++ }
++ } else {
++
++ /* If no matching PCB was found, send a TCP RST (reset) to the
++ sender. */
++ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
++ if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
++ TCP_STATS_INC(tcp.proterr);
++ TCP_STATS_INC(tcp.drop);
++ tcp_rst(ackno, seqno + tcplen,
++ ip_current_dest_addr(), ip_current_src_addr(),
++ tcphdr->dest, tcphdr->src);
++ }
++ pbuf_free(p);
++ }
++
++ LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
++ PERF_STOP("tcp_input");
++}
++
++/**
++ * Called by tcp_input() when a segment arrives for a listening
++ * connection (from tcp_input()).
++ *
++ * @param pcb the tcp_pcb_listen for which a segment arrived
++ * @return ERR_OK if the segment was processed
++ * another err_t on error
++ *
++ * @note the return value is not (yet?) used in tcp_input()
++ * @note the segment which arrived is saved in global variables, therefore only the pcb
++ * involved is passed as a parameter to this function
++ */
++static err_t
++tcp_listen_input(struct tcp_pcb_listen *pcb)
++{
++ struct tcp_pcb *npcb;
++ err_t rc;
++
++ /* In the LISTEN state, we check for incoming SYN segments,
++ creates a new PCB, and responds with a SYN|ACK. */
++ if (flags & TCP_ACK) {
++ /* For incoming segments with the ACK flag set, respond with a
++ RST. */
++ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
++ tcp_rst(ackno + 1, seqno + tcplen,
++ ip_current_dest_addr(), ip_current_src_addr(),
++ tcphdr->dest, tcphdr->src);
++ } else if (flags & TCP_SYN) {
++ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
++#if TCP_LISTEN_BACKLOG
++ if (pcb->accepts_pending >= pcb->backlog) {
++ LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
++ return ERR_ABRT;
++ }
++#endif /* TCP_LISTEN_BACKLOG */
++ npcb = tcp_alloc(pcb->prio);
++ /* If a new PCB could not be created (probably due to lack of memory),
++ we don't do anything, but rely on the sender will retransmit the
++ SYN at a time when we have more memory available. */
++ if (npcb == NULL) {
++ LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
++ TCP_STATS_INC(tcp.memerr);
++ return ERR_MEM;
++ }
++#if TCP_LISTEN_BACKLOG
++ pcb->accepts_pending++;
++#endif /* TCP_LISTEN_BACKLOG */
++ /* Set up the new PCB. */
++ ip_addr_copy(npcb->local_ip, current_iphdr_dest);
++ npcb->local_port = pcb->local_port;
++ ip_addr_copy(npcb->remote_ip, current_iphdr_src);
++ npcb->remote_port = tcphdr->src;
++ npcb->state = SYN_RCVD;
++ npcb->rcv_nxt = seqno + 1;
++ npcb->rcv_ann_right_edge = npcb->rcv_nxt;
++ npcb->snd_wnd = tcphdr->wnd;
++ npcb->ssthresh = npcb->snd_wnd;
++ npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
++ npcb->callback_arg = pcb->callback_arg;
++#if LWIP_CALLBACK_API
++ npcb->accept = pcb->accept;
++#endif /* LWIP_CALLBACK_API */
++ /* inherit socket options */
++ npcb->so_options = pcb->so_options & SOF_INHERITED;
++ /* Register the new PCB so that we can begin receiving segments
++ for it. */
++ TCP_REG(&tcp_active_pcbs, npcb);
++
++ /* Parse any options in the SYN. */
++ tcp_parseopt(npcb);
++#if TCP_CALCULATE_EFF_SEND_MSS
++ npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
++#endif /* TCP_CALCULATE_EFF_SEND_MSS */
++
++ snmp_inc_tcppassiveopens();
++
++ /* Send a SYN|ACK together with the MSS option. */
++ rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
++ if (rc != ERR_OK) {
++ tcp_abandon(npcb, 0);
++ return rc;
++ }
++ return tcp_output(npcb);
++ }
++ return ERR_OK;
++}
++
++/**
++ * Called by tcp_input() when a segment arrives for a connection in
++ * TIME_WAIT.
++ *
++ * @param pcb the tcp_pcb for which a segment arrived
++ *
++ * @note the segment which arrived is saved in global variables, therefore only the pcb
++ * involved is passed as a parameter to this function
++ */
++static err_t
++tcp_timewait_input(struct tcp_pcb *pcb)
++{
++ /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
++ /* RFC 793 3.9 Event Processing - Segment Arrives:
++ * - first check sequence number - we skip that one in TIME_WAIT (always
++ * acceptable since we only send ACKs)
++ * - second check the RST bit (... return) */
++ if (flags & TCP_RST) {
++ return ERR_OK;
++ }
++ /* - fourth, check the SYN bit, */
++ if (flags & TCP_SYN) {
++ /* If an incoming segment is not acceptable, an acknowledgment
++ should be sent in reply */
++ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
++ /* If the SYN is in the window it is an error, send a reset */
++ tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
++ tcphdr->dest, tcphdr->src);
++ return ERR_OK;
++ }
++ } else if (flags & TCP_FIN) {
++ /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
++ Restart the 2 MSL time-wait timeout.*/
++ pcb->tmr = tcp_ticks;
++ }
++
++ if ((tcplen > 0)) {
++ /* Acknowledge data, FIN or out-of-window SYN */
++ pcb->flags |= TF_ACK_NOW;
++ return tcp_output(pcb);
++ }
++ return ERR_OK;
++}
++
++/**
++ * Implements the TCP state machine. Called by tcp_input. In some
++ * states tcp_receive() is called to receive data. The tcp_seg
++ * argument will be freed by the caller (tcp_input()) unless the
++ * recv_data pointer in the pcb is set.
++ *
++ * @param pcb the tcp_pcb for which a segment arrived
++ *
++ * @note the segment which arrived is saved in global variables, therefore only the pcb
++ * involved is passed as a parameter to this function
++ */
++static err_t
++tcp_process(struct tcp_pcb *pcb)
++{
++ struct tcp_seg *rseg;
++ u8_t acceptable = 0;
++ err_t err;
++
++ err = ERR_OK;
++
++ /* Process incoming RST segments. */
++ if (flags & TCP_RST) {
++ /* First, determine if the reset is acceptable. */
++ if (pcb->state == SYN_SENT) {
++ if (ackno == pcb->snd_nxt) {
++ acceptable = 1;
++ }
++ } else {
++ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
++ pcb->rcv_nxt+pcb->rcv_wnd)) {
++ acceptable = 1;
++ }
++ }
++
++ if (acceptable) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
++ LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
++ recv_flags |= TF_RESET;
++ pcb->flags &= ~TF_ACK_DELAY;
++ return ERR_RST;
++ } else {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
++ seqno, pcb->rcv_nxt));
++ LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
++ seqno, pcb->rcv_nxt));
++ return ERR_OK;
++ }
++ }
++
++ if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
++ /* Cope with new connection attempt after remote end crashed */
++ tcp_ack_now(pcb);
++ return ERR_OK;
++ }
++
++ if ((pcb->flags & TF_RXCLOSED) == 0) {
++ /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
++ pcb->tmr = tcp_ticks;
++ }
++ pcb->keep_cnt_sent = 0;
++
++ tcp_parseopt(pcb);
++
++ /* Do different things depending on the TCP state. */
++ switch (pcb->state) {
++ case SYN_SENT:
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
++ pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
++ /* received SYN ACK with expected sequence number? */
++ if ((flags & TCP_ACK) && (flags & TCP_SYN)
++ && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
++ pcb->snd_buf++;
++ pcb->rcv_nxt = seqno + 1;
++ pcb->rcv_ann_right_edge = pcb->rcv_nxt;
++ pcb->lastack = ackno;
++ pcb->snd_wnd = tcphdr->wnd;
++ pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
++ pcb->state = ESTABLISHED;
++
++#if TCP_CALCULATE_EFF_SEND_MSS
++ pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
++#endif /* TCP_CALCULATE_EFF_SEND_MSS */
++
++ /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
++ * but for the default value of pcb->mss) */
++ pcb->ssthresh = pcb->mss * 10;
++
++ pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
++ LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
++ --pcb->snd_queuelen;
++ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
++ rseg = pcb->unacked;
++ pcb->unacked = rseg->next;
++
++ /* If there's nothing left to acknowledge, stop the retransmit
++ timer, otherwise reset it to start again */
++ if(pcb->unacked == NULL)
++ pcb->rtime = -1;
++ else {
++ pcb->rtime = 0;
++ pcb->nrtx = 0;
++ }
++
++ tcp_seg_free(rseg);
++
++ /* Call the user specified function to call when sucessfully
++ * connected. */
++ TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
++ if (err == ERR_ABRT) {
++ return ERR_ABRT;
++ }
++ tcp_ack_now(pcb);
++ }
++ /* received ACK? possibly a half-open connection */
++ else if (flags & TCP_ACK) {
++ /* send a RST to bring the other side in a non-synchronized state. */
++ tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
++ tcphdr->dest, tcphdr->src);
++ }
++ break;
++ case SYN_RCVD:
++ if (flags & TCP_ACK) {
++ /* expected ACK number? */
++ if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
++ u16_t old_cwnd;
++ pcb->state = ESTABLISHED;
++ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
++#if LWIP_CALLBACK_API
++ LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
++#endif
++ /* Call the accept function. */
++ TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
++ if (err != ERR_OK) {
++ /* If the accept function returns with an error, we abort
++ * the connection. */
++ /* Already aborted? */
++ if (err != ERR_ABRT) {
++ tcp_abort(pcb);
++ }
++ return ERR_ABRT;
++ }
++ old_cwnd = pcb->cwnd;
++ /* If there was any data contained within this ACK,
++ * we'd better pass it on to the application as well. */
++ tcp_receive(pcb);
++
++ /* Prevent ACK for SYN to generate a sent event */
++ if (pcb->acked != 0) {
++ pcb->acked--;
++ }
++
++ pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
++
++ if (recv_flags & TF_GOT_FIN) {
++ tcp_ack_now(pcb);
++ pcb->state = CLOSE_WAIT;
++ }
++ } else {
++ /* incorrect ACK number, send RST */
++ tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
++ tcphdr->dest, tcphdr->src);
++ }
++ } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
++ /* Looks like another copy of the SYN - retransmit our SYN-ACK */
++ tcp_rexmit(pcb);
++ }
++ break;
++ case CLOSE_WAIT:
++ /* FALLTHROUGH */
++ case ESTABLISHED:
++ tcp_receive(pcb);
++ if (recv_flags & TF_GOT_FIN) { /* passive close */
++ tcp_ack_now(pcb);
++ pcb->state = CLOSE_WAIT;
++ }
++ break;
++ case FIN_WAIT_1:
++ tcp_receive(pcb);
++ if (recv_flags & TF_GOT_FIN) {
++ if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
++ LWIP_DEBUGF(TCP_DEBUG,
++ ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
++ tcp_ack_now(pcb);
++ tcp_pcb_purge(pcb);
++ TCP_RMV(&tcp_active_pcbs, pcb);
++ pcb->state = TIME_WAIT;
++ TCP_REG(&tcp_tw_pcbs, pcb);
++ } else {
++ tcp_ack_now(pcb);
++ pcb->state = CLOSING;
++ }
++ } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
++ pcb->state = FIN_WAIT_2;
++ }
++ break;
++ case FIN_WAIT_2:
++ tcp_receive(pcb);
++ if (recv_flags & TF_GOT_FIN) {
++ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
++ tcp_ack_now(pcb);
++ tcp_pcb_purge(pcb);
++ TCP_RMV(&tcp_active_pcbs, pcb);
++ pcb->state = TIME_WAIT;
++ TCP_REG(&tcp_tw_pcbs, pcb);
++ }
++ break;
++ case CLOSING:
++ tcp_receive(pcb);
++ if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
++ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
++ tcp_pcb_purge(pcb);
++ TCP_RMV(&tcp_active_pcbs, pcb);
++ pcb->state = TIME_WAIT;
++ TCP_REG(&tcp_tw_pcbs, pcb);
++ }
++ break;
++ case LAST_ACK:
++ tcp_receive(pcb);
++ if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
++ LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
++ /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
++ recv_flags |= TF_CLOSED;
++ }
++ break;
++ default:
++ break;
++ }
++ return ERR_OK;
++}
++
++#if TCP_QUEUE_OOSEQ
++/**
++ * Insert segment into the list (segments covered with new one will be deleted)
++ *
++ * Called from tcp_receive()
++ */
++static void
++tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
++{
++ struct tcp_seg *old_seg;
++
++ if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
++ /* received segment overlaps all following segments */
++ tcp_segs_free(next);
++ next = NULL;
++ }
++ else {
++ /* delete some following segments
++ oos queue may have segments with FIN flag */
++ while (next &&
++ TCP_SEQ_GEQ((seqno + cseg->len),
++ (next->tcphdr->seqno + next->len))) {
++ /* cseg with FIN already processed */
++ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
++ TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
++ }
++ old_seg = next;
++ next = next->next;
++ tcp_seg_free(old_seg);
++ }
++ if (next &&
++ TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
++ /* We need to trim the incoming segment. */
++ cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
++ pbuf_realloc(cseg->p, cseg->len);
++ }
++ }
++ cseg->next = next;
++}
++#endif /* TCP_QUEUE_OOSEQ */
++
++/**
++ * Called by tcp_process. Checks if the given segment is an ACK for outstanding
++ * data, and if so frees the memory of the buffered data. Next, is places the
++ * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
++ * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
++ * i it has been removed from the buffer.
++ *
++ * If the incoming segment constitutes an ACK for a segment that was used for RTT
++ * estimation, the RTT is estimated here as well.
++ *
++ * Called from tcp_process().
++ */
++static void
++tcp_receive(struct tcp_pcb *pcb)
++{
++ struct tcp_seg *next;
++#if TCP_QUEUE_OOSEQ
++ struct tcp_seg *prev, *cseg;
++#endif /* TCP_QUEUE_OOSEQ */
++ struct pbuf *p;
++ s32_t off;
++ s16_t m;
++ u32_t right_wnd_edge;
++ u16_t new_tot_len;
++ int found_dupack = 0;
++
++ if (flags & TCP_ACK) {
++ right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
++
++ /* Update window. */
++ if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
++ (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
++ (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
++ pcb->snd_wnd = tcphdr->wnd;
++ pcb->snd_wl1 = seqno;
++ pcb->snd_wl2 = ackno;
++ if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
++ pcb->persist_backoff = 0;
++ }
++ LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
++#if TCP_WND_DEBUG
++ } else {
++ if (pcb->snd_wnd != tcphdr->wnd) {
++ LWIP_DEBUGF(TCP_WND_DEBUG,
++ ("tcp_receive: no window update lastack %"U32_F" ackno %"
++ U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
++ pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
++ }
++#endif /* TCP_WND_DEBUG */
++ }
++
++ /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
++ * duplicate ack if:
++ * 1) It doesn't ACK new data
++ * 2) length of received packet is zero (i.e. no payload)
++ * 3) the advertised window hasn't changed
++ * 4) There is outstanding unacknowledged data (retransmission timer running)
++ * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
++ *
++ * If it passes all five, should process as a dupack:
++ * a) dupacks < 3: do nothing
++ * b) dupacks == 3: fast retransmit
++ * c) dupacks > 3: increase cwnd
++ *
++ * If it only passes 1-3, should reset dupack counter (and add to
++ * stats, which we don't do in lwIP)
++ *
++ * If it only passes 1, should reset dupack counter
++ *
++ */
++
++ /* Clause 1 */
++ if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
++ pcb->acked = 0;
++ /* Clause 2 */
++ if (tcplen == 0) {
++ /* Clause 3 */
++ if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
++ /* Clause 4 */
++ if (pcb->rtime >= 0) {
++ /* Clause 5 */
++ if (pcb->lastack == ackno) {
++ found_dupack = 1;
++ if (pcb->dupacks + 1 > pcb->dupacks)
++ ++pcb->dupacks;
++ if (pcb->dupacks > 3) {
++ /* Inflate the congestion window, but not if it means that
++ the value overflows. */
++ if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
++ pcb->cwnd += pcb->mss;
++ }
++ } else if (pcb->dupacks == 3) {
++ /* Do fast retransmit */
++ tcp_rexmit_fast(pcb);
++ }
++ }
++ }
++ }
++ }
++ /* If Clause (1) or more is true, but not a duplicate ack, reset
++ * count of consecutive duplicate acks */
++ if (!found_dupack) {
++ pcb->dupacks = 0;
++ }
++ } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
++ /* We come here when the ACK acknowledges new data. */
++
++ /* Reset the "IN Fast Retransmit" flag, since we are no longer
++ in fast retransmit. Also reset the congestion window to the
++ slow start threshold. */
++ if (pcb->flags & TF_INFR) {
++ pcb->flags &= ~TF_INFR;
++ pcb->cwnd = pcb->ssthresh;
++ }
++
++ /* Reset the number of retransmissions. */
++ pcb->nrtx = 0;
++
++ /* Reset the retransmission time-out. */
++ pcb->rto = (pcb->sa >> 3) + pcb->sv;
++
++ /* Update the send buffer space. Diff between the two can never exceed 64K? */
++ pcb->acked = (u16_t)(ackno - pcb->lastack);
++
++ pcb->snd_buf += pcb->acked;
++
++ /* Reset the fast retransmit variables. */
++ pcb->dupacks = 0;
++ pcb->lastack = ackno;
++
++ /* Update the congestion control variables (cwnd and
++ ssthresh). */
++ if (pcb->state >= ESTABLISHED) {
++ if (pcb->cwnd < pcb->ssthresh) {
++ if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
++ pcb->cwnd += pcb->mss;
++ }
++ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
++ } else {
++ u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
++ if (new_cwnd > pcb->cwnd) {
++ pcb->cwnd = new_cwnd;
++ }
++ LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
++ }
++ }
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
++ ackno,
++ pcb->unacked != NULL?
++ ntohl(pcb->unacked->tcphdr->seqno): 0,
++ pcb->unacked != NULL?
++ ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
++
++ /* Remove segment from the unacknowledged list if the incoming
++ ACK acknowlegdes them. */
++ while (pcb->unacked != NULL &&
++ TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
++ TCP_TCPLEN(pcb->unacked), ackno)) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
++ ntohl(pcb->unacked->tcphdr->seqno),
++ ntohl(pcb->unacked->tcphdr->seqno) +
++ TCP_TCPLEN(pcb->unacked)));
++
++ next = pcb->unacked;
++ pcb->unacked = pcb->unacked->next;
++
++ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
++ LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
++ /* Prevent ACK for FIN to generate a sent event */
++ if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
++ pcb->acked--;
++ }
++
++ pcb->snd_queuelen -= pbuf_clen(next->p);
++ tcp_seg_free(next);
++
++ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
++ if (pcb->snd_queuelen != 0) {
++ LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
++ pcb->unsent != NULL);
++ }
++ }
++
++ /* If there's nothing left to acknowledge, stop the retransmit
++ timer, otherwise reset it to start again */
++ if(pcb->unacked == NULL)
++ pcb->rtime = -1;
++ else
++ pcb->rtime = 0;
++
++ pcb->polltmr = 0;
++ } else {
++ /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
++ pcb->acked = 0;
++ }
++
++ /* We go through the ->unsent list to see if any of the segments
++ on the list are acknowledged by the ACK. This may seem
++ strange since an "unsent" segment shouldn't be acked. The
++ rationale is that lwIP puts all outstanding segments on the
++ ->unsent list after a retransmission, so these segments may
++ in fact have been sent once. */
++ while (pcb->unsent != NULL &&
++ TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
++ TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
++ ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
++ TCP_TCPLEN(pcb->unsent)));
++
++ next = pcb->unsent;
++ pcb->unsent = pcb->unsent->next;
++ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
++ LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
++ /* Prevent ACK for FIN to generate a sent event */
++ if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
++ pcb->acked--;
++ }
++ pcb->snd_queuelen -= pbuf_clen(next->p);
++ tcp_seg_free(next);
++ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
++ if (pcb->snd_queuelen != 0) {
++ LWIP_ASSERT("tcp_receive: valid queue length",
++ pcb->unacked != NULL || pcb->unsent != NULL);
++ }
++ }
++ /* End of ACK for new data processing. */
++
++ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
++ pcb->rttest, pcb->rtseq, ackno));
++
++ /* RTT estimation calculations. This is done by checking if the
++ incoming segment acknowledges the segment we use to take a
++ round-trip time measurement. */
++ if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
++ /* diff between this shouldn't exceed 32K since this are tcp timer ticks
++ and a round-trip shouldn't be that long... */
++ m = (s16_t)(tcp_ticks - pcb->rttest);
++
++ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
++ m, m * TCP_SLOW_INTERVAL));
++
++ /* This is taken directly from VJs original code in his paper */
++ m = m - (pcb->sa >> 3);
++ pcb->sa += m;
++ if (m < 0) {
++ m = -m;
++ }
++ m = m - (pcb->sv >> 2);
++ pcb->sv += m;
++ pcb->rto = (pcb->sa >> 3) + pcb->sv;
++
++ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
++ pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
++
++ pcb->rttest = 0;
++ }
++ }
++
++ /* If the incoming segment contains data, we must process it
++ further. */
++ if (tcplen > 0) {
++ /* This code basically does three things:
++
++ +) If the incoming segment contains data that is the next
++ in-sequence data, this data is passed to the application. This
++ might involve trimming the first edge of the data. The rcv_nxt
++ variable and the advertised window are adjusted.
++
++ +) If the incoming segment has data that is above the next
++ sequence number expected (->rcv_nxt), the segment is placed on
++ the ->ooseq queue. This is done by finding the appropriate
++ place in the ->ooseq queue (which is ordered by sequence
++ number) and trim the segment in both ends if needed. An
++ immediate ACK is sent to indicate that we received an
++ out-of-sequence segment.
++
++ +) Finally, we check if the first segment on the ->ooseq queue
++ now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
++ rcv_nxt > ooseq->seqno, we must trim the first edge of the
++ segment on ->ooseq before we adjust rcv_nxt. The data in the
++ segments that are now on sequence are chained onto the
++ incoming segment so that we only need to call the application
++ once.
++ */
++
++ /* First, we check if we must trim the first edge. We have to do
++ this if the sequence number of the incoming segment is less
++ than rcv_nxt, and the sequence number plus the length of the
++ segment is larger than rcv_nxt. */
++ /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
++ if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
++ if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
++ /* Trimming the first edge is done by pushing the payload
++ pointer in the pbuf downwards. This is somewhat tricky since
++ we do not want to discard the full contents of the pbuf up to
++ the new starting point of the data since we have to keep the
++ TCP header which is present in the first pbuf in the chain.
++
++ What is done is really quite a nasty hack: the first pbuf in
++ the pbuf chain is pointed to by inseg.p. Since we need to be
++ able to deallocate the whole pbuf, we cannot change this
++ inseg.p pointer to point to any of the later pbufs in the
++ chain. Instead, we point the ->payload pointer in the first
++ pbuf to data in one of the later pbufs. We also set the
++ inseg.data pointer to point to the right place. This way, the
++ ->p pointer will still point to the first pbuf, but the
++ ->p->payload pointer will point to data in another pbuf.
++
++ After we are done with adjusting the pbuf pointers we must
++ adjust the ->data pointer in the seg and the segment
++ length.*/
++
++ off = pcb->rcv_nxt - seqno;
++ p = inseg.p;
++ LWIP_ASSERT("inseg.p != NULL", inseg.p);
++ LWIP_ASSERT("insane offset!", (off < 0x7fff));
++ if (inseg.p->len < off) {
++ LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
++ new_tot_len = (u16_t)(inseg.p->tot_len - off);
++ while (p->len < off) {
++ off -= p->len;
++ /* KJM following line changed (with addition of new_tot_len var)
++ to fix bug #9076
++ inseg.p->tot_len -= p->len; */
++ p->tot_len = new_tot_len;
++ p->len = 0;
++ p = p->next;
++ }
++ if(pbuf_header(p, (s16_t)-off)) {
++ /* Do we need to cope with this failing? Assert for now */
++ LWIP_ASSERT("pbuf_header failed", 0);
++ }
++ } else {
++ if(pbuf_header(inseg.p, (s16_t)-off)) {
++ /* Do we need to cope with this failing? Assert for now */
++ LWIP_ASSERT("pbuf_header failed", 0);
++ }
++ }
++ inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
++ inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
++ }
++ else {
++ if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
++ /* the whole segment is < rcv_nxt */
++ /* must be a duplicate of a packet that has already been correctly handled */
++
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
++ tcp_ack_now(pcb);
++ }
++ }
++
++ /* The sequence number must be within the window (above rcv_nxt
++ and below rcv_nxt + rcv_wnd) in order to be further
++ processed. */
++ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
++ pcb->rcv_nxt + pcb->rcv_wnd - 1)){
++ if (pcb->rcv_nxt == seqno) {
++ /* The incoming segment is the next in sequence. We check if
++ we have to trim the end of the segment and update rcv_nxt
++ and pass the data to the application. */
++ tcplen = TCP_TCPLEN(&inseg);
++
++ if (tcplen > pcb->rcv_wnd) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG,
++ ("tcp_receive: other end overran receive window"
++ "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
++ seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
++ if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
++ /* Must remove the FIN from the header as we're trimming
++ * that byte of sequence-space from the packet */
++ TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
++ }
++ /* Adjust length of segment to fit in the window. */
++ inseg.len = pcb->rcv_wnd;
++ if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
++ inseg.len -= 1;
++ }
++ pbuf_realloc(inseg.p, inseg.len);
++ tcplen = TCP_TCPLEN(&inseg);
++ LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
++ (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
++ }
++#if TCP_QUEUE_OOSEQ
++ /* Received in-sequence data, adjust ooseq data if:
++ - FIN has been received or
++ - inseq overlaps with ooseq */
++ if (pcb->ooseq != NULL) {
++ if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG,
++ ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
++ /* Received in-order FIN means anything that was received
++ * out of order must now have been received in-order, so
++ * bin the ooseq queue */
++ while (pcb->ooseq != NULL) {
++ struct tcp_seg *old_ooseq = pcb->ooseq;
++ pcb->ooseq = pcb->ooseq->next;
++ tcp_seg_free(old_ooseq);
++ }
++ }
++ else {
++ next = pcb->ooseq;
++ /* Remove all segments on ooseq that are covered by inseg already.
++ * FIN is copied from ooseq to inseg if present. */
++ while (next &&
++ TCP_SEQ_GEQ(seqno + tcplen,
++ next->tcphdr->seqno + next->len)) {
++ /* inseg cannot have FIN here (already processed above) */
++ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
++ (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
++ TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
++ tcplen = TCP_TCPLEN(&inseg);
++ }
++ prev = next;
++ next = next->next;
++ tcp_seg_free(prev);
++ }
++ /* Now trim right side of inseg if it overlaps with the first
++ * segment on ooseq */
++ if (next &&
++ TCP_SEQ_GT(seqno + tcplen,
++ next->tcphdr->seqno)) {
++ /* inseg cannot have FIN here (already processed above) */
++ inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
++ if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
++ inseg.len -= 1;
++ }
++ pbuf_realloc(inseg.p, inseg.len);
++ tcplen = TCP_TCPLEN(&inseg);
++ LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
++ (seqno + tcplen) == next->tcphdr->seqno);
++ }
++ pcb->ooseq = next;
++ }
++ }
++#endif /* TCP_QUEUE_OOSEQ */
++
++ pcb->rcv_nxt = seqno + tcplen;
++
++ /* Update the receiver's (our) window. */
++ LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
++ pcb->rcv_wnd -= tcplen;
++
++ tcp_update_rcv_ann_wnd(pcb);
++
++ /* If there is data in the segment, we make preparations to
++ pass this up to the application. The ->recv_data variable
++ is used for holding the pbuf that goes to the
++ application. The code for reassembling out-of-sequence data
++ chains its data on this pbuf as well.
++
++ If the segment was a FIN, we set the TF_GOT_FIN flag that will
++ be used to indicate to the application that the remote side has
++ closed its end of the connection. */
++ if (inseg.p->tot_len > 0) {
++ recv_data = inseg.p;
++ /* Since this pbuf now is the responsibility of the
++ application, we delete our reference to it so that we won't
++ (mistakingly) deallocate it. */
++ inseg.p = NULL;
++ }
++ if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
++ recv_flags |= TF_GOT_FIN;
++ }
++
++#if TCP_QUEUE_OOSEQ
++ /* We now check if we have segments on the ->ooseq queue that
++ are now in sequence. */
++ while (pcb->ooseq != NULL &&
++ pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
++
++ cseg = pcb->ooseq;
++ seqno = pcb->ooseq->tcphdr->seqno;
++
++ pcb->rcv_nxt += TCP_TCPLEN(cseg);
++ LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
++ pcb->rcv_wnd >= TCP_TCPLEN(cseg));
++ pcb->rcv_wnd -= TCP_TCPLEN(cseg);
++
++ tcp_update_rcv_ann_wnd(pcb);
++
++ if (cseg->p->tot_len > 0) {
++ /* Chain this pbuf onto the pbuf that we will pass to
++ the application. */
++ if (recv_data) {
++ pbuf_cat(recv_data, cseg->p);
++ } else {
++ recv_data = cseg->p;
++ }
++ cseg->p = NULL;
++ }
++ if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
++ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
++ recv_flags |= TF_GOT_FIN;
++ if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
++ pcb->state = CLOSE_WAIT;
++ }
++ }
++
++ pcb->ooseq = cseg->next;
++ tcp_seg_free(cseg);
++ }
++#endif /* TCP_QUEUE_OOSEQ */
++
++
++ /* Acknowledge the segment(s). */
++ tcp_ack(pcb);
++
++ } else {
++ /* We get here if the incoming segment is out-of-sequence. */
++ tcp_send_empty_ack(pcb);
++#if TCP_QUEUE_OOSEQ
++ /* We queue the segment on the ->ooseq queue. */
++ if (pcb->ooseq == NULL) {
++ pcb->ooseq = tcp_seg_copy(&inseg);
++ } else {
++ /* If the queue is not empty, we walk through the queue and
++ try to find a place where the sequence number of the
++ incoming segment is between the sequence numbers of the
++ previous and the next segment on the ->ooseq queue. That is
++ the place where we put the incoming segment. If needed, we
++ trim the second edges of the previous and the incoming
++ segment so that it will fit into the sequence.
++
++ If the incoming segment has the same sequence number as a
++ segment on the ->ooseq queue, we discard the segment that
++ contains less data. */
++
++ prev = NULL;
++ for(next = pcb->ooseq; next != NULL; next = next->next) {
++ if (seqno == n