- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / tcpip / main.c
index 0dab08f..9b547b9 100644 (file)
@@ -7,20 +7,15 @@
  * REVISIONS:
  *   CSH 01/08-2000 Created
  */
-#include <tcpip.h>
-#include <dispatch.h>
-#include <fileobjs.h>
-#include <datagram.h>
-#include <loopback.h>
-#include <rawip.h>
-#include <udp.h>
-#include <tcp.h>
+#include "precomp.h"
 
+#define NDEBUG
 
-#ifdef DBG
-/* See debug.h for debug/trace constants */
-DWORD DebugTraceLevel = MIN_TRACE;
-#endif /* DBG */
+#ifndef NDEBUG
+DWORD DebugTraceLevel = DEBUG_ULTRA & ~(DEBUG_LOCK | DEBUG_PBUFFER);
+#else
+DWORD DebugTraceLevel = 0;
+#endif /* NDEBUG */
 
 PDEVICE_OBJECT TCPDeviceObject   = NULL;
 PDEVICE_OBJECT UDPDeviceObject   = NULL;
@@ -28,10 +23,17 @@ PDEVICE_OBJECT IPDeviceObject    = NULL;
 PDEVICE_OBJECT RawIPDeviceObject = NULL;
 NDIS_HANDLE GlobalPacketPool     = NULL;
 NDIS_HANDLE GlobalBufferPool     = NULL;
-TDIEntityID *EntityList          = NULL;
+KSPIN_LOCK EntityListLock;
+TDIEntityInfo *EntityList        = NULL;
 ULONG EntityCount                = 0;
+ULONG EntityMax                  = 0;
 UDP_STATISTICS UDPStats;
 
