[NETCFGX]
[reactos.git] / reactos / drivers / network / tcpip / datalink / lan.c
index aaf32db..165ec6b 100644 (file)
@@ -10,9 +10,6 @@
 
 #include "precomp.h"
 
-/* Define this to bugcheck on double complete */
-/* #define BREAK_ON_DOUBLE_COMPLETE */
-
 UINT TransferDataCalled = 0;
 UINT TransferDataCompleteCalled = 0;
 UINT LanReceiveWorkerCalled = 0;
@@ -51,54 +48,6 @@ BOOLEAN ProtocolRegistered     = FALSE;
 LIST_ENTRY AdapterListHead;
 KSPIN_LOCK AdapterListLock;
 
-/* Double complete protection */
-KSPIN_LOCK LanSendCompleteLock;
-LIST_ENTRY LanSendCompleteList;
-
-VOID LanChainCompletion( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
-    PLAN_WQ_ITEM PendingCompletion =
-       ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
-
-    if( !PendingCompletion ) return;
-
-    PendingCompletion->Packet  = NdisPacket;
-    PendingCompletion->Adapter = Adapter;
-
-    ExInterlockedInsertTailList( &LanSendCompleteList,
-                                &PendingCompletion->ListEntry,
-                                &LanSendCompleteLock );
-}
-
-BOOLEAN LanShouldComplete( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
-    PLIST_ENTRY ListEntry;
-    PLAN_WQ_ITEM CompleteEntry;
-    KIRQL OldIrql;
-
-    KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
-    for( ListEntry = LanSendCompleteList.Flink;
-        ListEntry != &LanSendCompleteList;
-        ListEntry = ListEntry->Flink ) {
-       CompleteEntry = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
-
-       if( CompleteEntry->Adapter == Adapter &&
-           CompleteEntry->Packet  == NdisPacket ) {
-           RemoveEntryList( ListEntry );
-           KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
-           ExFreePool( CompleteEntry );
-           return TRUE;
-       }
-    }
-    KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
-
-    DbgPrint("NDIS completed the same send packet twice "
-            "(Adapter %x Packet %x)!!\n", Adapter, NdisPacket);
-#ifdef BREAK_ON_DOUBLE_COMPLETE
-    KeBugCheck(0);
-#endif
-
-    return FALSE;
-}
-
 NDIS_STATUS NDISCall(
     PLAN_ADAPTER Adapter,
     NDIS_REQUEST_TYPE Type,
@@ -159,21 +108,21 @@ VOID FreeAdapter(
  *     Adapter = Pointer to LAN_ADAPTER structure to free
  */
 {
-    exFreePool(Adapter);
+    ExFreePoolWithTag(Adapter, LAN_ADAPTER_TAG);
 }
 
 
 NTSTATUS TcpipLanGetDwordOid
 ( PIP_INTERFACE Interface,
   NDIS_OID Oid,
-  PDWORD Result ) {
+  PULONG Result ) {
     /* Get maximum frame size */
     if( Interface->Context ) {
         return NDISCall((PLAN_ADAPTER)Interface->Context,
                         NdisRequestQueryInformation,
                         Oid,
                         Result,
-                        sizeof(DWORD));
+                        sizeof(ULONG));
     } else switch( Oid ) { /* Loopback Case */
     case OID_GEN_HARDWARE_STATUS:
         *Result = NdisHardwareStatusReady;
@@ -185,7 +134,7 @@ NTSTATUS TcpipLanGetDwordOid
 }
 
 
-VOID STDCALL ProtocolOpenAdapterComplete(
+VOID NTAPI ProtocolOpenAdapterComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status,
     NDIS_STATUS OpenErrorStatus)
@@ -207,7 +156,7 @@ VOID STDCALL ProtocolOpenAdapterComplete(
 }
 
 
-VOID STDCALL ProtocolCloseAdapterComplete(
+VOID NTAPI ProtocolCloseAdapterComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status)
 /*
@@ -227,7 +176,7 @@ VOID STDCALL ProtocolCloseAdapterComplete(
 }
 
 
-VOID STDCALL ProtocolResetComplete(
+VOID NTAPI ProtocolResetComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status)
 /*
@@ -247,7 +196,7 @@ VOID STDCALL ProtocolResetComplete(
 }
 
 
-VOID STDCALL ProtocolRequestComplete(
+VOID NTAPI ProtocolRequestComplete(
     NDIS_HANDLE BindingContext,
     PNDIS_REQUEST NdisRequest,
     NDIS_STATUS Status)
@@ -270,7 +219,7 @@ VOID STDCALL ProtocolRequestComplete(
 }
 
 
-VOID STDCALL ProtocolSendComplete(
+VOID NTAPI ProtocolSendComplete(
     NDIS_HANDLE BindingContext,
     PNDIS_PACKET Packet,
     NDIS_STATUS Status)
@@ -282,14 +231,7 @@ VOID STDCALL ProtocolSendComplete(
  *     Status         = Status of the operation
  */
 {
-    TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
-    if( LanShouldComplete( (PLAN_ADAPTER)BindingContext, Packet ) ) {
-       ASSERT_KM_POINTER(Packet);
-       ASSERT_KM_POINTER(PC(Packet));
-       ASSERT_KM_POINTER(PC(Packet)->DLComplete);
-       (*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
-       TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
-    }
+    FreeNdisPacket(Packet);
 }
 
 VOID LanReceiveWorker( PVOID Context ) {
@@ -307,6 +249,10 @@ VOID LanReceiveWorker( PVOID Context ) {
     Adapter = WorkItem->Adapter;
     BytesTransferred = WorkItem->BytesTransferred;
 
+    ExFreePoolWithTag(WorkItem, WQ_CONTEXT_TAG);
+
+    IPInitializePacket(&IPPacket, 0);
+
     IPPacket.NdisPacket = Packet;
 
     NdisGetFirstBufferFromPacket(Packet,
@@ -342,6 +288,7 @@ VOID LanReceiveWorker( PVOID Context ) {
        TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
        ARPReceive(Adapter->Context, &IPPacket);
     default:
+        IPPacket.Free(&IPPacket);
        break;
     }
 
@@ -353,22 +300,23 @@ VOID LanSubmitReceiveWork(
     PNDIS_PACKET Packet,
     NDIS_STATUS Status,
     UINT BytesTransferred) {
-    LAN_WQ_ITEM WQItem;
+    PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM),
+                                                WQ_CONTEXT_TAG);
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
-    PVOID LanWorkItem;
 
     TI_DbgPrint(DEBUG_DATALINK,("called\n"));
 
-    WQItem.Packet = Packet;
-    WQItem.Adapter = Adapter;
-    WQItem.BytesTransferred = BytesTransferred;
+    if (!WQItem) return;
+
+    WQItem->Packet = Packet;
+    WQItem->Adapter = Adapter;
+    WQItem->BytesTransferred = BytesTransferred;
 
-    if( !ChewCreate
-       ( &LanWorkItem, sizeof(LAN_WQ_ITEM),  LanReceiveWorker, &WQItem ) )
-       ASSERT(0);
+    if (!ChewCreate( LanReceiveWorker, WQItem ))
+        ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG);
 }
 
-VOID STDCALL ProtocolTransferDataComplete(
+VOID NTAPI ProtocolTransferDataComplete(
     NDIS_HANDLE BindingContext,
     PNDIS_PACKET Packet,
     NDIS_STATUS Status,
@@ -397,7 +345,7 @@ VOID STDCALL ProtocolTransferDataComplete(
     LanSubmitReceiveWork( BindingContext, Packet, Status, BytesTransferred );
 }
 
-NDIS_STATUS STDCALL ProtocolReceive(
+NDIS_STATUS NTAPI ProtocolReceive(
     NDIS_HANDLE BindingContext,
     NDIS_HANDLE MacReceiveContext,
     PVOID HeaderBuffer,
@@ -466,7 +414,7 @@ NDIS_STATUS STDCALL ProtocolReceive(
                                 Adapter, Adapter->MTU));
 
     NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
-                                           PacketSize + HeaderBufferSize );
+                                           PacketSize );
     if( NdisStatus != NDIS_STATUS_SUCCESS ) {
        return NDIS_STATUS_NOT_ACCEPTED;
     }
@@ -511,7 +459,7 @@ NDIS_STATUS STDCALL ProtocolReceive(
 }
 
 
-VOID STDCALL ProtocolReceiveComplete(
+VOID NTAPI ProtocolReceiveComplete(
     NDIS_HANDLE BindingContext)
 /*
  * FUNCTION: Called by NDIS when we're done receiving data
@@ -523,7 +471,7 @@ VOID STDCALL ProtocolReceiveComplete(
 }
 
 
-VOID STDCALL ProtocolStatus(
+VOID NTAPI ProtocolStatus(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS GeneralStatus,
     PVOID StatusBuffer,
@@ -565,8 +513,36 @@ VOID STDCALL ProtocolStatus(
     }
 }
 
+NDIS_STATUS NTAPI
+ProtocolPnPEvent(
+    NDIS_HANDLE NdisBindingContext,
+    PNET_PNP_EVENT PnPEvent)
+{
+    switch(PnPEvent->NetEvent)
+    {
+      case NetEventSetPower:
+         DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer);
+         return NDIS_STATUS_SUCCESS;
+
+      case NetEventQueryPower:
+         DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer);
+         return NDIS_STATUS_SUCCESS;
+
+      case NetEventQueryRemoveDevice:
+         DbgPrint("Device is about to be removed\n");
+         return NDIS_STATUS_SUCCESS;
+
+      case NetEventCancelRemoveDevice:
+         DbgPrint("Device removal cancelled\n");
+         return NDIS_STATUS_SUCCESS;
+
+      default:
+         DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent);
+         return NDIS_STATUS_SUCCESS;
+    }
+}
 
-VOID STDCALL ProtocolStatusComplete(
+VOID NTAPI ProtocolStatusComplete(
     NDIS_HANDLE NdisBindingContext)
 /*
  * FUNCTION: Called by NDIS when a status-change has occurred
@@ -577,7 +553,7 @@ VOID STDCALL ProtocolStatusComplete(
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 }
 
-VOID STDCALL ProtocolBindAdapter(
+VOID NTAPI ProtocolBindAdapter(
     OUT PNDIS_STATUS   Status,
     IN  NDIS_HANDLE    BindContext,
     IN  PNDIS_STRING   DeviceName,
@@ -619,17 +595,18 @@ VOID LANTransmit(
 {
     NDIS_STATUS NdisStatus;
     PETH_HEADER EHeader;
-    PCHAR Data;
-    UINT Size;
+    PCHAR Data, OldData;
+    UINT Size, OldSize;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
     KIRQL OldIrql;
+    PNDIS_PACKET XmitPacket;
 
     TI_DbgPrint(DEBUG_DATALINK,
                ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
                 NdisPacket, Offset, Adapter));
 
     if (Adapter->State != LAN_STATE_STARTED) {
-        ProtocolSendComplete(Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
+        (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
         return;
     }
 
@@ -642,11 +619,19 @@ VOID LANTransmit(
                 Adapter->HWAddress[4] & 0xff,
                 Adapter->HWAddress[5] & 0xff));
 
-    /* XXX arty -- Handled adjustment in a saner way than before ...
-     * not needed immediately */
-    GetDataPtr( NdisPacket, 0, &Data, &Size );
+    GetDataPtr( NdisPacket, 0, &OldData, &OldSize );
 
-    LanChainCompletion( Adapter, NdisPacket );
+    NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES);
+        return;
+    }
+
+    GetDataPtr(XmitPacket, 0, &Data, &Size);
+
+    RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize);
+
+    (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS);
 
         switch (Adapter->Media) {
         case NdisMedium802_3:
@@ -673,14 +658,7 @@ VOID LANTransmit(
                 EHeader->EType = ETYPE_IPv6;
                 break;
             default:
-#ifdef DBG
-                /* Should not happen */
-                TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
-
-                ProtocolSendComplete((NDIS_HANDLE)Context,
-                                     NdisPacket,
-                                     NDIS_STATUS_FAILURE);
-#endif
+                ASSERT(FALSE);
                 return;
             }
             break;
@@ -703,9 +681,15 @@ VOID LANTransmit(
                   ((PCHAR)LinkAddress)[5] & 0xff));
        }
 
+        if (Adapter->MTU < Size) {
+            /* This is NOT a pointer. MSDN explicitly says so. */
+            NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket,
+                                             TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU);
+        }
+
        TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
        TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
