- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / datalink / lan.c
index 4633b63..a825de6 100644 (file)
@@ -18,6 +18,9 @@ UINT TransferDataCompleteCalled = 0;
 UINT LanReceiveWorkerCalled = 0;
 BOOLEAN LanReceiveWorkerBusy = FALSE;
 
+#define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
+#define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
 #define NGFP(_Packet)                                             \
     {                                                             \
         PVOID _Header;                                            \
@@ -48,19 +51,14 @@ BOOLEAN ProtocolRegistered     = FALSE;
 LIST_ENTRY AdapterListHead;
 KSPIN_LOCK AdapterListLock;
 
-/* Work around being called back into afd at Dpc level */
-KSPIN_LOCK LanWorkLock;
-LIST_ENTRY LanWorkList;
-WORK_QUEUE_ITEM LanWorkItem;
-
 /* Double complete protection */
 KSPIN_LOCK LanSendCompleteLock;
 LIST_ENTRY LanSendCompleteList;
 
 VOID LanChainCompletion( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
-    PLAN_WQ_ITEM PendingCompletion = 
+    PLAN_WQ_ITEM PendingCompletion =
        ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
-    
+
     if( !PendingCompletion ) return;
 
     PendingCompletion->Packet  = NdisPacket;
@@ -82,7 +80,7 @@ BOOLEAN LanShouldComplete( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
         ListEntry = ListEntry->Flink ) {
        CompleteEntry = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
 
-       if( CompleteEntry->Adapter == Adapter && 
+       if( CompleteEntry->Adapter == Adapter &&
            CompleteEntry->Packet  == NdisPacket ) {
            RemoveEntryList( ListEntry );
            KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
@@ -165,6 +163,28 @@ VOID FreeAdapter(
 }
 
 
+NTSTATUS TcpipLanGetDwordOid
+( PIP_INTERFACE Interface,
+  NDIS_OID Oid,
+  PDWORD Result ) {
+    /* Get maximum frame size */
+    if( Interface->Context ) {
+        return NDISCall((PLAN_ADAPTER)Interface->Context,
+                        NdisRequestQueryInformation,
+                        Oid,
+                        Result,
+                        sizeof(DWORD));
+    } else switch( Oid ) { /* Loopback Case */
+    case OID_GEN_HARDWARE_STATUS:
+        *Result = NdisHardwareStatusReady;
+        return STATUS_SUCCESS;
+
+    default:
+        return STATUS_INVALID_PARAMETER;
+    }
+}
+
+
 VOID STDCALL ProtocolOpenAdapterComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status,
@@ -264,10 +284,9 @@ VOID STDCALL ProtocolSendComplete(
     }
 }
 
-VOID STDCALL LanReceiveWorker( PVOID Context ) {
+VOID LanReceiveWorker( PVOID Context ) {
     UINT PacketType;
-    PLIST_ENTRY ListEntry;
-    PLAN_WQ_ITEM WorkItem;
+    PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
     PNDIS_PACKET Packet;
     PLAN_ADAPTER Adapter;
     UINT BytesTransferred;
@@ -275,93 +294,70 @@ VOID STDCALL LanReceiveWorker( PVOID Context ) {
     IP_PACKET IPPacket;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
-    
-    while( (ListEntry = 
-           ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
-       WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
-
-       TI_DbgPrint(DEBUG_DATALINK, ("WorkItem: %x\n", WorkItem));
-
-       Packet = WorkItem->Packet;
-       Adapter = WorkItem->Adapter;
-       BytesTransferred = WorkItem->BytesTransferred;
-
-       ExFreePool( WorkItem );
 
-        IPPacket.NdisPacket = Packet;
-       
-        NdisGetFirstBufferFromPacket(Packet,
-                                     &NdisBuffer,
-                                     &IPPacket.Header,
-                                     &IPPacket.ContigSize,
-                                     &IPPacket.TotalSize);
-
-       IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
-        /* Determine which upper layer protocol that should receive
-           this packet and pass it to the correct receive handler */
-
-       TI_DbgPrint(MID_TRACE,
-                   ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
-                    IPPacket.ContigSize, IPPacket.TotalSize,
-                    BytesTransferred));
-
-        PacketType = PC(IPPacket.NdisPacket)->PacketType;
-       IPPacket.Position = 0;
-
-       TI_DbgPrint
-               (DEBUG_DATALINK,
-                ("Ether Type = %x ContigSize = %d Total = %d\n",
-                 PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
-       
-        switch (PacketType) {
-            case ETYPE_IPv4:
-            case ETYPE_IPv6:
-               TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
-                IPReceive(Adapter->Context, &IPPacket);
-                break;
-            case ETYPE_ARP:
-               TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
-                ARPReceive(Adapter->Context, &IPPacket);
-            default:
-                break;
-        }
-
-       FreeNdisPacket( Packet );
+    Packet = WorkItem->Packet;
+    Adapter = WorkItem->Adapter;
+    BytesTransferred = WorkItem->BytesTransferred;
+    
+    IPPacket.NdisPacket = Packet;
+    
+    NdisGetFirstBufferFromPacket(Packet,
+                                &NdisBuffer,
+                                &IPPacket.Header,
+                                &IPPacket.ContigSize,
+                                &IPPacket.TotalSize);
+    
+    IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
+    /* Determine which upper layer protocol that should receive
+       this packet and pass it to the correct receive handler */
+    
+    TI_DbgPrint(MID_TRACE,
+               ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
+                IPPacket.ContigSize, IPPacket.TotalSize,
+                BytesTransferred));
+    
+    PacketType = PC(IPPacket.NdisPacket)->PacketType;
+    IPPacket.Position = 0;
+    
+    TI_DbgPrint
+       (DEBUG_DATALINK,
+        ("Ether Type = %x ContigSize = %d Total = %d\n",
+         PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
+    
+    switch (PacketType) {
+    case ETYPE_IPv4:
+    case ETYPE_IPv6:
+       TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
+       IPReceive(Adapter->Context, &IPPacket);
+       break;
+    case ETYPE_ARP:
+       TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
+       ARPReceive(Adapter->Context, &IPPacket);
+    default:
+       break;
     }
-    TI_DbgPrint(DEBUG_DATALINK, ("Leaving\n"));
-    LanReceiveWorkerBusy = FALSE;
+    
+    FreeNdisPacket( Packet );
 }
 
-VOID LanSubmitReceiveWork( 
+VOID LanSubmitReceiveWork(
     NDIS_HANDLE BindingContext,
     PNDIS_PACKET Packet,
     NDIS_STATUS Status,
     UINT BytesTransferred) {
-    PLAN_WQ_ITEM WQItem;
+    LAN_WQ_ITEM WQItem;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
-    KIRQL OldIrql;
+    PVOID LanWorkItem;
 
-    TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
-    
-    WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
-    if( !WQItem ) {
-       TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
-       return;
-    }
+    TI_DbgPrint(DEBUG_DATALINK,("called\n"));
 
-    WQItem->Packet = Packet;
-    WQItem->Adapter = Adapter;
-    WQItem->BytesTransferred = BytesTransferred;
-    InsertTailList( &LanWorkList, &WQItem->ListEntry );
-    if( !LanReceiveWorkerBusy ) {
-       LanReceiveWorkerBusy = TRUE;
-       ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
-       TI_DbgPrint(DEBUG_DATALINK,
-                   ("Work item inserted %x %x\n", &LanWorkItem, WQItem));
-    } else {
-       DbgPrint("LAN WORKER BUSY %x %x\n", &LanWorkItem, WQItem);
-    }
-    TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
+    WQItem.Packet = Packet;
+    WQItem.Adapter = Adapter;
+    WQItem.BytesTransferred = BytesTransferred;
+
+    if( !ChewCreate
+       ( &LanWorkItem, sizeof(LAN_WQ_ITEM),  LanReceiveWorker, &WQItem ) )
+       ASSERT(0);
 }
 
 VOID STDCALL ProtocolTransferDataComplete(
@@ -383,6 +379,8 @@ VOID STDCALL ProtocolTransferDataComplete(
 {
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
 
+    TI_DbgPrint(DEBUG_DATALINK,("called\n"));
+
     TransferDataCompleteCalled++;
     ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
 
@@ -422,7 +420,6 @@ NDIS_STATUS STDCALL ProtocolReceive(
     PNDIS_PACKET NdisPacket;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
     PETH_HEADER EHeader  = (PETH_HEADER)HeaderBuffer;
-    KIRQL OldIrql;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
 
@@ -457,15 +454,12 @@ NDIS_STATUS STDCALL ProtocolReceive(
 
     /* Get a transfer data packet */
 
-    TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n", 
+    TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
                                 Adapter, Adapter->MTU));
 
-    TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
-
     NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
                                            PacketSize + HeaderBufferSize );
     if( NdisStatus != NDIS_STATUS_SUCCESS ) {
-       TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
        return NDIS_STATUS_NOT_ACCEPTED;
     }
 
@@ -496,7 +490,7 @@ NDIS_STATUS STDCALL ProtocolReceive(
            ASSERT(PacketSize <= Adapter->MTU);
 
             NdisTransferData(&NdisStatus, Adapter->NdisHandle,
-                             MacReceiveContext, 0, PacketSize, 
+                             MacReceiveContext, 0, PacketSize,
                             NdisPacket, &BytesTransferred);
         }
         else
@@ -504,7 +498,6 @@ NDIS_STATUS STDCALL ProtocolReceive(
             BytesTransferred = 0;
         }
     }
-    TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
     TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
 
     if (NdisStatus != NDIS_STATUS_PENDING)
@@ -577,10 +570,10 @@ VOID STDCALL ProtocolBindAdapter(
  *     SystemSpecific2: Unused & must not be touched
  */
 {
-       /* XXX confirm that this is still true, or re-word the following comment */
-       /* we get to ignore BindContext because we will never pend an operation with NDIS */
-       TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
-       *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
+    /* XXX confirm that this is still true, or re-word the following comment */
+    /* we get to ignore BindContext because we will never pend an operation with NDIS */
+    TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
+    *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
 }
 
 
@@ -607,7 +600,7 @@ VOID LANTransmit(
     KIRQL OldIrql;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
 
-    TI_DbgPrint(DEBUG_DATALINK, 
+    TI_DbgPrint(DEBUG_DATALINK,
                ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
                 NdisPacket, Offset, Adapter));
 
@@ -620,11 +613,11 @@ VOID LANTransmit(
                 Adapter->HWAddress[4] & 0xff,
                 Adapter->HWAddress[5] & 0xff));
 
-    /* XXX arty -- Handled adjustment in a saner way than before ... 
+    /* XXX arty -- Handled adjustment in a saner way than before ...
      * not needed immediately */
     GetDataPtr( NdisPacket, 0, &Data, &Size );
 
-    LanChainCompletion( Adapter, NdisPacket );    
+    LanChainCompletion( Adapter, NdisPacket );
 
     if (Adapter->State == LAN_STATE_STARTED) {
         switch (Adapter->Media) {
@@ -642,25 +635,25 @@ VOID LANTransmit(
             RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
 
             switch (Type) {
-                case LAN_PROTO_IPv4:
-                    EHeader->EType = ETYPE_IPv4;
-                    break;
-                case LAN_PROTO_ARP:
-                    EHeader->EType = ETYPE_ARP;
-                    break;
-                case LAN_PROTO_IPv6:
-                    EHeader->EType = ETYPE_IPv6;
-                    break;
-                default:
+            case LAN_PROTO_IPv4:
+                EHeader->EType = ETYPE_IPv4;
+                break;
+            case LAN_PROTO_ARP:
+                EHeader->EType = ETYPE_ARP;
+                break;
+            case LAN_PROTO_IPv6:
+                EHeader->EType = ETYPE_IPv6;
+                break;
+            default:
 #ifdef DBG
-                    /* Should not happen */
-                    TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
+                /* Should not happen */
+                TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
 
-                    ProtocolSendComplete((NDIS_HANDLE)Context,
-                                         NdisPacket,
-                                         NDIS_STATUS_FAILURE);
+                ProtocolSendComplete((NDIS_HANDLE)Context,
+                                     NdisPacket,
+                                     NDIS_STATUS_FAILURE);
 #endif
-                    return;
+                return;
             }
             break;
 
@@ -672,8 +665,8 @@ VOID LANTransmit(
        TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
        if( LinkAddress ) {
            TI_DbgPrint
-               ( MID_TRACE, 
-                 ("Link Address [%02x %02x %02x %02x %02x %02x]\n", 
+               ( MID_TRACE,
+                 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
                   ((PCHAR)LinkAddress)[0] & 0xff,
                   ((PCHAR)LinkAddress)[1] & 0xff,
                   ((PCHAR)LinkAddress)[2] & 0xff,
@@ -685,13 +678,13 @@ VOID LANTransmit(
        TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
        TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
         NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
-       TI_DbgPrint(MID_TRACE, ("NdisSend %s\n", 
+       TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
                                NdisStatus == NDIS_STATUS_PENDING ?
                                "Pending" : "Complete"));
        TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
 
-       /* I had a talk with vizzini: these really ought to be here. 
-        * we're supposed to see these completed by ndis *only* when 
+       /* I had a talk with vizzini: these really ought to be here.
+        * we're supposed to see these completed by ndis *only* when
         * status_pending is returned.  Note that this is different from
         * the situation with IRPs. */
         if (NdisStatus != NDIS_STATUS_PENDING)
@@ -701,69 +694,16 @@ VOID LANTransmit(
     }
 }
 
-static NTSTATUS 
+static NTSTATUS
 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
     OBJECT_ATTRIBUTES Attributes;
     NTSTATUS Status;
-    
+
     InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
-    Status = ZwOpenKey(RegHandle, GENERIC_READ, &Attributes);
+    Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
     return Status;
 }
 
-static NTSTATUS ReadIPAddressFromRegistry( HANDLE RegHandle,
-                                          PWCHAR RegistryValue,
-                                          PIP_ADDRESS Address ) {
-    UNICODE_STRING ValueName;
-    UNICODE_STRING UnicodeAddress; 
-    NTSTATUS Status;
-    ULONG ResultLength;
-    UCHAR buf[1024];
-    PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
-    ANSI_STRING AnsiAddress;
-    ULONG AnsiLen;
-
-    RtlInitUnicodeString(&ValueName, RegistryValue);
-    Status = 
-       ZwQueryValueKey(RegHandle, 
-                       &ValueName, 
-                       KeyValuePartialInformation, 
-                       Information, 
-                       sizeof(buf), 
-                       &ResultLength);
-
-    if (!NT_SUCCESS(Status))
-       return Status;
-    /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
-    TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
-    
-    UnicodeAddress.Buffer = (PWCHAR)&Information->Data;
-    UnicodeAddress.Length = Information->DataLength;
-    UnicodeAddress.MaximumLength = Information->DataLength;
-    
-    AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress);
-    if(!AnsiLen)
-       return STATUS_NO_MEMORY;
-    
-    AnsiAddress.Buffer = exAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
-    if(!AnsiAddress.Buffer)
-       return STATUS_NO_MEMORY;
-
-    AnsiAddress.Length = AnsiLen;
-    AnsiAddress.MaximumLength = AnsiLen;
-    
-    Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
-    if (!NT_SUCCESS(Status)) {
-       exFreePool(AnsiAddress.Buffer);
-       return STATUS_UNSUCCESSFUL;
-    }
-    
-    AnsiAddress.Buffer[AnsiAddress.Length] = 0;
-    AddrInitIPv4(Address, inet_addr(AnsiAddress.Buffer));
-
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
                                        PWCHAR RegistryValue,
                                        PUNICODE_STRING String ) {
@@ -775,25 +715,25 @@ static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
     PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
 
     RtlInitUnicodeString(&ValueName, RegistryValue);
-    Status = 
-       ZwQueryValueKey(RegHandle, 
-                       &ValueName, 
-                       KeyValuePartialInformation, 
-                       Information, 
-                       sizeof(buf), 
+    Status =
+       ZwQueryValueKey(RegHandle,
+                       &ValueName,
+                       KeyValuePartialInformation,
+                       Information,
+                       sizeof(buf),
                        &ResultLength);
 
     if (!NT_SUCCESS(Status))
        return Status;
     /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
     TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
-    
+
     UnicodeString.Buffer = (PWCHAR)&Information->Data;
-    UnicodeString.Length = Information->DataLength;
+    UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
     UnicodeString.MaximumLength = Information->DataLength;
-    String->Buffer = 
-       (PWCHAR)exAllocatePool( NonPagedPool, 
+
+    String->Buffer =
+       (PWCHAR)exAllocatePool( NonPagedPool,
                                UnicodeString.MaximumLength + sizeof(WCHAR) );
 
     if( !String->Buffer ) return STATUS_NO_MEMORY;
@@ -804,32 +744,166 @@ static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
     return STATUS_SUCCESS;
 }
 
-static VOID GetSimpleAdapterNameFromRegistryPath
-( PUNICODE_STRING TargetString,
-  PUNICODE_STRING RegistryPath ) {
-    PWCHAR i, LastSlash = NULL;
-    UINT NewStringLength = 0;
+/*
+ * Utility to copy and append two unicode strings.
+ *
+ * IN OUT PUNICODE_STRING ResultFirst -> First string and result
+ * IN     PUNICODE_STRING Second      -> Second string to append
+ * IN     BOOL            Deallocate  -> TRUE: Deallocate First string before
+ *                                       overwriting.
+ *
+ * Returns NTSTATUS.
+ */
+
+NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
+                                  PUNICODE_STRING Second,
+                                  BOOL Deallocate) {
+    NTSTATUS Status;
+    UNICODE_STRING Ustr = *ResultFirst;
+    PWSTR new_string = ExAllocatePoolWithTag
+        (PagedPool,
+         (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TAG_STRING);
+    if( !new_string ) {
+       return STATUS_NO_MEMORY;
+    }
+    memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
+    memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
+           Second->Buffer, Second->Length );
+    if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
+    ResultFirst->Length = Ustr.Length + Second->Length;
+    ResultFirst->MaximumLength = ResultFirst->Length;
+    new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
+    Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
+       STATUS_SUCCESS : STATUS_NO_MEMORY;
+    ExFreePool(new_string);
+    return Status;
+}
+
+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 };
+    HANDLE DescKey = NULL, LinkageKey = NULL;
+    NTSTATUS Status;
+
+    TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
+
+    RtlInitUnicodeString(&BackSlash, L"\\");
+    RtlInitUnicodeString(&Linkage, L"\\Linkage");
+
+    RtlInitUnicodeString(&DescKeyName, L"");
+    AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
+    AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
+    AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
+
+    RtlInitUnicodeString(&LinkageKeyName, L"");
+    AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
+    AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
+
+    Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
+    if( !NT_SUCCESS(Status) ) goto cleanup;
+
+    Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
+    if( !NT_SUCCESS(Status) ) goto cleanup;
+
+    if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
+        Status = OpenRegistryKey( &DescKeyName, &DescKey );
+        if( !NT_SUCCESS(Status) ) goto cleanup;
+
+        Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
+        if( !NT_SUCCESS(Status) ) goto cleanup;
+
+        TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
+    } else Status = STATUS_UNSUCCESSFUL;
+
+cleanup:
+    RtlFreeUnicodeString( &RootDevice );
+    RtlFreeUnicodeString( &LinkageKeyName );
+    RtlFreeUnicodeString( &DescKeyName );
+    if( LinkageKey ) NtClose( LinkageKey );
+    if( DescKey ) NtClose( DescKey );
+
+    TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
+
+    return Status;
+}
+
+static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
+                                          PUNICODE_STRING DeviceDesc ) {
+    UNICODE_STRING EnumKeyName, TargetKeyName;
+    HANDLE EnumKey;
+    NTSTATUS Status;
+    ULONG i;
+    KEY_BASIC_INFORMATION *Kbio =
+        ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
+    ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
+
+    RtlInitUnicodeString
+        (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
+
+    Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
 
-    for( i = RegistryPath->Buffer; 
-        i < RegistryPath->Buffer + 
-            (RegistryPath->Length / sizeof(WCHAR));
-        i++ ) if( *i == '\\' ) LastSlash = i;
+    if( !NT_SUCCESS(Status) )
+        TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
+                                    &EnumKeyName, Status));
 
-    if( LastSlash ) LastSlash++; else LastSlash = RegistryPath->Buffer;
+    for( i = 0; NT_SUCCESS(Status); i++ ) {
+        Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
+                                 Kbio, KbioLength, &ResultLength );
 
-    NewStringLength = RegistryPath->MaximumLength - 
-       ((LastSlash - RegistryPath->Buffer) * sizeof(WCHAR));
+        if( Status == STATUS_BUFFER_TOO_SMALL ) {
+            ExFreePool( Kbio );
+            KbioLength = ResultLength;
+            Kbio = ExAllocatePool( NonPagedPool, KbioLength );
 
-    TargetString->Buffer = 
-       (PWCHAR)exAllocatePool( NonPagedPool, NewStringLength );
+            Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
+                                     Kbio, KbioLength, &ResultLength );
 
-    if( !TargetString->Buffer ) {
-       TargetString->Length = TargetString->MaximumLength = 0;
-       return;
+            TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
+            return Status;
+        }
+
+        if( NT_SUCCESS(Status) ) {
+            TargetKeyName.Length = TargetKeyName.MaximumLength =
+                Kbio->NameLength;
+            TargetKeyName.Buffer = Kbio->Name;
+
+            Status = CheckForDeviceDesc
+                ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
+            if( NT_SUCCESS(Status) ) {
+                NtClose( EnumKey );
+                return Status;
+            } else Status = STATUS_SUCCESS;
+        }
     }
 
-    TargetString->Length = TargetString->MaximumLength = NewStringLength;
-    RtlCopyMemory( TargetString->Buffer, LastSlash, NewStringLength );
+    RtlInitUnicodeString( DeviceDesc, L"" );
+    AppendUnicodeString( DeviceDesc, &TargetKeyName, FALSE );
+    NtClose( EnumKey );
+    return STATUS_UNSUCCESSFUL;
+}
+
+VOID GetName( PUNICODE_STRING RegistryKey,
+              PUNICODE_STRING OutName ) {
+    PWCHAR Ptr;
+    UNICODE_STRING PartialRegistryKey;
+
+    PartialRegistryKey.Buffer =
+        RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
+    Ptr = PartialRegistryKey.Buffer;
+
+    while( *Ptr != L'\\' &&
+           ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
+        Ptr++;
+
+    PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
+        (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
+
+    RtlInitUnicodeString( OutName, L"" );
+    AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
 }
 
 VOID BindAdapter(
@@ -847,7 +921,7 @@ VOID BindAdapter(
     PIP_INTERFACE IF;
     NDIS_STATUS NdisStatus;
     LLIP_BIND_INFO BindInfo;
-    IP_ADDRESS DefaultGateway, DefaultMask = { 0 };
+    IP_ADDRESS DefaultMask = { 0 };
     ULONG Lookahead = LOOKAHEAD_SIZE;
     NTSTATUS Status;
     HANDLE RegHandle = 0;
@@ -862,7 +936,7 @@ VOID BindAdapter(
                           &Lookahead,
                           sizeof(ULONG));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
+        TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
         return;
     }
 
@@ -882,87 +956,36 @@ VOID BindAdapter(
         return;
     }
 
-    /* 
-     * Query per-adapter configuration from the registry 
+    /*
+     * Query per-adapter configuration from the registry
      * In case anyone is curious:  there *is* an Ndis configuration api
      * for this sort of thing, but it doesn't really support things like
      * REG_MULTI_SZ very well, and there is a note in the DDK that says that
      * protocol drivers developed for win2k and above just use the native
      * services (ZwOpenKey, etc).
      */
-    
-    Status = OpenRegistryKey( RegistryPath, &RegHandle );
-           
-    if(NT_SUCCESS(Status))
-       Status = ReadIPAddressFromRegistry( RegHandle, L"DefaultGateway",
-                                           &DefaultGateway );
-    if(!NT_SUCCESS(Status)) {
-       Status = STATUS_SUCCESS;
-       RtlZeroMemory( &DefaultGateway, sizeof(DefaultGateway) );
-    }
 
-    if(NT_SUCCESS(Status))
-       Status = ReadIPAddressFromRegistry( RegHandle, L"IPAddress",
-                                           &IF->Unicast );
-    if(NT_SUCCESS(Status)) 
-       Status = ReadIPAddressFromRegistry( RegHandle, L"SubnetMask",
-                                           &IF->Netmask );
+    GetName( RegistryPath, &IF->Name );
 
-    IF->Broadcast.Type = IP_ADDRESS_V4;
-    IF->Broadcast.Address.IPv4Address = 
-        IF->Unicast.Address.IPv4Address | 
-        ~IF->Netmask.Address.IPv4Address;
-
-    TI_DbgPrint(MID_TRACE,("BCAST(IF) %s\n", A2S(&IF->Broadcast)));
+    Status = OpenRegistryKey( RegistryPath, &RegHandle );
 
     if(NT_SUCCESS(Status)) {
-       Status = ReadStringFromRegistry( RegHandle, L"DeviceDesc",
-                                        &IF->Name );
+       Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
+        TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
+                    &IF->Description));
+    }
 
-       RtlZeroMemory( &IF->Name, sizeof( IF->Name ) );
+    DefaultMask.Type = IP_ADDRESS_V4;
 
-       /* I think that not getting a devicedesc is not a fatal error */
-       if( !NT_SUCCESS(Status) ) {
-           if( IF->Name.Buffer ) exFreePool( IF->Name.Buffer );
-           GetSimpleAdapterNameFromRegistryPath( &IF->Name, RegistryPath );
-       }
-       Status = STATUS_SUCCESS;
-    }
+    IF->Unicast = DefaultMask;
+    IF->Netmask = DefaultMask;
 
-    if(!NT_SUCCESS(Status))
-    {
-       TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status));
-       
-       /* XXX how do we proceed?  No ip address, no parameters... do we guess? */
-       if(RegHandle)  
-           ZwClose(RegHandle);
-       IPDestroyInterface(IF);
-       return;
-    }
-    
-    TI_DbgPrint
-       (MID_TRACE, 
-        ("--> Our IP address on this interface: '%s'\n", 
-         A2S(&IF->Unicast)));
-    
-    TI_DbgPrint
-       (MID_TRACE, 
-        ("--> Our net mask on this interface: '%s'\n", 
-         A2S(&IF->Netmask)));
-
-    if( DefaultGateway.Address.IPv4Address ) {
-       TI_DbgPrint
-           (MID_TRACE, 
-            ("--> Our gateway is: '%s'\n", 
-             A2S(&DefaultGateway)));
-
-       /* Create a default route */
-       RouterCreateRoute( &DefaultMask, /* Zero */
-                          &DefaultMask, /* Zero */
-                          &DefaultGateway,
-                          IF,
-                          1 );
-    }
+    IF->Broadcast.Type = IP_ADDRESS_V4;
+    IF->Broadcast.Address.IPv4Address =
+        IF->Unicast.Address.IPv4Address |
+        ~IF->Netmask.Address.IPv4Address;
+
+    TI_DbgPrint(DEBUG_DATALINK,("BCAST(IF) %s\n", A2S(&IF->Broadcast)));
 
     /* Get maximum link speed */
     NdisStatus = NDISCall(Adapter,
@@ -985,7 +1008,7 @@ VOID BindAdapter(
                           sizeof(UINT));
 
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
+        TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
         IPDestroyInterface(IF);
         return;
     }
@@ -1090,7 +1113,7 @@ NDIS_STATUS LANRegisterAdapter(
         IF->HeaderSize      = sizeof(ETH_HEADER);
         IF->MinFrameSize    = 60;
         AddressOID          = OID_802_3_CURRENT_ADDRESS;
-        IF->PacketFilter    = 
+        IF->PacketFilter    =
             NDIS_PACKET_TYPE_BROADCAST |
             NDIS_PACKET_TYPE_DIRECTED  |
             NDIS_PACKET_TYPE_MULTICAST;
@@ -1209,10 +1232,10 @@ NDIS_STATUS LANUnregisterAdapter(
         NdisCloseAdapter(&NdisStatus, NdisHandle);
         if (NdisStatus == NDIS_STATUS_PENDING) {
             TcpipWaitForSingleObject(&Adapter->Event,
-                                  UserRequest,
-                                  KernelMode,
-                                  FALSE,
-                                  NULL);
+                                     UserRequest,
+                                     KernelMode,
+                                     FALSE,
+                                     NULL);
             NdisStatus = Adapter->NdisStatus;
         }
     } else
@@ -1261,16 +1284,16 @@ NTSTATUS LANRegisterProtocol(
     ProtChars.StatusCompleteHandler          = ProtocolStatusComplete;
     ProtChars.BindAdapterHandler             = ProtocolBindAdapter;
 
-       /* Try to register protocol */
+    /* Try to register protocol */
     NdisRegisterProtocol(&NdisStatus,
                          &NdisProtocolHandle,
                          &ProtChars,
                          sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
     if (NdisStatus != NDIS_STATUS_SUCCESS)
-        {
-                TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
+    {
+        TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
         return (NTSTATUS)NdisStatus;
-        }
+    }
 
     ProtocolRegistered = TRUE;
 
@@ -1300,7 +1323,7 @@ VOID LANUnregisterProtocol(
         CurrentEntry = AdapterListHead.Flink;
         while (CurrentEntry != &AdapterListHead) {
             NextEntry = CurrentEntry->Flink;
-               Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
+            Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
             /* Unregister it */
             LANUnregisterAdapter(Current);
             CurrentEntry = NextEntry;
@@ -1314,10 +1337,8 @@ VOID LANUnregisterProtocol(
 }
 
 VOID LANStartup() {
-    InitializeListHead( &LanWorkList );
     InitializeListHead( &LanSendCompleteList );
     KeInitializeSpinLock( &LanSendCompleteLock );
-    ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
 }
 
 VOID LANShutdown() {
@@ -1325,15 +1346,6 @@ VOID LANShutdown() {
     PLAN_WQ_ITEM WorkItem;
     PLIST_ENTRY ListEntry;
 
-    TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
-    while( !IsListEmpty( &LanWorkList ) ) {
-       ListEntry = RemoveHeadList( &LanWorkList );
-       WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
-       FreeNdisPacket( WorkItem->Packet );
-       ExFreePool( WorkItem );
-    }
-    TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
-
     KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
     while( !IsListEmpty( &LanSendCompleteList ) ) {
        ListEntry = RemoveHeadList( &LanSendCompleteList );