+/* Network timers */
+KTIMER IPTimer;
+KDPC IPTimeoutDpc;
+KSPIN_LOCK IpWorkLock;
+WORK_QUEUE_ITEM IpWorkItem;
 
 VOID TiWriteErrorLog(
     PDRIVER_OBJECT DriverContext,
@@ -48,7 +50,8 @@ VOID TiWriteErrorLog(
  *     ErrorCode        = An error code to put in the log entry
  *     UniqueErrorValue = UniqueErrorValue in the error log packet
  *     FinalStatus      = FinalStatus in the error log packet
- *     String           = If not NULL, a pointer to a string to put in log entry
+ *     String           = If not NULL, a pointer to a string to put in log
+ *                        entry
  *     DumpDataCount    = Number of ULONGs of dump data
  *     DumpData         = Pointer to dump data for the log entry
  */
@@ -60,7 +63,7 @@ VOID TiWriteErrorLog(
     PUCHAR pString;
     static WCHAR DriverName[] = L"TCP/IP";
 
-    EntrySize = sizeof(IO_ERROR_LOG_PACKET) + 
+    EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
         (DumpDataCount * sizeof(ULONG)) + sizeof(DriverName);
 
     if (String) {
@@ -99,7 +102,6 @@ VOID TiWriteErrorLog(
 #endif
 }
 
-
 /*
  * FUNCTION: Creates a file object
  * ARGUMENTS:
@@ -108,84 +110,161 @@ VOID TiWriteErrorLog(
  * RETURNS:
  *     Status of the operation
  */
+
 NTSTATUS TiCreateFileObject(
-    PDEVICE_OBJECT DeviceObject,
-    PIRP Irp)
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
 {
-    PIO_STACK_LOCATION IrpSp;
-    PFILE_FULL_EA_INFORMATION EaInfo;
-    PTA_ADDRESS_IP Address;
-    PTRANSPORT_CONTEXT Context;
-    TDI_REQUEST Request;
-    NTSTATUS Status;
-
-    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
-
-    EaInfo = Irp->AssociatedIrp.SystemBuffer;
-
-    /* Parameter check */
-    if (!EaInfo) {
-        TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n"));
+  PFILE_FULL_EA_INFORMATION EaInfo;
+  PTRANSPORT_CONTEXT Context;
+  PIO_STACK_LOCATION IrpSp;
+  PTA_IP_ADDRESS Address;
+  TDI_REQUEST Request;
+  PVOID ClientContext;
+  NTSTATUS Status;
+  ULONG Protocol;
+
+  TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
+
+  EaInfo = Irp->AssociatedIrp.SystemBuffer;
+CP
+  /* Parameter check */
+  /* No EA information means that we're opening for SET/QUERY_INFORMATION
+   * style calls. */
+#if 0
+  if (!EaInfo) {
+    TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n"));
+    return STATUS_INVALID_PARAMETER;
+  }
+#endif
+CP
+  /* Allocate resources here. We release them again if something failed */
+  Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT));
+  if (!Context) {
+    TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+CP
+  Context->CancelIrps = FALSE;
+  KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE);
+CP
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
+  IrpSp->FileObject->FsContext = Context;
+  Request.RequestContext       = Irp;
+CP
+  /* Branch to the right handler */
+  if (EaInfo &&
+      (EaInfo->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH) &&
+      (RtlCompareMemory
+       (&EaInfo->EaName, TdiTransportAddress,
+       TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) {
+    /* This is a request to open an address */
+CP
+
+       /* XXX This should probably be done in IoCreateFile() */
+    /* Parameter checks */
+
+    Address = (PTA_IP_ADDRESS)(EaInfo->EaName + EaInfo->EaNameLength + 1); //0-term
+
+    if ((EaInfo->EaValueLength < sizeof(TA_IP_ADDRESS)) ||
+      (Address->TAAddressCount != 1) ||
+      (Address->Address[0].AddressLength < TDI_ADDRESS_LENGTH_IP) ||
+      (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) {
+      TI_DbgPrint(MIN_TRACE, ("Parameters are invalid:\n"));
+      TI_DbgPrint(MIN_TRACE, ("AddressCount: %d\n", Address->TAAddressCount));
+      if( Address->TAAddressCount == 1 ) {
+         TI_DbgPrint(MIN_TRACE, ("AddressLength: %\n",
+                                 Address->Address[0].AddressLength));
+         TI_DbgPrint(MIN_TRACE, ("AddressType: %\n",
+                                 Address->Address[0].AddressType));
+      }
+      PoolFreeBuffer(Context);
+      return STATUS_INVALID_PARAMETER;
+    }
+CP
+    /* Open address file object */
+
+    /* Protocol depends on device object so find the protocol */
+    if (DeviceObject == TCPDeviceObject)
+      Protocol = IPPROTO_TCP;
+    else if (DeviceObject == UDPDeviceObject)
+      Protocol = IPPROTO_UDP;
+    else if (DeviceObject == IPDeviceObject)
+      Protocol = IPPROTO_RAW;
+    else if (DeviceObject == RawIPDeviceObject) {
+      Status = TiGetProtocolNumber(&IrpSp->FileObject->FileName, &Protocol);
+      if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Raw IP protocol number is invalid.\n"));
+        PoolFreeBuffer(Context);
         return STATUS_INVALID_PARAMETER;
+      }
+    } else {
+      TI_DbgPrint(MIN_TRACE, ("Invalid device object at (0x%X).\n", DeviceObject));
+      PoolFreeBuffer(Context);
+      return STATUS_INVALID_PARAMETER;
+    }
+CP
+    Status = FileOpenAddress(&Request, Address, Protocol, NULL);
+    if (NT_SUCCESS(Status)) {
+      IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+      Context->Handle.AddressHandle = Request.Handle.AddressHandle;
     }
-    
-    /* Allocate resources here. We release them again if something failed */
-    Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT));
-    if (!Context) {
-        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-        return STATUS_INSUFFICIENT_RESOURCES;
+CP
+  } else if (EaInfo &&
+            (EaInfo->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH) &&
+            (RtlCompareMemory
+             (&EaInfo->EaName, TdiConnectionContext,
+              TDI_CONNECTION_CONTEXT_LENGTH) ==
+             TDI_CONNECTION_CONTEXT_LENGTH)) {
+    /* This is a request to open a connection endpoint */
+CP
+    /* Parameter checks */
+
+    if (EaInfo->EaValueLength < sizeof(PVOID)) {
+      TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
+      PoolFreeBuffer(Context);
+      return STATUS_INVALID_PARAMETER;
     }
 
-    Context->RefCount   = 1;
-    Context->CancelIrps = FALSE;
-    KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE);
-
-    IrpSp = IoGetCurrentIrpStackLocation(Irp);
-    IrpSp->FileObject->FsContext = Context;
-    Request.RequestContext       = Irp;
-
-    /* Branch to the right handler */
-    if ((EaInfo->EaNameLength==TDI_TRANSPORT_ADDRESS_LENGTH) && 
-        (RtlCompareMemory(&EaInfo->EaName, TdiTransportAddress,
-         TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) {
-        /* This is a request to open an address */
-
-        /* Parameter checks */
-        Address = (PTA_ADDRESS_IP)(EaInfo->EaName + EaInfo->EaNameLength + 1);
-        if ((EaInfo->EaValueLength < sizeof(TA_ADDRESS_IP)) ||
-            (Address->TAAddressCount != 1) ||
-            (Address->Address[0].AddressLength < sizeof(TDI_ADDRESS_IP)) ||
-            (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) {
-            TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
-            ExFreePool(Context);
-            return STATUS_INVALID_PARAMETER;
-        }
-
-        /* Open address file object */
-        /* FIXME: Protocol depends on device object */
-        Status = FileOpenAddress(&Request, Address, IPPROTO_UDP, NULL);
-        if (NT_SUCCESS(Status)) {
-            IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
-            Context->Handle.AddressHandle = Request.Handle.AddressHandle;
-        }
-    } else {
-        TI_DbgPrint(MIN_TRACE, ("Connection point, and control connections are not supported.\n"));
-        /* FIXME: Open a connection endpoint, or control connection */
-        Status = STATUS_NOT_IMPLEMENTED;
+    /* Can only do connection oriented communication using TCP */
+
+    if (DeviceObject != TCPDeviceObject) {
+      TI_DbgPrint(MIN_TRACE, ("Bad device object.\n"));
+      PoolFreeBuffer(Context);
+      return STATUS_INVALID_PARAMETER;
     }
 
-    if (!NT_SUCCESS(Status))
-        ExFreePool(Context);
+    ClientContext = *((PVOID*)(EaInfo->EaName + EaInfo->EaNameLength));
 
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+    /* Open connection endpoint file object */
 
-    return Status;
+    Status = FileOpenConnection(&Request, ClientContext);
+    if (NT_SUCCESS(Status)) {
+      IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
+      Context->Handle.ConnectionContext = Request.Handle.ConnectionContext;
+    }
+  } else {
+    /* This is a request to open a control connection */
+    Status = FileOpenControlChannel(&Request);
+    if (NT_SUCCESS(Status)) {
+      IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONTROL_CHANNEL_FILE;
+      Context->Handle.ControlChannel = Request.Handle.ControlChannel;
+    }
+  }
+
+  if (!NT_SUCCESS(Status))
+    PoolFreeBuffer(Context);
+
+  TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+
+  Irp->IoStatus.Status = Status;
+  return Status;
 }
 
 
 VOID TiCleanupFileObjectComplete(
-    PVOID Context,
-    NTSTATUS Status)
+  PVOID Context,
+  NTSTATUS Status)
 /*
  * FUNCTION: Completes an object cleanup IRP I/O request
  * ARGUMENTS:
@@ -193,30 +272,22 @@ VOID TiCleanupFileObjectComplete(
  *     Status  = Final status of the operation
  */
 {
-    PIRP Irp;
-    PIO_STACK_LOCATION IrpSp;
-    PTRANSPORT_CONTEXT TranContext;
-    KIRQL OldIrql;
+  PIRP Irp;
+  PIO_STACK_LOCATION IrpSp;
+  PTRANSPORT_CONTEXT TranContext;
+  KIRQL OldIrql;
 
-    Irp         = (PIRP)Context;
-    IrpSp       = IoGetCurrentIrpStackLocation(Irp);
-    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+  Irp         = (PIRP)Context;
+  IrpSp       = IoGetCurrentIrpStackLocation(Irp);
+  TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
 
-    Irp->IoStatus.Status = Status;
-    
-    IoAcquireCancelSpinLock(&OldIrql);
-
-    /* Remove the initial reference provided at object creation time */
-    TranContext->RefCount--;
+  Irp->IoStatus.Status = Status;
 
-#ifdef DBG
-    if (TranContext->RefCount != 0)
-        TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount is %i, should be 0.\n", TranContext->RefCount));
-#endif
+  IoAcquireCancelSpinLock(&OldIrql);
 
-    KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
+  KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
 
-    IoReleaseCancelSpinLock(OldIrql);
+  IoReleaseCancelSpinLock(OldIrql);
 }
 
 
@@ -231,73 +302,74 @@ VOID TiCleanupFileObjectComplete(
  *     This function does not pend
  */
 NTSTATUS TiCleanupFileObject(
-    PDEVICE_OBJECT DeviceObject,
-    PIRP Irp)
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
 {
-    PIO_STACK_LOCATION IrpSp;
-    PTRANSPORT_CONTEXT Context;
-    TDI_REQUEST Request;
-    NTSTATUS Status;
-    KIRQL OldIrql;
-
-    IrpSp   = IoGetCurrentIrpStackLocation(Irp);
-    Context = IrpSp->FileObject->FsContext;    
-    if (!Context) {
-        TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
-        return STATUS_INVALID_PARAMETER;
-    }
+  PIO_STACK_LOCATION IrpSp;
+  PTRANSPORT_CONTEXT Context;
+  TDI_REQUEST Request;
+  NTSTATUS Status;
+  KIRQL OldIrql;
 
-    IoAcquireCancelSpinLock(&OldIrql);
+  IrpSp   = IoGetCurrentIrpStackLocation(Irp);
+  Context = IrpSp->FileObject->FsContext;
+  if (!Context) {
+    TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
+    return STATUS_INVALID_PARAMETER;
+  }
 
-    Context->CancelIrps = TRUE;
-    KeResetEvent(&Context->CleanupEvent);
+  IoAcquireCancelSpinLock(&OldIrql);
 
-    IoReleaseCancelSpinLock(OldIrql);
+  Context->CancelIrps = TRUE;
+  KeResetEvent(&Context->CleanupEvent);
 
-    Request.RequestNotifyObject = TiCleanupFileObjectComplete;
-    Request.RequestContext      = Irp;
+  IoReleaseCancelSpinLock(OldIrql);
 
-    switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
-    case TDI_TRANSPORT_ADDRESS_FILE:
-        Request.Handle.AddressHandle = Context->Handle.AddressHandle;
-        Status = FileCloseAddress(&Request);
-        break;
+  Request.RequestNotifyObject = TiCleanupFileObjectComplete;
+  Request.RequestContext      = Irp;
 
-    case TDI_CONNECTION_FILE:
-        Request.Handle.ConnectionContext = Context->Handle.ConnectionContext;
-        Status = FileCloseConnection(&Request);
-        break;
+  switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
+  case TDI_TRANSPORT_ADDRESS_FILE:
+    Request.Handle.AddressHandle = Context->Handle.AddressHandle;
+    Status = FileCloseAddress(&Request);
+    break;
 
-    case TDI_CONTROL_CHANNEL_FILE:
-        Request.Handle.ControlChannel = Context->Handle.ControlChannel;
-        Status = FileCloseControlChannel(&Request);
-        break;
+  case TDI_CONNECTION_FILE:
+    Request.Handle.ConnectionContext = Context->Handle.ConnectionContext;
+    Status = FileCloseConnection(&Request);
+    break;
 
-    default:
-        /* This should never happen */
+  case TDI_CONTROL_CHANNEL_FILE:
+    Request.Handle.ControlChannel = Context->Handle.ControlChannel;
+    Status = FileCloseControlChannel(&Request);
+    break;
 
-        TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n"));
+  default:
+    /* This should never happen */
 
-        IoAcquireCancelSpinLock(&OldIrql);
-        Context->CancelIrps = FALSE;
-        IoReleaseCancelSpinLock(OldIrql);
+    TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n"));
 
-        return STATUS_INVALID_PARAMETER;
-    }
+    IoAcquireCancelSpinLock(&OldIrql);
+    Context->CancelIrps = FALSE;
+    IoReleaseCancelSpinLock(OldIrql);
 
-    if (Status != STATUS_PENDING)
-       TiCleanupFileObjectComplete(Irp, Status);
-    
-    KeWaitForSingleObject(&Context->CleanupEvent,
-        UserRequest, KernelMode, FALSE, NULL);
-    
-    return Irp->IoStatus.Status;
+    return STATUS_INVALID_PARAMETER;
+  }
+
+  if (Status != STATUS_PENDING)
+    TiCleanupFileObjectComplete(Irp, Status);
+
+  KeWaitForSingleObject(&Context->CleanupEvent,
+    UserRequest, KernelMode, FALSE, NULL);
+
+  return Irp->IoStatus.Status;
 }
 
 
-NTSTATUS TiDispatchOpenClose(
-    PDEVICE_OBJECT DeviceObject,
-    PIRP Irp)
+NTSTATUS STDCALL
+TiDispatchOpenClose(
+  IN PDEVICE_OBJECT DeviceObject,
+  IN PIRP Irp)
 /*
  * FUNCTION: Main dispath routine
  * ARGUMENTS:
@@ -307,60 +379,57 @@ NTSTATUS TiDispatchOpenClose(
  *     Status of the operation
  */
 {
-    PIO_STACK_LOCATION IrpSp;
-    NTSTATUS Status;
-    PTRANSPORT_CONTEXT Context;
-
-    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
-
-    IoMarkIrpPending(Irp);
-    Irp->IoStatus.Status      = STATUS_PENDING;
-    Irp->IoStatus.Information = 0;
-
-    IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
-    switch (IrpSp->MajorFunction) {
-    /* Open an address file, connection endpoint, or control connection */
-    case IRP_MJ_CREATE:
-        Status = TiCreateFileObject(DeviceObject, Irp);
-        break;
-
-    /* Close an address file, connection endpoint, or control connection */
-    case IRP_MJ_CLOSE:
-        Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
-        if (Context)
-            ExFreePool(Context);
-        Status = STATUS_SUCCESS;
-        break;
-
-    /* Release resources bound to an address file, connection endpoint, 
-       or control connection */
-    case IRP_MJ_CLEANUP:
-        Status = TiCleanupFileObject(DeviceObject, Irp);
-        break;
-
-       default:
-        Status = STATUS_INVALID_DEVICE_REQUEST;
-    }
+  PIO_STACK_LOCATION IrpSp;
+  NTSTATUS Status;
+  PTRANSPORT_CONTEXT Context;
 
-    if (Status != STATUS_PENDING) {
-        IrpSp->Control &= ~SL_PENDING_RETURNED;
-        Irp->IoStatus.Status = Status;
+  RIRP(Irp);
 
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+  TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
 
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
-    }
+  IoMarkIrpPending(Irp);
+  Irp->IoStatus.Status      = STATUS_PENDING;
+  Irp->IoStatus.Information = 0;
 
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
 
-    return Status;
+  switch (IrpSp->MajorFunction) {
+  /* Open an address file, connection endpoint, or control connection */
+  case IRP_MJ_CREATE:
+    Status = TiCreateFileObject(DeviceObject, Irp);
+    break;
+
+  /* Close an address file, connection endpoint, or control connection */
+  case IRP_MJ_CLOSE:
+    Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+    if (Context)
+        PoolFreeBuffer(Context);
+    Status = STATUS_SUCCESS;
+    break;
+
+  /* Release resources bound to an address file, connection endpoint,
+     or control connection */
+  case IRP_MJ_CLEANUP:
+    Status = TiCleanupFileObject(DeviceObject, Irp);
+    break;
+
+  default:
+    Status = STATUS_INVALID_DEVICE_REQUEST;
+  }
+
+  TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+  return IRPFinish( Irp, Status );
 }
 
 
-NTSTATUS TiDispatchInternal(
-    PDEVICE_OBJECT DeviceObject,
-    PIRP Irp)
+NTSTATUS
+#ifndef _MSC_VER
+STDCALL
+#endif
+TiDispatchInternal(
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
 /*
  * FUNCTION: Internal IOCTL dispatch routine
  * ARGUMENTS:
@@ -370,97 +439,106 @@ NTSTATUS TiDispatchInternal(
  *     Status of the operation
  */
 {
-       NTSTATUS Status;
-    PIO_STACK_LOCATION IrpSp;
+  NTSTATUS Status;
+  BOOL Complete = TRUE;
+  PIO_STACK_LOCATION IrpSp;
 
-    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
+  RIRP(Irp);
 
-       IrpSp = IoGetCurrentIrpStackLocation(Irp);
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
 
-    Irp->IoStatus.Status      = STATUS_SUCCESS;
-    Irp->IoStatus.Information = 0;
+  TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X) MN (%d).\n",
+    DeviceObject, Irp, IrpSp->MinorFunction));
 
-    switch (IrpSp->MinorFunction) {
-    case TDI_RECEIVE:
-        Status = DispTdiReceive(Irp);
-        break;
+  Irp->IoStatus.Status      = STATUS_SUCCESS;
+  Irp->IoStatus.Information = 0;
 
-    case TDI_RECEIVE_DATAGRAM:
-        Status = DispTdiReceiveDatagram(Irp);
-        break;
+  switch (IrpSp->MinorFunction) {
+  case TDI_RECEIVE:
+    Status = DispTdiReceive(Irp);
+    Complete = FALSE;
+    break;
 
-    case TDI_SEND:
-        Status = DispTdiSend(Irp);
-        break;
+  case TDI_RECEIVE_DATAGRAM:
+    Status = DispTdiReceiveDatagram(Irp);
+    Complete = FALSE;
+    break;
 
-    case TDI_SEND_DATAGRAM:
-        Status = DispTdiSendDatagram(Irp);
-        break;
+  case TDI_SEND:
+    Status = DispTdiSend(Irp);
+    Complete = FALSE; /* Completed in DispTdiSend */
+    break;
 
-    case TDI_ACCEPT:
-        Status = DispTdiAccept(Irp);
-        break;
+  case TDI_SEND_DATAGRAM:
+    Status = DispTdiSendDatagram(Irp);
+    Complete = FALSE;
+    break;
 
-    case TDI_LISTEN:
-        Status = DispTdiListen(Irp);
-        break;
+  case TDI_ACCEPT:
+    Status = DispTdiAccept(Irp);
+    break;
 
-    case TDI_CONNECT:
-        Status = DispTdiConnect(Irp);
-        break;
+  case TDI_LISTEN:
+    Status = DispTdiListen(Irp);
+    Complete = FALSE;
+    break;
 
-    case TDI_DISCONNECT:
-        Status = DispTdiDisconnect(Irp);
-        break;
+  case TDI_CONNECT:
+    Status = DispTdiConnect(Irp);
+    Complete = FALSE; /* Completed by the TCP event handler */
+    break;
 
-    case TDI_ASSOCIATE_ADDRESS:
-        Status = DispTdiAssociateAddress(Irp);
-        break;
+  case TDI_DISCONNECT:
+    Status = DispTdiDisconnect(Irp);
+    break;
 
-    case TDI_DISASSOCIATE_ADDRESS:
-        Status = DispTdiDisassociateAddress(Irp);
-        break;
+  case TDI_ASSOCIATE_ADDRESS:
+    Status = DispTdiAssociateAddress(Irp);
+    break;
 
-    case TDI_QUERY_INFORMATION:
-        Status = DispTdiQueryInformation(DeviceObject, Irp);
-        break;
+  case TDI_DISASSOCIATE_ADDRESS:
+    Status = DispTdiDisassociateAddress(Irp);
+    break;
 
-    case TDI_SET_INFORMATION:
-        Status = DispTdiSetInformation(Irp);
-        break;
+  case TDI_QUERY_INFORMATION:
+    Status = DispTdiQueryInformation(DeviceObject, Irp);
+    break;
 
-    case TDI_SET_EVENT_HANDLER:
-        Status = DispTdiSetEventHandler(Irp);
-        break;
+  case TDI_SET_INFORMATION:
+    Status = DispTdiSetInformation(Irp);
+    break;
 
-    case TDI_ACTION:
-        Status = STATUS_SUCCESS;
-        break;
+  case TDI_SET_EVENT_HANDLER:
+    Status = DispTdiSetEventHandler(Irp);
+    break;
 
-    /* An unsupported IOCTL code was submitted */
-    default:
-        Status = STATUS_INVALID_DEVICE_REQUEST;
-    }
-
-    if (Status != STATUS_PENDING) {
-        Irp->IoStatus.Status = Status;
+  case TDI_ACTION:
+    Status = STATUS_SUCCESS;
+    break;
 
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+  /* An unsupported IOCTL code was submitted */
+  default:
+    Status = STATUS_INVALID_DEVICE_REQUEST;
+  }
 
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
-    }
+  TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
 
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+  if( Complete )
+      IRPFinish( Irp, Status );
 
-       return Status;
+  return Status;
 }
 
 
-NTSTATUS TiDispatch(
-    PDEVICE_OBJECT DeviceObject,
-    PIRP Irp)
+NTSTATUS
+#ifndef _MSC_VER
+STDCALL
+#endif
+TiDispatch(
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
 /*
- * FUNCTION: Dispath routine for IRP_MJ_DEVICE_CONTROL requests
+ * FUNCTION: Dispatch routine for IRP_MJ_DEVICE_CONTROL requests
  * ARGUMENTS:
  *     DeviceObject = Pointer to a device object for this driver
  *     Irp          = Pointer to a I/O request packet
@@ -468,126 +546,158 @@ NTSTATUS TiDispatch(
  *     Status of the operation
  */
 {
-    NTSTATUS Status;
-    PIO_STACK_LOCATION IrpSp;
+  NTSTATUS Status;
+  PIO_STACK_LOCATION IrpSp;
 
-    TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp));
+  RIRP(Irp);
 
-    Irp->IoStatus.Information = 0;
+  IrpSp  = IoGetCurrentIrpStackLocation(Irp);
+
+  TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp));
+
+  Irp->IoStatus.Information = 0;
 
-    IrpSp  = IoGetCurrentIrpStackLocation(Irp);
 #ifdef _MSC_VER
-    Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);
-    if (NT_SUCCESS(Status)) {
-        TiDispatchInternal(DeviceObject, Irp);
-        Status = STATUS_PENDING;
-    } else {
+  Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);
+  if (NT_SUCCESS(Status)) {
+    TiDispatchInternal(DeviceObject, Irp);
+    Status = STATUS_PENDING;
+  } else {
 #else
-    if (TRUE) {
+  if (TRUE) {
 #endif
-        /* See if this request is TCP/IP specific */
-        switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
-        case IOCTL_TCP_QUERY_INFORMATION_EX:
-            Status = DispTdiQueryInformationEx(Irp, IrpSp);
-            break;
-
-        case IOCTL_TCP_SET_INFORMATION_EX:
-            Status = DispTdiSetInformationEx(Irp, IrpSp);
-            break;
-
-        default:
-            TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",
-                IrpSp->Parameters.DeviceIoControl.IoControlCode));
-            Status = STATUS_NOT_IMPLEMENTED;
-            break;
-        }
-    }
-
-    if (Status != STATUS_PENDING) {
-        Irp->IoStatus.Status = Status;
+    /* See if this request is TCP/IP specific */
+    switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+    case IOCTL_TCP_QUERY_INFORMATION_EX:
+      TI_DbgPrint(MIN_TRACE, ("TCP_QUERY_INFORMATION_EX\n"));
+      Status = DispTdiQueryInformationEx(Irp, IrpSp);
+      break;
+
+    case IOCTL_TCP_SET_INFORMATION_EX:
+      TI_DbgPrint(MIN_TRACE, ("TCP_SET_INFORMATION_EX\n"));
+      Status = DispTdiSetInformationEx(Irp, IrpSp);
+      break;
+
+    case IOCTL_SET_IP_ADDRESS:
+      TI_DbgPrint(MIN_TRACE, ("SET_IP_ADDRESS\n"));
+      Status = DispTdiSetIPAddress(Irp, IrpSp);
+      break;
+
+    case IOCTL_DELETE_IP_ADDRESS:
+      TI_DbgPrint(MIN_TRACE, ("DELETE_IP_ADDRESS\n"));
+      Status = DispTdiDeleteIPAddress(Irp, IrpSp);
+      break;
 
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
-
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+    default:
+      TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",
+          IrpSp->Parameters.DeviceIoControl.IoControlCode));
+      Status = STATUS_NOT_IMPLEMENTED;
+      break;
     }