-       NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
+       NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket);
        TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
                                NdisStatus == NDIS_STATUS_PENDING ?
                                "Pending" : "Complete"));
@@ -716,7 +700,7 @@ VOID LANTransmit(
         * status_pending is returned.  Note that this is different from
         * the situation with IRPs. */
         if (NdisStatus != NDIS_STATUS_PENDING)
-            ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
+            ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus);
 }
 
 static NTSTATUS
@@ -758,7 +742,7 @@ static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
     UnicodeString.MaximumLength = Information->DataLength;
 
     String->Buffer =
-       (PWCHAR)exAllocatePool( NonPagedPool,
+       (PWCHAR)ExAllocatePool( NonPagedPool,
                                UnicodeString.MaximumLength + sizeof(WCHAR) );
 
     if( !String->Buffer ) return STATUS_NO_MEMORY;
@@ -782,12 +766,12 @@ static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
 
 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
                                   PUNICODE_STRING Second,
-                                  BOOL Deallocate) {
+                                  BOOLEAN Deallocate) {
     NTSTATUS Status;
     UNICODE_STRING Ustr = *ResultFirst;
-    PWSTR new_string = ExAllocatePoolWithTag
+    PWSTR new_string = ExAllocatePool
         (PagedPool,
-         (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TAG_STRING);
+         (ResultFirst->Length + Second->Length + sizeof(WCHAR)));
     if( !new_string ) {
        return STATUS_NO_MEMORY;
     }
@@ -808,9 +792,9 @@ static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
                                     PUNICODE_STRING TargetKeyName,
                                     PUNICODE_STRING Name,
                                     PUNICODE_STRING DeviceDesc ) {
-    UNICODE_STRING RootDevice = { 0 }, LinkageKeyName = { 0 };
-    UNICODE_STRING DescKeyName = { 0 }, Linkage = { 0 };
-    UNICODE_STRING BackSlash = { 0 };
+    UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL };
+    UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL };
+    UNICODE_STRING BackSlash = { 0, 0, NULL };
     HANDLE DescKey = NULL, LinkageKey = NULL;
     NTSTATUS Status;
 
