Exemple #1
0
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"));
}
Exemple #2
0
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"));
}
Exemple #3
0
NTSTATUS NTAPI
TiDispatchOpenClose(
  IN PDEVICE_OBJECT DeviceObject,
  IN PIRP Irp)
/*
 * FUNCTION: Main dispath routine
 * ARGUMENTS:
 *     DeviceObject = Pointer to a device object for this driver
 *     Irp          = Pointer to a I/O request packet
 * RETURNS:
 *     Status of the operation
 */
{

  PIO_STACK_LOCATION IrpSp;
  NTSTATUS Status;

  DbgPrint("TiDispatchOpenClose Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp);

  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:
    Status = TiCloseFileObject(DeviceObject, Irp);
    break;

  default:
    Status = STATUS_INVALID_DEVICE_REQUEST;
  }

  //DbgPrint("Leaving. Status is (0x%X)\n", Status);

  return IRPFinish( Irp, Status );

}
Exemple #4
0
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"));
}
Exemple #5
0
NTSTATUS NTAPI
TiDispatch(
  PDEVICE_OBJECT DeviceObject,
  PIRP Irp)
/*
 * 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
 * RETURNS:
 *     Status of the operation
 */
{


  NTSTATUS Status;
  PIO_STACK_LOCATION IrpSp;

  IrpSp  = IoGetCurrentIrpStackLocation(Irp);

  TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatch] Called. IRP is at (0x%X).\n", Irp));
  DbgPrint("TiDispatch Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp);
  Irp->IoStatus.Information = 0;

#if 0
  Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);
  if (NT_SUCCESS(Status)) {
    TiDispatchInternal(DeviceObject, Irp);
    Status = STATUS_PENDING;
  } else {
#else
  if (TRUE) {
#endif
    /* 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;

    default:
      TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",
          IrpSp->Parameters.DeviceIoControl.IoControlCode));
      Status = STATUS_NOT_IMPLEMENTED;
      break;
    }
  }

  TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatch] Leaving. Status = (0x%X).\n", Status));

  return IRPFinish( Irp, Status );


}
NTSTATUS
DriverEntry(
		  PDRIVER_OBJECT DriverObject,
		  PUNICODE_STRING RegistryPath)
{
  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, ("[TCPIP, DriverEntry] \n"));
  
  //_asm int 3;

  KdPrint(("driver entery..................\n"));

  /* TdiInitialize() ? */

  /* FIXME: Create symbolic links in Win32 namespace */

  /* Initialize our periodic timer and its associated DPC object. When the
     timer expires, the IPTimeout deferred procedure call (DPC) is queued */
  KeInitializeDpc(&IPTimeoutDpc, IPTimeoutDpcFn, NULL);
  KeInitializeTimer(&IPTimer);
	 
  /* 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));
    TiUnload(DriverObject);
    return Status;
  }

  ChewInit( IPDeviceObject );
	 

  /* 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 = ExAllocatePoolWithTag(NonPagedPool,
                                     sizeof(TDIEntityID) * MAX_TDI_ENTITIES,
                                     TDI_ENTITY_TAG );

  if (!EntityList) {
    TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
    TiUnload(DriverObject);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  EntityCount = 0;
  EntityMax   = MAX_TDI_ENTITIES;

  /* Allocate NDIS packet descriptors */
  NdisAllocatePacketPoolEx(&NdisStatus, &GlobalPacketPool, 500, 1500, sizeof(PACKET_CONTEXT));
  if (NdisStatus != NDIS_STATUS_SUCCESS) {
    TiUnload(DriverObject);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  /* Allocate NDIS buffer descriptors */
  NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 2000);
  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 */
  Status = RawIPStartup();
  if( !NT_SUCCESS(Status) ) {
      TiUnload(DriverObject);
      return Status;
  }

  Status = UDPStartup();
  if( !NT_SUCCESS(Status) ) {
      TiUnload(DriverObject);
      return Status;
  }

  Status = TCPStartup();
  if( !NT_SUCCESS(Status) ) {
      TiUnload(DriverObject);
      return Status;
  }

  Status = ICMPStartup();
  if( !NT_SUCCESS(Status) ) {
      TiUnload(DriverObject);
      return Status;
  }

  /* 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_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal;
  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch;

  DriverObject->DriverUnload = TiUnload;

  /* Open loopback adapter */
  Status = LoopRegisterAdapter(NULL, NULL);
  if (!NT_SUCCESS(Status)) {
    TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status));
    TiUnload(DriverObject);
    return Status;
  }

  /* 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;
  }

  /* 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);

  TI_DbgPrint(MAX_TRACE, ("[TCPIP, DriverEntry] Finished\n"));


  return STATUS_SUCCESS;

}
Exemple #6
0
NTSTATUS NTAPI
TiDispatchInternal(
  PDEVICE_OBJECT DeviceObject,
  PIRP Irp)
/*
 * FUNCTION: Internal IOCTL dispatch routine
 * ARGUMENTS:
 *     DeviceObject = Pointer to a device object for this driver
 *     Irp          = Pointer to a I/O request packet
 * RETURNS:
 *     Status of the operation
 */
{

  NTSTATUS Status;
  BOOLEAN Complete = TRUE;
  PIO_STACK_LOCATION IrpSp;

  IrpSp = IoGetCurrentIrpStackLocation(Irp);
  DbgPrint("TiDispatchInternal Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp);
  TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatchInternal] Called. DeviceObject is at (0x%X), IRP is at (0x%X) MN (%d).\n",
    DeviceObject, Irp, IrpSp->MinorFunction));

  Irp->IoStatus.Status      = STATUS_SUCCESS;
  Irp->IoStatus.Information = 0;

  switch (IrpSp->MinorFunction) {
  case TDI_RECEIVE:
    Status = DispTdiReceive(Irp);
    Complete = FALSE;
    break;

  case TDI_RECEIVE_DATAGRAM:
    Status = DispTdiReceiveDatagram(Irp);
    Complete = FALSE;
    break;

  case TDI_SEND:
    Status = DispTdiSend(Irp);
    Complete = FALSE; /* Completed in DispTdiSend */
    break;

  case TDI_SEND_DATAGRAM:
    Status = DispTdiSendDatagram(Irp);
    Complete = FALSE;
    break;

  case TDI_ACCEPT:
    Status = DispTdiAccept(Irp);
    break;

  case TDI_LISTEN:
    Status = DispTdiListen(Irp);
    Complete = FALSE;
    break;

  case TDI_CONNECT:
    Status = DispTdiConnect(Irp);
    Complete = FALSE; /* Completed by the TCP event handler */
    break;

  case TDI_DISCONNECT:
    Status = DispTdiDisconnect(Irp);
    Complete = FALSE;
    break;

  case TDI_ASSOCIATE_ADDRESS:
    Status = DispTdiAssociateAddress(Irp);
    break;

  case TDI_DISASSOCIATE_ADDRESS:
    Status = DispTdiDisassociateAddress(Irp);
    break;

  case TDI_QUERY_INFORMATION:
    Status = DispTdiQueryInformation(DeviceObject, Irp);
    break;

  case TDI_SET_INFORMATION:
    Status = DispTdiSetInformation(Irp);
    break;

  case TDI_SET_EVENT_HANDLER:
    Status = DispTdiSetEventHandler(Irp);
    break;

  case TDI_ACTION:
    Status = STATUS_SUCCESS;
    break;

  /* An unsupported IOCTL code was submitted */
  default:
    Status = STATUS_INVALID_DEVICE_REQUEST;
  }

  TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatchInternal] Leaving. Status = (0x%X).\n", Status));

  if( Complete )
      IRPFinish( Irp, Status );

  return Status;

}
Exemple #7
0
NTSTATUS NTAPI
TiDispatch(
  PDEVICE_OBJECT DeviceObject,
  PIRP Irp)