+  }
 
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+  TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
 
-    return Status;
+  return IRPFinish( Irp, Status );
 }
 
 
-VOID TiUnload(
-    PDRIVER_OBJECT DriverObject)
+VOID STDCALL TiUnload(
+  PDRIVER_OBJECT DriverObject)
 /*
  * FUNCTION: Unloads the driver
  * ARGUMENTS:
  *     DriverObject = Pointer to driver object created by the system
  */
 {
-#ifdef BDG
-    KIRQL OldIrql;
+#ifdef DBG
+  KIRQL OldIrql;
 
-    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
-    if (!IsListEmpty(AddressFileList)) {
-        TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n"));
-    }
-    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+  TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+  if (!IsListEmpty(&AddressFileListHead)) {
+    TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n"));
+  }
+  TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
 #endif
+  ChewShutdown();
 
-    /* Unregister loopback adapter */
-    LoopUnregisterAdapter(NULL);
+  /* Cancel timer */
+  KeCancelTimer(&IPTimer);
 
-    /* Unregister protocol with NDIS */
-#ifdef _MSC_VER
-    LANUnregisterProtocol();
-#endif
+  /* Unregister loopback adapter */
+  LoopUnregisterAdapter(NULL);
+
+  /* Unregister protocol with NDIS */
+  LANUnregisterProtocol();
 
-    /* Shutdown transport level protocol subsystems */
-    TCPShutdown();
-    UDPShutdown();
-    RawIPShutdown();
-    DGShutdown();
+  /* Shutdown transport level protocol subsystems */
+  TCPShutdown();
+  UDPShutdown();
+  RawIPShutdown();
 
-    /* Shutdown network level protocol subsystem */
-    IPShutdown();
+  /* Shutdown network level protocol subsystem */
+  IPShutdown();
 
-    /* Free NDIS buffer descriptors */
-    if (GlobalBufferPool)
-        NdisFreeBufferPool(GlobalBufferPool);
+  /* Shutdown the lan worker */
+  LANShutdown();
 
-    /* Free NDIS packet descriptors */
-    if (GlobalPacketPool)
-        NdisFreePacketPool(GlobalPacketPool);
+  /* Free NDIS buffer descriptors */
+  if (GlobalBufferPool)
+    NdisFreeBufferPool(GlobalBufferPool);
 
-    /* Release all device objects */
+  /* Free NDIS packet descriptors */
+  if (GlobalPacketPool)
+    NdisFreePacketPool(GlobalPacketPool);
 
-    if (TCPDeviceObject)
-        IoDeleteDevice(TCPDeviceObject);
+  /* Release all device objects */
 
-    if (UDPDeviceObject)
-        IoDeleteDevice(UDPDeviceObject);
+  if (TCPDeviceObject)
+    IoDeleteDevice(TCPDeviceObject);
 
-    if (RawIPDeviceObject)
-        IoDeleteDevice(RawIPDeviceObject);
+  if (UDPDeviceObject)
+    IoDeleteDevice(UDPDeviceObject);
 
-    if (IPDeviceObject)
-        IoDeleteDevice(IPDeviceObject);
+  if (RawIPDeviceObject)
+    IoDeleteDevice(RawIPDeviceObject);
 
-    if (EntityList)
-        ExFreePool(EntityList);
+  if (IPDeviceObject)
+    IoDeleteDevice(IPDeviceObject);
 
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+  if (EntityList)
+    PoolFreeBuffer(EntityList);
+
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
+VOID STDCALL IPTimeoutDpcFn(
+    PKDPC Dpc,
+    PVOID DeferredContext,
+    PVOID SystemArgument1,
+    PVOID SystemArgument2)
+/*
+ * FUNCTION: Timeout DPC
+ * ARGUMENTS:
+ *     Dpc             = Pointer to our DPC object
+ *     DeferredContext = Pointer to context information (unused)
+ *     SystemArgument1 = Unused
+ *     SystemArgument2 = Unused
+ * NOTES:
+ *     This routine is dispatched once in a while to do maintainance jobs
+ */
+{
+    if( !IpWorkItemQueued ) {
+       ExQueueWorkItem( &IpWorkItem, CriticalWorkQueue );
+       IpWorkItemQueued = TRUE;
+    }
+}
 
 NTSTATUS
 #ifndef _MSC_VER
 STDCALL
 #endif
 DriverEntry(
-    PDRIVER_OBJECT DriverObject,
-    PUNICODE_STRING RegistryPath)
+  PDRIVER_OBJECT DriverObject,
+  PUNICODE_STRING RegistryPath)
 /*
  * FUNCTION: Main driver entry point
  * ARGUMENTS:
@@ -597,171 +707,174 @@ DriverEntry(
  *     Status of driver initialization
  */
 {
-    NTSTATUS Status;
-    UNICODE_STRING strDeviceName;
-    STRING strNdisDeviceName;
-    NDIS_STATUS NdisStatus;
-#ifdef _MSC_VER
-    PLAN_ADAPTER Adapter;
-    NDIS_STRING DeviceName;
-#endif
-
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
-
-    /* Create IP device object */
-    RtlInitUnicodeString(&strDeviceName, DD_IP_DEVICE_NAME);
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
-        FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject);
-    if (!NT_SUCCESS(Status)) {
-        TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status));
-        return Status;
-    }
-
-    /* Create RawIP device object */
-    RtlInitUnicodeString(&strDeviceName, DD_RAWIP_DEVICE_NAME);
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
-        FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject);
-    if (!NT_SUCCESS(Status)) {
-        TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status));
-        TiUnload(DriverObject);
-        return Status;
-    }
-
-    /* Create UDP device object */
-    RtlInitUnicodeString(&strDeviceName, DD_UDP_DEVICE_NAME);
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
-        FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject);
-    if (!NT_SUCCESS(Status)) {
-        TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status));
-        TiUnload(DriverObject);
-        return Status;
-    }
-
-    /* Create TCP device object */
-    RtlInitUnicodeString(&strDeviceName, DD_TCP_DEVICE_NAME);
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
-        FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject);
-    if (!NT_SUCCESS(Status)) {
-        TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status));
-        TiUnload(DriverObject);
-        return Status;
-    }
-
-    /* Allocate NDIS packet descriptors */
-    NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT));
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        TiUnload(DriverObject);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /* Allocate NDIS buffer descriptors */
-    NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100);
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        TiUnload(DriverObject);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /* Initialize address file list and protecting spin lock */
-    InitializeListHead(&AddressFileListHead);
-    KeInitializeSpinLock(&AddressFileListLock);
-
-    /* Initialize interface list and protecting spin lock */
-    InitializeListHead(&InterfaceListHead);
-    KeInitializeSpinLock(&InterfaceListLock);
-
-    /* Initialize network level protocol subsystem */
-    IPStartup(DriverObject, RegistryPath);
-
-    /* Initialize transport level protocol subsystems */
-    DGStartup();
-    RawIPStartup();
-    UDPStartup();
-    TCPStartup();
-
-    /* Register protocol with NDIS */
-    RtlInitString(&strNdisDeviceName, IP_DEVICE_NAME);
-    Status = LANRegisterProtocol(&strNdisDeviceName);
-    if (!NT_SUCCESS(Status)) {
-               TiWriteErrorLog(
-            DriverObject,
-            EVENT_TRANSPORT_REGISTER_FAILED,
-            TI_ERROR_DRIVERENTRY,
-            Status,
-            NULL,
-            0,
-            NULL);
-        TiUnload(DriverObject);
-        return Status;
-    }
-
-    /* Open loopback adapter */
-    if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) {
-        TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status));
-        TiUnload(DriverObject);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-#if 1
-#ifdef _MSC_VER
-    /* Open underlying adapter(s) we are bound to */
-
-    /* FIXME: Get binding information from registry */
-
-    /* Put your own NDIS adapter device name here */
-
-#if 0
-    /* NT4 */
-    NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1");
-#else
-    /* NT5 */
-    NdisInitUnicodeString(&DeviceName,
-        L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}");
-#endif
-
-    NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter);
-    if (!NT_SUCCESS(NdisStatus)) {
-        TI_DbgPrint(MIN_TRACE, ("Failed to intialize adapter. Status (0x%X).\n", Status));
-               TiWriteErrorLog(
-            DriverObject,
-            EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
-            TI_ERROR_DRIVERENTRY,
-            NdisStatus,
-            NULL,
-            0,
-            NULL);
-        TiUnload(DriverObject);
-        return STATUS_DEVICE_DOES_NOT_EXIST;
-    }
-#endif
-#endif
-    /* Setup network layer and transport layer entities */
-    EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2);
-    if (!NT_SUCCESS(Status)) {
-        TiUnload(DriverObject);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    EntityList[0].tei_entity   = CL_NL_ENTITY;
-    EntityList[0].tei_instance = 0;
-    EntityList[1].tei_entity   = CL_TL_ENTITY;
-    EntityList[1].tei_instance = 0;
-    EntityCount = 2;
-
-    /* Use direct I/O */
-    IPDeviceObject->Flags    |= DO_DIRECT_IO;
-    RawIPDeviceObject->Flags |= DO_DIRECT_IO;
-    UDPDeviceObject->Flags   |= DO_DIRECT_IO;
-    TCPDeviceObject->Flags   |= DO_DIRECT_IO;
-
-    /* Initialize the driver object with this driver's entry points */
-    DriverObject->MajorFunction[IRP_MJ_CREATE]  = TiDispatchOpenClose;
-    DriverObject->MajorFunction[IRP_MJ_CLOSE]   = TiDispatchOpenClose;
-    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose;
-    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal;
-    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch;
+  NTSTATUS Status;
+  UNICODE_STRING strIpDeviceName = RTL_CONSTANT_STRING(DD_IP_DEVICE_NAME);
+  UNICODE_STRING strRawDeviceName = RTL_CONSTANT_STRING(DD_RAWIP_DEVICE_NAME);
+  UNICODE_STRING strUdpDeviceName = RTL_CONSTANT_STRING(DD_UDP_DEVICE_NAME);
+  UNICODE_STRING strTcpDeviceName = RTL_CONSTANT_STRING(DD_TCP_DEVICE_NAME);
+  UNICODE_STRING strNdisDeviceName = RTL_CONSTANT_STRING(TCPIP_PROTOCOL_NAME);
+  NDIS_STATUS NdisStatus;
+  LARGE_INTEGER DueTime;
+
+  TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+  TrackingInit();
+  TrackTag(NDIS_BUFFER_TAG);
+  TrackTag(NDIS_PACKET_TAG);
+  TrackTag(FBSD_MALLOC);
+  TrackTag(EXALLOC_TAG);
+
+  /* TdiInitialize() ? */
+
+  /* FIXME: Create symbolic links in Win32 namespace */
+
+  /* Create IP device object */
+  Status = IoCreateDevice(DriverObject, 0, &strIpDeviceName,
+    FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject);
+  if (!NT_SUCCESS(Status)) {
+    TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status));
+    return Status;
+  }
 