@@ -866,6 +850,8 @@ static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
         ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
     ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
 
+    RtlInitUnicodeString( DeviceDesc, NULL );
+
     if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
 
     RtlInitUnicodeString
@@ -920,8 +906,6 @@ static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
         }
     }
 
-    RtlInitUnicodeString( DeviceDesc, L"" );
-    AppendUnicodeString( DeviceDesc, &TargetKeyName, FALSE );
     NtClose( EnumKey );
     ExFreePool( Kbio );
     return STATUS_UNSUCCESSFUL;
@@ -962,9 +946,17 @@ BOOLEAN BindAdapter(
     PIP_INTERFACE IF;
     NDIS_STATUS NdisStatus;
     LLIP_BIND_INFO BindInfo;
-    IP_ADDRESS DefaultMask = { 0 };
-    ULONG Lookahead = LOOKAHEAD_SIZE;
+    IP_ADDRESS DefaultMask, Router;
+    ULONG Lookahead = LOOKAHEAD_SIZE, Unused;
     NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE ParameterHandle;
+    PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
+    UNICODE_STRING IPAddress = RTL_CONSTANT_STRING(L"IPAddress");
+    UNICODE_STRING Netmask = RTL_CONSTANT_STRING(L"SubnetMask");
+    UNICODE_STRING Gateway = RTL_CONSTANT_STRING(L"DefaultGateway");
+    UNICODE_STRING RegistryDataU;
+    ANSI_STRING RegistryDataA;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 
@@ -1008,14 +1000,114 @@ BOOLEAN BindAdapter(
     GetName( RegistryPath, &IF->Name );
 
     Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
+    if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n"));
+        IPDestroyInterface(IF);
+        return FALSE;
+    }
 
     TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
                 &IF->Description));
 
