[TCPIP]
authorCameron Gutman <aicommander@gmail.com>
Sun, 7 Aug 2011 19:13:23 +0000 (19:13 +0000)
committerCameron Gutman <aicommander@gmail.com>
Sun, 7 Aug 2011 19:13:23 +0000 (19:13 +0000)
- 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

178 files changed:
1  2 
reactos/drivers/network/tcpip/CMakeLists.txt
reactos/drivers/network/tcpip/include/precomp.h
reactos/drivers/network/tcpip/include/tcp.h
reactos/drivers/network/tcpip/include/tcpip.h
reactos/drivers/network/tcpip/include/titypes.h
reactos/drivers/network/tcpip/tcpip.rbuild
reactos/drivers/network/tcpip/tcpip/dispatch.c
reactos/drivers/network/tcpip/tcpip/fileobjs.c
reactos/drivers/network/tcpip/tcpip/main.c
reactos/lib/drivers/CMakeLists.txt
reactos/lib/drivers/directory.rbuild
reactos/lib/drivers/ip/CMakeLists.txt
reactos/lib/drivers/ip/ip.rbuild
reactos/lib/drivers/ip/network/ip.c
reactos/lib/drivers/ip/network/routines.c
reactos/lib/drivers/ip/precomp.h
reactos/lib/drivers/ip/transport/tcp/accept.c
reactos/lib/drivers/ip/transport/tcp/event.c
reactos/lib/drivers/ip/transport/tcp/if.c
reactos/lib/drivers/ip/transport/tcp/tcp.c
reactos/lib/drivers/lwip/CHANGELOG
reactos/lib/drivers/lwip/CMakeLists.txt
reactos/lib/drivers/lwip/COPYING
reactos/lib/drivers/lwip/FILES
reactos/lib/drivers/lwip/README
reactos/lib/drivers/lwip/UPGRADING
reactos/lib/drivers/lwip/doc/FILES
reactos/lib/drivers/lwip/doc/contrib.txt
reactos/lib/drivers/lwip/doc/rawapi.txt
reactos/lib/drivers/lwip/doc/savannah.txt
reactos/lib/drivers/lwip/doc/snmp_agent.txt
reactos/lib/drivers/lwip/doc/sys_arch.txt
reactos/lib/drivers/lwip/lwip.rbuild
reactos/lib/drivers/lwip/src/FILES
reactos/lib/drivers/lwip/src/api/api_lib.c
reactos/lib/drivers/lwip/src/api/api_msg.c
reactos/lib/drivers/lwip/src/api/err.c
reactos/lib/drivers/lwip/src/api/netbuf.c
reactos/lib/drivers/lwip/src/api/netdb.c
reactos/lib/drivers/lwip/src/api/netifapi.c
reactos/lib/drivers/lwip/src/api/sockets.c
reactos/lib/drivers/lwip/src/api/tcpip.c
reactos/lib/drivers/lwip/src/core/def.c
reactos/lib/drivers/lwip/src/core/dhcp.c
reactos/lib/drivers/lwip/src/core/dns.c
reactos/lib/drivers/lwip/src/core/init.c
reactos/lib/drivers/lwip/src/core/ipv4/autoip.c
reactos/lib/drivers/lwip/src/core/ipv4/icmp.c
reactos/lib/drivers/lwip/src/core/ipv4/igmp.c
reactos/lib/drivers/lwip/src/core/ipv4/inet.c
reactos/lib/drivers/lwip/src/core/ipv4/inet_chksum.c
reactos/lib/drivers/lwip/src/core/ipv4/ip.c
reactos/lib/drivers/lwip/src/core/ipv4/ip_addr.c
reactos/lib/drivers/lwip/src/core/ipv4/ip_frag.c
reactos/lib/drivers/lwip/src/core/ipv6/README
reactos/lib/drivers/lwip/src/core/ipv6/icmp6.c
reactos/lib/drivers/lwip/src/core/ipv6/inet6.c
reactos/lib/drivers/lwip/src/core/ipv6/ip6.c
reactos/lib/drivers/lwip/src/core/ipv6/ip6_addr.c
reactos/lib/drivers/lwip/src/core/mem.c
reactos/lib/drivers/lwip/src/core/memp.c
reactos/lib/drivers/lwip/src/core/netif.c
reactos/lib/drivers/lwip/src/core/pbuf.c
reactos/lib/drivers/lwip/src/core/raw.c
reactos/lib/drivers/lwip/src/core/snmp/asn1_dec.c
reactos/lib/drivers/lwip/src/core/snmp/asn1_enc.c
reactos/lib/drivers/lwip/src/core/snmp/mib2.c
reactos/lib/drivers/lwip/src/core/snmp/mib_structs.c
reactos/lib/drivers/lwip/src/core/snmp/msg_in.c
reactos/lib/drivers/lwip/src/core/snmp/msg_out.c
reactos/lib/drivers/lwip/src/core/stats.c
reactos/lib/drivers/lwip/src/core/sys.c
reactos/lib/drivers/lwip/src/core/tcp.c
reactos/lib/drivers/lwip/src/core/tcp_in.c
reactos/lib/drivers/lwip/src/core/tcp_out.c
reactos/lib/drivers/lwip/src/core/timers.c
reactos/lib/drivers/lwip/src/core/udp.c
reactos/lib/drivers/lwip/src/include/arch/bpstruct.h
reactos/lib/drivers/lwip/src/include/arch/cc.h
reactos/lib/drivers/lwip/src/include/arch/epstruct.h
reactos/lib/drivers/lwip/src/include/arch/perf.h
reactos/lib/drivers/lwip/src/include/arch/sys_arch.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/autoip.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/icmp.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/igmp.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/inet.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/inet_chksum.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/ip.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/ip_addr.h
reactos/lib/drivers/lwip/src/include/ipv4/lwip/ip_frag.h
reactos/lib/drivers/lwip/src/include/ipv6/lwip/icmp.h
reactos/lib/drivers/lwip/src/include/ipv6/lwip/inet.h
reactos/lib/drivers/lwip/src/include/ipv6/lwip/ip.h
reactos/lib/drivers/lwip/src/include/ipv6/lwip/ip_addr.h
reactos/lib/drivers/lwip/src/include/lwip/api.h
reactos/lib/drivers/lwip/src/include/lwip/api_msg.h
reactos/lib/drivers/lwip/src/include/lwip/arch.h
reactos/lib/drivers/lwip/src/include/lwip/debug.h
reactos/lib/drivers/lwip/src/include/lwip/def.h
reactos/lib/drivers/lwip/src/include/lwip/dhcp.h
reactos/lib/drivers/lwip/src/include/lwip/dns.h
reactos/lib/drivers/lwip/src/include/lwip/err.h
reactos/lib/drivers/lwip/src/include/lwip/init.h
reactos/lib/drivers/lwip/src/include/lwip/mem.h
reactos/lib/drivers/lwip/src/include/lwip/memp.h
reactos/lib/drivers/lwip/src/include/lwip/memp_std.h
reactos/lib/drivers/lwip/src/include/lwip/netbuf.h
reactos/lib/drivers/lwip/src/include/lwip/netdb.h
reactos/lib/drivers/lwip/src/include/lwip/netif.h
reactos/lib/drivers/lwip/src/include/lwip/netifapi.h
reactos/lib/drivers/lwip/src/include/lwip/opt.h
reactos/lib/drivers/lwip/src/include/lwip/pbuf.h
reactos/lib/drivers/lwip/src/include/lwip/raw.h
reactos/lib/drivers/lwip/src/include/lwip/sio.h
reactos/lib/drivers/lwip/src/include/lwip/snmp.h
reactos/lib/drivers/lwip/src/include/lwip/snmp_asn1.h
reactos/lib/drivers/lwip/src/include/lwip/snmp_msg.h
reactos/lib/drivers/lwip/src/include/lwip/snmp_structs.h
reactos/lib/drivers/lwip/src/include/lwip/sockets.h
reactos/lib/drivers/lwip/src/include/lwip/stats.h
reactos/lib/drivers/lwip/src/include/lwip/sys.h
reactos/lib/drivers/lwip/src/include/lwip/tcp.h
reactos/lib/drivers/lwip/src/include/lwip/tcp_impl.h
reactos/lib/drivers/lwip/src/include/lwip/tcpip.h
reactos/lib/drivers/lwip/src/include/lwip/timers.h
reactos/lib/drivers/lwip/src/include/lwip/udp.h
reactos/lib/drivers/lwip/src/include/lwipopts.h
reactos/lib/drivers/lwip/src/include/netif/etharp.h
reactos/lib/drivers/lwip/src/include/netif/loopif.h
reactos/lib/drivers/lwip/src/include/netif/ppp_oe.h
reactos/lib/drivers/lwip/src/include/netif/slipif.h
reactos/lib/drivers/lwip/src/include/rosip.h
reactos/lib/drivers/lwip/src/netif/FILES
reactos/lib/drivers/lwip/src/netif/etharp.c
reactos/lib/drivers/lwip/src/netif/ethernetif.c
reactos/lib/drivers/lwip/src/netif/loopif.c
reactos/lib/drivers/lwip/src/netif/ppp/auth.c
reactos/lib/drivers/lwip/src/netif/ppp/auth.h
reactos/lib/drivers/lwip/src/netif/ppp/chap.c
reactos/lib/drivers/lwip/src/netif/ppp/chap.h
reactos/lib/drivers/lwip/src/netif/ppp/chpms.c
reactos/lib/drivers/lwip/src/netif/ppp/chpms.h
reactos/lib/drivers/lwip/src/netif/ppp/fsm.c
reactos/lib/drivers/lwip/src/netif/ppp/fsm.h
reactos/lib/drivers/lwip/src/netif/ppp/ipcp.c
reactos/lib/drivers/lwip/src/netif/ppp/ipcp.h
reactos/lib/drivers/lwip/src/netif/ppp/lcp.c
reactos/lib/drivers/lwip/src/netif/ppp/lcp.h
reactos/lib/drivers/lwip/src/netif/ppp/magic.c
reactos/lib/drivers/lwip/src/netif/ppp/magic.h
reactos/lib/drivers/lwip/src/netif/ppp/md5.c
reactos/lib/drivers/lwip/src/netif/ppp/md5.h
reactos/lib/drivers/lwip/src/netif/ppp/pap.c
reactos/lib/drivers/lwip/src/netif/ppp/pap.h
reactos/lib/drivers/lwip/src/netif/ppp/ppp.c
reactos/lib/drivers/lwip/src/netif/ppp/ppp.h
reactos/lib/drivers/lwip/src/netif/ppp/ppp_oe.c
reactos/lib/drivers/lwip/src/netif/ppp/pppdebug.h
reactos/lib/drivers/lwip/src/netif/ppp/randm.c
reactos/lib/drivers/lwip/src/netif/ppp/randm.h
reactos/lib/drivers/lwip/src/netif/ppp/vj.c
reactos/lib/drivers/lwip/src/netif/ppp/vj.h
reactos/lib/drivers/lwip/src/netif/ppp/vjbsdhdr.h
reactos/lib/drivers/lwip/src/netif/slipif.c
reactos/lib/drivers/lwip/src/rosip.c
reactos/lib/drivers/lwip/src/rosmem.c
reactos/lib/drivers/lwip/src/rostcp.c
reactos/lib/drivers/lwip/src/sys_arch.c
reactos/lib/drivers/lwip/test/unit/lwip_check.h
reactos/lib/drivers/lwip/test/unit/lwip_unittests.c
reactos/lib/drivers/lwip/test/unit/tcp/tcp_helper.c
reactos/lib/drivers/lwip/test/unit/tcp/tcp_helper.h
reactos/lib/drivers/lwip/test/unit/tcp/test_tcp.c
reactos/lib/drivers/lwip/test/unit/tcp/test_tcp.h
reactos/lib/drivers/lwip/test/unit/tcp/test_tcp_oos.c
reactos/lib/drivers/lwip/test/unit/tcp/test_tcp_oos.h
reactos/lib/drivers/lwip/test/unit/udp/test_udp.c
reactos/lib/drivers/lwip/test/unit/udp/test_udp.h