/*
 * 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
 * RETURNS:
 *     Status of the operation
 */
{
  NTSTATUS Status;
  PIO_STACK_LOCATION IrpSp;

  IrpSp  = IoGetCurrentIrpStackLocation(Irp);

  TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatch] Called. IRP is at (0x%X).\n", Irp));

  Irp->IoStatus.Information = 0;

#if 0
  Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);
  if (NT_SUCCESS(Status)) {
    TiDispatchInternal(DeviceObject, Irp);
    Status = STATUS_PENDING;
  } else {
#else
  if (TRUE) {
#endif
    /* 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;

    case IOCTL_QUERY_IP_HW_ADDRESS:
      TI_DbgPrint(MIN_TRACE, ("QUERY_IP_HW_ADDRESS\n"));
      Status = DispTdiQueryIpHwAddress(DeviceObject, Irp, IrpSp);
      break;

    default:
      TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",
          IrpSp->Parameters.DeviceIoControl.IoControlCode));
      Status = STATUS_NOT_IMPLEMENTED;
      break;
    }
  }

  TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatch] Leaving. Status = (0x%X).\n", Status));

  return IRPFinish( Irp, Status );
}


VOID NTAPI TiUnload(
  PDRIVER_OBJECT DriverObject)
/*
 * FUNCTION: Unloads the driver
 * ARGUMENTS:
 *     DriverObject = Pointer to driver object created by the system
 */
{
#if DBG
  KIRQL OldIrql;

  TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
  if (!IsListEmpty(&AddressFileListHead)) {
    TI_DbgPrint(MIN_TRACE, ("[TCPIP, TiUnload] Called. Open address file objects exists.\n"));
  }
  TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
#endif
  /* Cancel timer */
  KeCancelTimer(&IPTimer);

  /* Unregister loopback adapter */
  LoopUnregisterAdapter(NULL);

  /* Unregister protocol with NDIS */
  LANUnregisterProtocol();

  /* Shutdown transport level protocol subsystems */
  TCPShutdown();
  UDPShutdown();
  RawIPShutdown();
  ICMPShutdown();

  /* Shutdown network level protocol subsystem */
  IPShutdown();

  /* Free NDIS buffer descriptors */
  if (GlobalBufferPool)
    NdisFreeBufferPool(GlobalBufferPool);

  /* Free NDIS packet descriptors */
  if (GlobalPacketPool)
    NdisFreePacketPool(GlobalPacketPool);

  /* Release all device objects */

  if (TCPDeviceObject)
    IoDeleteDevice(TCPDeviceObject);

  if (UDPDeviceObject)
    IoDeleteDevice(UDPDeviceObject);

  if (RawIPDeviceObject)
    IoDeleteDevice(RawIPDeviceObject);

  if (IPDeviceObject) {
     ChewShutdown();
     IoDeleteDevice(IPDeviceObject);
  }

  if (EntityList)
    ExFreePoolWithTag(EntityList, TDI_ENTITY_TAG);

  TI_DbgPrint(MAX_TRACE, ("[TCPIP, TiUnload] Leaving.\n"));
}