-    DefaultMask.Type = IP_ADDRESS_V4;
+    DbgPrint("Opening %wZ\n", RegistryPath);
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               RegistryPath,
+                               OBJ_CASE_INSENSITIVE,
+                               0,
+                               NULL);
+
+    AddrInitIPv4(&DefaultMask, 0);
+
+    Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        IF->Unicast = DefaultMask;
+        IF->Netmask = DefaultMask;
+    }
+    else
+    {
+        KeyValueInfo = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR));
+        if (!KeyValueInfo)
+        {
+            ZwClose(ParameterHandle);
+            IPDestroyInterface(IF);
+            return FALSE;
+        }
+
+        RegistryDataU.MaximumLength = 16 + sizeof(WCHAR);
+        RegistryDataU.Buffer = (PWCHAR)KeyValueInfo->Data;
+
+        Status = ZwQueryValueKey(ParameterHandle,
+                                 &IPAddress,
+                                 KeyValuePartialInformation,
+                                 KeyValueInfo,
+                                 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
+                                 &Unused);
+        if (NT_SUCCESS(Status))
+        {
+            RegistryDataU.Length = KeyValueInfo->DataLength;
+
+            RtlUnicodeStringToAnsiString(&RegistryDataA,
+                                         &RegistryDataU,
+                                         TRUE);
+
+            AddrInitIPv4(&IF->Unicast, inet_addr(RegistryDataA.Buffer));
+
+            RtlFreeAnsiString(&RegistryDataA);
+
+        }
+        else
+        {
+            IF->Unicast = DefaultMask;
+        }
+
+        Status = ZwQueryValueKey(ParameterHandle,
+                                 &Netmask,
+                                 KeyValuePartialInformation,
+                                 KeyValueInfo,
+                                 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
+                                 &Unused);
+        if (NT_SUCCESS(Status))
+        {
+            RegistryDataU.Length = KeyValueInfo->DataLength;
+
+            RtlUnicodeStringToAnsiString(&RegistryDataA,
+                                         &RegistryDataU,
+                                         TRUE);
+
+            AddrInitIPv4(&IF->Netmask, inet_addr(RegistryDataA.Buffer));
+
+            RtlFreeAnsiString(&RegistryDataA);
+        }
+        else
+        {
+            IF->Netmask = DefaultMask;
+        }
+
+        Status = ZwQueryValueKey(ParameterHandle,
+                                 &Gateway,
+                                 KeyValuePartialInformation,
+                                 KeyValueInfo,
+                                 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
+                                 &Unused);
+        if (NT_SUCCESS(Status))
+        {
+            RegistryDataU.Length = KeyValueInfo->DataLength;
 
-    IF->Unicast = DefaultMask;
-    IF->Netmask = DefaultMask;
+            RtlUnicodeStringToAnsiString(&RegistryDataA,
+                                         &RegistryDataU,
+                                         TRUE);
+
+            AddrInitIPv4(&Router, inet_addr(RegistryDataA.Buffer));
+
+            RtlFreeAnsiString(&RegistryDataA);
+
+            if (!AddrIsUnspecified(&Router)) RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, IF, 1);
+        }
+
+        ZwClose(ParameterHandle);
+    }
 
     IF->Broadcast.Type = IP_ADDRESS_V4;
     IF->Broadcast.Address.IPv4Address =