-    DriverObject->DriverUnload = (PDRIVER_UNLOAD)TiUnload;
+  ChewInit( IPDeviceObject );
 
-    return STATUS_SUCCESS;
+  /* Create RawIP device object */
+  Status = IoCreateDevice(DriverObject, 0, &strRawDeviceName,
+    FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject);
+  if (!NT_SUCCESS(Status)) {
+    TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status));
+    TiUnload(DriverObject);
+    return Status;
+  }
+
+  /* Create UDP device object */
+  Status = IoCreateDevice(DriverObject, 0, &strUdpDeviceName,
+    FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject);
+  if (!NT_SUCCESS(Status)) {
+    TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status));
+    TiUnload(DriverObject);
+    return Status;
+  }
+
+  /* Create TCP device object */
+  Status = IoCreateDevice(DriverObject, 0, &strTcpDeviceName,
+    FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject);
+  if (!NT_SUCCESS(Status)) {
+    TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status));
+    TiUnload(DriverObject);
+    return Status;
+  }
+
+  /* Setup network layer and transport layer entities */
+  KeInitializeSpinLock(&EntityListLock);
+  EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * MAX_TDI_ENTITIES );
+  if (!NT_SUCCESS(Status)) {
+         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+    TiUnload(DriverObject);
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  EntityList[0].tei_entity   = CL_NL_ENTITY;
+  EntityList[0].tei_instance = 0;
+  EntityList[0].context      = 0;
+  EntityList[0].info_req     = InfoNetworkLayerTdiQueryEx;
+  EntityList[0].info_set     = InfoNetworkLayerTdiSetEx;
+  EntityList[1].tei_entity   = CL_TL_ENTITY;
+  EntityList[1].tei_instance = 0;
+  EntityList[1].context      = 0;
+  EntityList[1].info_req     = InfoTransportLayerTdiQueryEx;
+  EntityList[1].info_set     = InfoTransportLayerTdiSetEx;
+  EntityCount = 2;
+  EntityMax   = MAX_TDI_ENTITIES;
+
+  /* Allocate NDIS packet descriptors */
+  NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT));
+  if (NdisStatus != NDIS_STATUS_SUCCESS) {
+    TiUnload(DriverObject);
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  /* Allocate NDIS buffer descriptors */
+  NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100);
+  if (NdisStatus != NDIS_STATUS_SUCCESS) {
+    TiUnload(DriverObject);
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  /* Initialize address file list and protecting spin lock */
+  InitializeListHead(&AddressFileListHead);
+  KeInitializeSpinLock(&AddressFileListLock);
+
+  /* Initialize connection endpoint list and protecting spin lock */
+  InitializeListHead(&ConnectionEndpointListHead);
+  KeInitializeSpinLock(&ConnectionEndpointListLock);
+
+  /* Initialize interface list and protecting spin lock */
+  InitializeListHead(&InterfaceListHead);
+  KeInitializeSpinLock(&InterfaceListLock);
+
+  /* Initialize network level protocol subsystem */
+  IPStartup(RegistryPath);
+
+  /* Initialize transport level protocol subsystems */
+  RawIPStartup();
+  UDPStartup();
+  TCPStartup();
+
+  /* Initialize the lan worker */
+  LANStartup();
+
+  /* Register protocol with NDIS */
+  /* This used to be IP_DEVICE_NAME but the DDK says it has to match your entry in the SCM */
+  Status = LANRegisterProtocol(&strNdisDeviceName);
+  if (!NT_SUCCESS(Status)) {
+         TI_DbgPrint(MIN_TRACE,("Failed to register protocol with NDIS; status 0x%x\n", Status));
+         TiWriteErrorLog(
+      DriverObject,
+      EVENT_TRANSPORT_REGISTER_FAILED,
+      TI_ERROR_DRIVERENTRY,
+      Status,
+      NULL,
+      0,
+      NULL);
+    TiUnload(DriverObject);
+    return Status;
+  }
+
+  /* Open loopback adapter */
+  if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) {
+    TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status));
+    TiUnload(DriverObject);
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  /* Use direct I/O */
+  IPDeviceObject->Flags    |= DO_DIRECT_IO;
+  RawIPDeviceObject->Flags |= DO_DIRECT_IO;
+  UDPDeviceObject->Flags   |= DO_DIRECT_IO;
+  TCPDeviceObject->Flags   |= DO_DIRECT_IO;
+
+  /* Initialize the driver object with this driver's entry points */
+  DriverObject->MajorFunction[IRP_MJ_CREATE]  = TiDispatchOpenClose;
+  DriverObject->MajorFunction[IRP_MJ_CLOSE]   = TiDispatchOpenClose;
+  DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose;
+  DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal;
+  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch;
+
+  DriverObject->DriverUnload = TiUnload;
+
+  /* Initialize our periodic timer and its associated DPC object. When the
+     timer expires, the IPTimeout deferred procedure call (DPC) is queued */
+  ExInitializeWorkItem( &IpWorkItem, IPTimeout, NULL );
+  KeInitializeDpc(&IPTimeoutDpc, IPTimeoutDpcFn, NULL);
+  KeInitializeTimer(&IPTimer);
+
+  /* Start the periodic timer with an initial and periodic
+     relative expiration time of IP_TIMEOUT milliseconds */
+  DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000;
+  KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc);
+
+  return STATUS_SUCCESS;
 }