index 3fcb941,0000000..ce6f84b
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,213 @@@
- /* 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);
index c759a9d,0000000..7bc8ce3
mode 100644,000000..100644
--- /dev/null
@@@ -1,315 -1,0 +1,318 @@@
-     /* 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 */
index f3c6114,0000000..698254d
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,38 @@@
-       <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>
index 75c1cfb,0000000..65e0f96
mode 100644,000000..100644
--- /dev/null
@@@ -1,1650 -1,0 +1,1606 @@@
-   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 */
index f7ead95,0000000..e47f700
mode 100644,000000..100644
--- /dev/null
@@@ -1,552 -1,0 +1,551 @@@
-       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 */
Simple merge
index 3f84d44,0000000..2c0c011
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
-       <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>
Simple merge
index 21dd265,0000000..3eea383
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,46 @@@
-       <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>
Simple merge
index 44aa276,0000000..db32eee
mode 100644,000000..100644
--- /dev/null
@@@ -1,177 -1,0 +1,104 @@@
- 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
 +}
 +
Simple merge
index 4534da3,0000000..40cfafd
mode 100644,000000..100644
--- /dev/null
@@@ -1,249 -1,0 +1,528 @@@
-  * 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);
 +}
index 951e807,0000000..ce46f95
mode 100644,000000..100644
--- /dev/null
@@@ -1,1193 -1,0 +1,676 @@@
- 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 */
index 0000000,d0e15f2..d0e15f2
mode 000000,100644..100644
--- /dev/null
index 0000000,973dd81..973dd81
mode 000000,100644..100644
--- /dev/null
index 0000000,e23898b..e23898b
mode 000000,100644..100644
--- /dev/null
index 0000000,6625319..6625319
mode 000000,100644..100644
--- /dev/null
index 0000000,a62cc4f..a62cc4f
mode 000000,100644..100644
--- /dev/null
index 0000000,215ad88..215ad88
mode 000000,100644..100644
--- /dev/null
index 0000000,05d356f..05d356f
mode 000000,100644..100644
--- /dev/null
index 0000000,65f82bc..65f82bc
mode 000000,100644..100644
--- /dev/null
index 0000000,0000000..7059ccd
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++<?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>
index 0000000,952aeab..952aeab
mode 000000,100644..100644
--- /dev/null
index 0000000,92fa8b7..92fa8b7
mode 000000,100644..100644
--- /dev/null
index 0000000,352b552..352b552
mode 000000,100644..100644
--- /dev/null
index 0000000,d633612..d633612
mode 000000,100644..100644
--- /dev/null
index 0000000,9837555..9837555
mode 000000,100644..100644
--- /dev/null
index 0000000,9fcb100..9fcb100
mode 000000,100644..100644
--- /dev/null
index 0000000,d3a77de..d3a77de
mode 000000,100644..100644
--- /dev/null
index 0000000,c629bc4..c629bc4
mode 000000,100644..100644
--- /dev/null
index 0000000,0000000..e1bfe88
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1585 @@@
++/**
++ * @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(&current_iphdr_dest, inp) ||
++      ip_addr_ismulticast(&current_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), &current_iphdr_src) &&
++       ip_addr_cmp(&(pcb->local_ip), &current_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), &current_iphdr_src) &&
++         ip_addr_cmp(&(pcb->local_ip), &current_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), &current_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), &current_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