@@ -1046,6 +1138,7 @@ BOOLEAN BindAdapter(
 
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
+        IPUnregisterInterface(IF);
         IPDestroyInterface(IF);
         return FALSE;
     }
@@ -1098,7 +1191,7 @@ NDIS_STATUS LANRegisterAdapter(
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 
-    IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
+    IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG);
     if (!IF) {
         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
         return NDIS_STATUS_RESOURCES;
@@ -1136,7 +1229,7 @@ NDIS_STATUS LANRegisterAdapter(
         KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
     else if (NdisStatus != NDIS_STATUS_SUCCESS) {
        TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
-       exFreePool(IF);
+       ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
         return NdisStatus;
     }
 
@@ -1161,7 +1254,7 @@ NDIS_STATUS LANRegisterAdapter(
     default:
         /* Unsupported media */
         TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
-        exFreePool(IF);
+        ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
         return NDIS_STATUS_NOT_SUPPORTED;
     }
 
@@ -1173,7 +1266,7 @@ NDIS_STATUS LANRegisterAdapter(
                           sizeof(UINT));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
        TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (NDISCall)\n", AdapterName));
-        exFreePool(IF);
+        ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
         return NdisStatus;
     }
 
@@ -1185,7 +1278,7 @@ NDIS_STATUS LANRegisterAdapter(
                           sizeof(UINT));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
-        exFreePool(IF);
+        ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
         return NdisStatus;
     }
 
@@ -1208,7 +1301,7 @@ NDIS_STATUS LANRegisterAdapter(
                           IF->HWAddressLength);
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
-        exFreePool(IF);
+        ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
         return NdisStatus;
     }
 
@@ -1220,7 +1313,7 @@ NDIS_STATUS LANRegisterAdapter(
                           sizeof(UINT));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
-        exFreePool(IF);
+        ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
         return NdisStatus;
     }
 
@@ -1230,7 +1323,7 @@ NDIS_STATUS LANRegisterAdapter(
     /* Bind adapter to IP layer */
     if( !BindAdapter(IF, RegistryPath) ) {
        TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
-       exFreePool(IF);
+       ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
        return NDIS_STATUS_NOT_ACCEPTED;
     }
 
@@ -1290,6 +1383,52 @@ NDIS_STATUS LANUnregisterAdapter(
     return NdisStatus;
 }
 
+VOID 
+NTAPI
+LANUnregisterProtocol(VOID)
+/*
+ * FUNCTION: Unregisters this protocol driver with NDIS
+ * NOTES: Does not care wether we are already registered
+ */
+{
+    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    if (ProtocolRegistered) {
+        NDIS_STATUS NdisStatus;
+        PLIST_ENTRY CurrentEntry;
+        PLIST_ENTRY NextEntry;
+        PLAN_ADAPTER Current;
+        KIRQL OldIrql;
+
+        TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
+
+        /* Search the list and remove every adapter we find */
+        CurrentEntry = AdapterListHead.Flink;
+        while (CurrentEntry != &AdapterListHead) {
+            NextEntry = CurrentEntry->Flink;
+            Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
+            /* Unregister it */
+            LANUnregisterAdapter(Current);
+            CurrentEntry = NextEntry;
+        }
+
+        TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
+
+        NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
+        ProtocolRegistered = FALSE;
+    }
+}
+
+VOID
+NTAPI
+ProtocolUnbindAdapter(
+    PNDIS_STATUS Status,
+    NDIS_HANDLE ProtocolBindingContext,
+    NDIS_HANDLE UnbindContext)
+{
+    /* We don't pend any unbinding so we can just ignore UnbindContext */
+    *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext);
+}
 
 NTSTATUS LANRegisterProtocol(
     PNDIS_STRING Name)
@@ -1327,6 +1466,9 @@ NTSTATUS LANRegisterProtocol(
     ProtChars.StatusHandler                  = ProtocolStatus;
     ProtChars.StatusCompleteHandler          = ProtocolStatusComplete;
     ProtChars.BindAdapterHandler             = ProtocolBindAdapter;
+    ProtChars.PnPEventHandler                = ProtocolPnPEvent;
+    ProtChars.UnbindAdapterHandler           = ProtocolUnbindAdapter;
+    ProtChars.UnloadHandler                  = LANUnregisterProtocol;
 
     /* Try to register protocol */
     NdisRegisterProtocol(&NdisStatus,
@@ -1344,60 +1486,4 @@ NTSTATUS LANRegisterProtocol(
     return STATUS_SUCCESS;
 }
 
-
-VOID LANUnregisterProtocol(
-    VOID)
-/*
- * FUNCTION: Unregisters this protocol driver with NDIS
- * NOTES: Does not care wether we are already registered
- */
-{
-    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
-
-    if (ProtocolRegistered) {
-        NDIS_STATUS NdisStatus;
-        PLIST_ENTRY CurrentEntry;
-        PLIST_ENTRY NextEntry;
-        PLAN_ADAPTER Current;
-        KIRQL OldIrql;
-
-        TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
-
-        /* Search the list and remove every adapter we find */
-        CurrentEntry = AdapterListHead.Flink;
-        while (CurrentEntry != &AdapterListHead) {
-            NextEntry = CurrentEntry->Flink;
-            Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
-            /* Unregister it */
-            LANUnregisterAdapter(Current);
-            CurrentEntry = NextEntry;
-        }
-
-        TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
-
-        NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
-        ProtocolRegistered = FALSE;
-    }
-}
-
-VOID LANStartup() {
-    InitializeListHead( &LanSendCompleteList );
-    KeInitializeSpinLock( &LanSendCompleteLock );
-}
-
-VOID LANShutdown() {
-    KIRQL OldIrql;
-    PLAN_WQ_ITEM WorkItem;
-    PLIST_ENTRY ListEntry;
-
-    KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
-    while( !IsListEmpty( &LanSendCompleteList ) ) {
-       ListEntry = RemoveHeadList( &LanSendCompleteList );
-       WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
-       FreeNdisPacket( WorkItem->Packet );
-       ExFreePool( WorkItem );
-    }
-    KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
-}
-
 /* EOF */