- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / datalink / lan.c
index f418b08..a825de6 100644 (file)
@@ -7,20 +7,97 @@
  * REVISIONS:
  *   CSH 01/08-2000 Created
  */
-#include <tcpip.h>
-#include <lan.h>
-#include <address.h>
-#include <routines.h>
-#include <transmit.h>
-#include <receive.h>
-#include <arp.h>
 
+#include "precomp.h"
+
+/* Define this to bugcheck on double complete */
+/* #define BREAK_ON_DOUBLE_COMPLETE */
+
+UINT TransferDataCalled = 0;
+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;                                            \
+        ULONG _ContigSize, _TotalSize;                            \
+        PNDIS_BUFFER _NdisBuffer;                                 \
+                                                                  \
+        TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
+       NdisGetFirstBufferFromPacket(_Packet,                     \
+                                    &_NdisBuffer,                \
+                                    &_Header,                    \
+                                    &_ContigSize,                \
+                                    &_TotalSize);                \
+        TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
+        TI_DbgPrint(MID_TRACE,("Header    : %x\n", _Header));     \
+        TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
+        TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize));  \
+    }
+
+typedef struct _LAN_WQ_ITEM {
+    LIST_ENTRY ListEntry;
+    PNDIS_PACKET Packet;
+    PLAN_ADAPTER Adapter;
+    UINT BytesTransferred;
+} LAN_WQ_ITEM, *PLAN_WQ_ITEM;
 
 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
 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,
@@ -74,86 +151,41 @@ NDIS_STATUS NDISCall(
 }
 
 
-PNDIS_PACKET AllocateTDPacket(
+VOID FreeAdapter(
     PLAN_ADAPTER Adapter)
 /*
- * FUNCTION: Allocates an NDIS packet for NdisTransferData
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure
  * ARGUMENTS:
- *     Adapter = Pointer to LAN_ADAPTER structure
- * RETURNS:
- *     Pointer to NDIS packet or NULL if there was not enough free
- *     non-paged memory
+ *     Adapter = Pointer to LAN_ADAPTER structure to free
  */
 {
-    NDIS_STATUS NdisStatus;
-    PNDIS_PACKET NdisPacket;
-    PNDIS_BUFFER Buffer;
-    PVOID Data;
-
-    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
-    if (NdisStatus != NDIS_STATUS_SUCCESS)
-        return NULL;
-
-    Data = ExAllocatePool(NonPagedPool, Adapter->MTU);
-    if (!Data) {
-        NdisFreePacket(NdisPacket);
-        return NULL;
-    }
-        
-    NdisAllocateBuffer(&NdisStatus,
-                      &Buffer,
-                      GlobalBufferPool,
-                      Data,
-                      Adapter->MTU);
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        NdisFreePacket(NdisPacket);
-        ExFreePool(Data);
-        return NULL;
-    }
-
-    NdisChainBufferAtFront(NdisPacket, Buffer);
-
-    PC(NdisPacket)->Context = NULL; /* End of list */
-
-    return NdisPacket;
+    exFreePool(Adapter);
 }
 
 
-VOID FreeTDPackets(
-    PLAN_ADAPTER Adapter)
-/*
- * FUNCTION: Frees transfer data packets
- * ARGUMENTS:
- *     Adapter = Pointer to LAN_ADAPTER structure
- */
-{
-    PNDIS_PACKET NdisPacket, Next;
-
-    /* Release transfer data packets */
-    NdisPacket = Adapter->TDPackets;
-    while (NdisPacket) {
-        Next = PC(NdisPacket)->Context;
-        FreeNdisPacket(NdisPacket);
-        NdisPacket = Next;
-    }
-    Adapter->TDPackets = NULL;
-}
-
+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;
 
-VOID FreeAdapter(
-    PLAN_ADAPTER Adapter)
-/*
- * FUNCTION: Frees memory for a LAN_ADAPTER structure
- * ARGUMENTS:
- *     Adapter = Pointer to LAN_ADAPTER structure to free
- */
-{
-    FreeTDPackets(Adapter);
-    ExFreePool(Adapter);
+    default:
+        return STATUS_INVALID_PARAMETER;
+    }
 }
 
 
-VOID ProtocolOpenAdapterComplete(
+VOID STDCALL ProtocolOpenAdapterComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status,
     NDIS_STATUS OpenErrorStatus)
@@ -173,7 +205,7 @@ VOID ProtocolOpenAdapterComplete(
 }
 
 
-VOID ProtocolCloseAdapterComplete(
+VOID STDCALL ProtocolCloseAdapterComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status)
 /*
@@ -193,7 +225,7 @@ VOID ProtocolCloseAdapterComplete(
 }
 
 
-VOID ProtocolResetComplete(
+VOID STDCALL ProtocolResetComplete(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS Status)
 /*
@@ -207,7 +239,7 @@ VOID ProtocolResetComplete(
 }
 
 
-VOID ProtocolRequestComplete(
+VOID STDCALL ProtocolRequestComplete(
     NDIS_HANDLE BindingContext,
     PNDIS_REQUEST NdisRequest,
     NDIS_STATUS Status)
@@ -230,7 +262,7 @@ VOID ProtocolRequestComplete(
 }
 
 
-VOID ProtocolSendComplete(
+VOID STDCALL ProtocolSendComplete(
     NDIS_HANDLE BindingContext,
     PNDIS_PACKET Packet,
     NDIS_STATUS Status)
@@ -242,17 +274,93 @@ VOID ProtocolSendComplete(
  *     Status         = Status of the operation
  */
 {
-       PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+    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"));
+    }
+}
 
-    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+VOID LanReceiveWorker( PVOID Context ) {
+    UINT PacketType;
+    PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
+    PNDIS_PACKET Packet;
+    PLAN_ADAPTER Adapter;
+    UINT BytesTransferred;
+    PNDIS_BUFFER NdisBuffer;
+    IP_PACKET IPPacket;
 
-    AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
+    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 
-    (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
+    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;
+    }
+    
+    FreeNdisPacket( Packet );
 }
 
+VOID LanSubmitReceiveWork(
+    NDIS_HANDLE BindingContext,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS Status,
+    UINT BytesTransferred) {
+    LAN_WQ_ITEM WQItem;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+    PVOID LanWorkItem;
+
+    TI_DbgPrint(DEBUG_DATALINK,("called\n"));
+
+    WQItem.Packet = Packet;
+    WQItem.Adapter = Adapter;
+    WQItem.BytesTransferred = BytesTransferred;
+
+    if( !ChewCreate
+       ( &LanWorkItem, sizeof(LAN_WQ_ITEM),  LanReceiveWorker, &WQItem ) )
+       ASSERT(0);
+}
 
-VOID ProtocolTransferDataComplete(
+VOID STDCALL ProtocolTransferDataComplete(
     NDIS_HANDLE BindingContext,
     PNDIS_PACKET Packet,
     NDIS_STATUS Status,
@@ -269,49 +377,19 @@ VOID ProtocolTransferDataComplete(
  *     type and pass it to the correct receive handler
  */
 {
-    UINT PacketType;
-    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
 
-    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
-
-    if (Status == NDIS_STATUS_SUCCESS) {
-        PNDIS_BUFFER NdisBuffer;
-        IP_PACKET IPPacket;
-
-        IPPacket.NdisPacket = Packet;
-
-        NdisGetFirstBufferFromPacket(Packet,
-                                     &NdisBuffer,
-                                     &IPPacket.Header,
-                                     &IPPacket.ContigSize,
-                                     &IPPacket.TotalSize);
-
-        /* Determine which upper layer protocol that should receive
-           this packet and pass it to the correct receive handler */
-        PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
-        switch (PacketType) {
-            case ETYPE_IPv4:
-            case ETYPE_IPv6:
-                IPReceive(Adapter->Context, &IPPacket);
-                break;
-            case ETYPE_ARP:
-                ARPReceive(Adapter->Context, &IPPacket);
-            default:
-                break;
-        }
-    }
+    TI_DbgPrint(DEBUG_DATALINK,("called\n"));
 
-    /* Release the packet descriptor */
-    KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+    TransferDataCompleteCalled++;
+    ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
 
-    PC(Packet)->Context = Adapter->TDPackets;
-    Adapter->TDPackets  = Packet;
+    if( Status != NDIS_STATUS_SUCCESS ) return;
 
-    KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+    LanSubmitReceiveWork( BindingContext, Packet, Status, BytesTransferred );
 }
 
-
-NDIS_STATUS ProtocolReceive(
+NDIS_STATUS STDCALL ProtocolReceive(
     NDIS_HANDLE BindingContext,
     NDIS_HANDLE MacReceiveContext,
     PVOID HeaderBuffer,
@@ -334,14 +412,16 @@ NDIS_STATUS ProtocolReceive(
  */
 {
     USHORT EType;
-    UINT PacketType;
+    UINT PacketType, BytesTransferred;
+    UINT temp;
     IP_PACKET IPPacket;
+    PCHAR BufferData;
+    NDIS_STATUS NdisStatus;
     PNDIS_PACKET NdisPacket;
-    PNDIS_BUFFER NdisBuffer;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
     PETH_HEADER EHeader  = (PETH_HEADER)HeaderBuffer;
 
-    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+    TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
 
     if (Adapter->State != LAN_STATE_STARTED) {
         TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
@@ -374,77 +454,65 @@ NDIS_STATUS ProtocolReceive(
 
     /* Get a transfer data packet */
 
-    KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+    TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
+                                Adapter, Adapter->MTU));
 
-    NdisPacket = Adapter->TDPackets;
-    if (NdisPacket == (PNDIS_PACKET)NULL) {
-        TI_DbgPrint(DEBUG_DATALINK, ("No available packet descriptors.\n"));
-        /* We don't have a free packet descriptor. Drop the packet */
-        KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
-        return NDIS_STATUS_SUCCESS;
+    NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
+                                           PacketSize + HeaderBufferSize );
+    if( NdisStatus != NDIS_STATUS_SUCCESS ) {
+       return NDIS_STATUS_NOT_ACCEPTED;
     }
-    Adapter->TDPackets = PC(NdisPacket)->Context;
 
-    KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+    PC(NdisPacket)->PacketType = PacketType;
 
-    if (LookaheadBufferSize < PacketSize) {
-        NDIS_STATUS NdisStatus;
-        UINT BytesTransferred;
-
-        /* Get the data */
-        NdisTransferData(&NdisStatus,
-                         Adapter->NdisHandle,
-                         MacReceiveContext,
-                         0,
-                         PacketSize,
-                         NdisPacket,
-                         &BytesTransferred);
-        if (NdisStatus != NDIS_STATUS_PENDING)
-            ProtocolTransferDataComplete(BindingContext,
-                                         NdisPacket,
-                                         NdisStatus,
-                                         BytesTransferred);
+    TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
 
-        return NDIS_STATUS_SUCCESS;
-    }
-
-    /* We got all the data in the lookahead buffer */
+    GetDataPtr( NdisPacket, 0, &BufferData, &temp );
 
     IPPacket.NdisPacket = NdisPacket;
-
-    NdisGetFirstBufferFromPacket(NdisPacket,
-                                 &NdisBuffer,
-                                 &IPPacket.Header,
-                                 &IPPacket.ContigSize,
-                                 &IPPacket.TotalSize);
-
-    RtlCopyMemory(IPPacket.Header, LookaheadBuffer, PacketSize);
-
-    switch (PacketType) {
-        case ETYPE_IPv4:
-        case ETYPE_IPv6:
-            IPReceive(Adapter->Context, &IPPacket);
-            break;
-        case ETYPE_ARP:
-            ARPReceive(Adapter->Context, &IPPacket);
-            break;
-        default:
-            break;
+    IPPacket.Position = 0;
+
+    TransferDataCalled++;
+
+    if (LookaheadBufferSize == PacketSize)
+    {
+        /* Optimized code path for packets that are fully contained in
+         * the lookahead buffer. */
+        NdisCopyLookaheadData(BufferData,
+                              LookaheadBuffer,
+                              LookaheadBufferSize,
+                              Adapter->MacOptions);
     }
+    else
+    {
+       if (NdisStatus == NDIS_STATUS_SUCCESS)
+        {
+           ASSERT(PacketSize <= Adapter->MTU);
+
+            NdisTransferData(&NdisStatus, Adapter->NdisHandle,
+                             MacReceiveContext, 0, PacketSize,
+                            NdisPacket, &BytesTransferred);
+        }
+        else
+        {
+            BytesTransferred = 0;
+        }
+    }
+    TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
 
-    /* Release the packet descriptor */
-    KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
-
-    PC(NdisPacket)->Context = Adapter->TDPackets;
-    Adapter->TDPackets      = NdisPacket;
+    if (NdisStatus != NDIS_STATUS_PENDING)
+       ProtocolTransferDataComplete(BindingContext,
+                                    NdisPacket,
+                                    NdisStatus,
+                                    PacketSize);
 
-    KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+    TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
 
     return NDIS_STATUS_SUCCESS;
 }
 
 
-VOID ProtocolReceiveComplete(
+VOID STDCALL ProtocolReceiveComplete(
     NDIS_HANDLE BindingContext)
 /*
  * FUNCTION: Called by NDIS when we're done receiving data
@@ -456,7 +524,7 @@ VOID ProtocolReceiveComplete(
 }
 
 
-VOID ProtocolStatus(
+VOID STDCALL ProtocolStatus(
     NDIS_HANDLE BindingContext,
     NDIS_STATUS GenerelStatus,
     PVOID StatusBuffer,
@@ -474,7 +542,7 @@ VOID ProtocolStatus(
 }
 
 
-VOID ProtocolStatusComplete(
+VOID STDCALL ProtocolStatusComplete(
     NDIS_HANDLE NdisBindingContext)
 /*
  * FUNCTION: Called by NDIS when a status-change has occurred
@@ -485,7 +553,7 @@ VOID ProtocolStatusComplete(
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 }
 
-VOID ProtocolBindAdapter(
+VOID STDCALL ProtocolBindAdapter(
     OUT PNDIS_STATUS   Status,
     IN  NDIS_HANDLE    BindContext,
     IN  PNDIS_STRING   DeviceName,
@@ -502,10 +570,10 @@ VOID 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\n", SystemSpecific1));
-       *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);
 }
 
 
@@ -527,17 +595,29 @@ VOID LANTransmit(
 {
     NDIS_STATUS NdisStatus;
     PETH_HEADER EHeader;
-    PVOID Data;
+    PCHAR Data;
+    UINT Size;
+    KIRQL OldIrql;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
 
-    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+    TI_DbgPrint(DEBUG_DATALINK,
+               ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
+                NdisPacket, Offset, Adapter));
+
+    TI_DbgPrint(DEBUG_DATALINK,
+               ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
+                Adapter->HWAddress[0] & 0xff,
+                Adapter->HWAddress[1] & 0xff,
+                Adapter->HWAddress[2] & 0xff,
+                Adapter->HWAddress[3] & 0xff,
+                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 );
 
-    /* NDIS send routines don't have an offset argument so we
-       must offset the data in upper layers and adjust the
-       packet here. We save the offset in the packet context
-       area so it can be undone before we release the packet */
-    Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
-    PC(NdisPacket)->DLOffset = Offset;
+    LanChainCompletion( Adapter, NdisPacket );
 
     if (Adapter->State == LAN_STATE_STARTED) {
         switch (Adapter->Media) {
@@ -555,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;
 
@@ -582,7 +662,31 @@ VOID LANTransmit(
             break;
         }
 
+       TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
+       if( LinkAddress ) {
+           TI_DbgPrint
+               ( MID_TRACE,
+                 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
+                  ((PCHAR)LinkAddress)[0] & 0xff,
+                  ((PCHAR)LinkAddress)[1] & 0xff,
+                  ((PCHAR)LinkAddress)[2] & 0xff,
+                  ((PCHAR)LinkAddress)[3] & 0xff,
+                  ((PCHAR)LinkAddress)[4] & 0xff,
+                  ((PCHAR)LinkAddress)[5] & 0xff));
+       }
+
+       TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
+       TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
         NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
+       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
+        * 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);
     } else {
@@ -590,10 +694,221 @@ VOID LANTransmit(
     }
 }
 
+static NTSTATUS
+OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
+    OBJECT_ATTRIBUTES Attributes;
+    NTSTATUS Status;
+
+    InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
+    Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
+    return Status;
+}
+
+static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
+                                       PWCHAR RegistryValue,
+                                       PUNICODE_STRING String ) {
+    UNICODE_STRING ValueName;
+    UNICODE_STRING UnicodeString;
+    NTSTATUS Status;
+    ULONG ResultLength;
+    UCHAR buf[1024];
+    PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
+
+    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));
+
+    UnicodeString.Buffer = (PWCHAR)&Information->Data;
+    UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
+    UnicodeString.MaximumLength = Information->DataLength;
+
+    String->Buffer =
+       (PWCHAR)exAllocatePool( NonPagedPool,
+                               UnicodeString.MaximumLength + sizeof(WCHAR) );
+
+    if( !String->Buffer ) return STATUS_NO_MEMORY;
+
+    String->MaximumLength = UnicodeString.MaximumLength;
+    RtlCopyUnicodeString( String, &UnicodeString );
+
+    return STATUS_SUCCESS;
+}
+
+/*
+ * 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 );
+
+    if( !NT_SUCCESS(Status) )
+        TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
+                                    &EnumKeyName, Status));
+
+    for( i = 0; NT_SUCCESS(Status); i++ ) {
+        Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
+                                 Kbio, KbioLength, &ResultLength );
+
+        if( Status == STATUS_BUFFER_TOO_SMALL ) {
+            ExFreePool( Kbio );
+            KbioLength = ResultLength;
+            Kbio = ExAllocatePool( NonPagedPool, KbioLength );
+
+            Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
+                                     Kbio, KbioLength, &ResultLength );
+
+            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;
+        }
+    }
+
+    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(
     PLAN_ADAPTER Adapter,
-               PNDIS_STRING RegistryPath)
+    PNDIS_STRING RegistryPath)
 /*
  * FUNCTION: Binds a LAN adapter to IP layer
  * ARGUMENTS:
@@ -603,13 +918,13 @@ VOID BindAdapter(
  *    bind the adapter to IP layer
  */
 {
-    INT i;
     PIP_INTERFACE IF;
-    PIP_ADDRESS Address;
-    PNDIS_PACKET Packet;
     NDIS_STATUS NdisStatus;
     LLIP_BIND_INFO BindInfo;
+    IP_ADDRESS DefaultMask = { 0 };
     ULONG Lookahead = LOOKAHEAD_SIZE;
+    NTSTATUS Status;
+    HANDLE RegHandle = 0;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 
@@ -621,24 +936,10 @@ 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;
     }
 
-    /* Allocate packets for NdisTransferData */
-    /* FIXME: How many should we allocate? */
-    Adapter->TDPackets = NULL;
-    for (i = 0; i < 2; i++) {
-        Packet              = AllocateTDPacket(Adapter);
-        if (!Packet) {
-            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-            FreeTDPackets(Adapter);
-            return;
-        }
-        PC(Packet)->Context = Adapter->TDPackets;
-        Adapter->TDPackets  = Packet;
-    }
-
     /* Bind the adapter to IP layer */
     BindInfo.Context       = Adapter;
     BindInfo.HeaderSize    = Adapter->HeaderSize;
@@ -649,109 +950,52 @@ VOID BindAdapter(
     BindInfo.Transmit      = LANTransmit;
 
     IF = IPCreateInterface(&BindInfo);
+
     if (!IF) {
         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-        FreeTDPackets(Adapter);
         return;
     }
 
-                       {
-                               /* 
-                                * 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).
-                                */
-
-                               OBJECT_ATTRIBUTES Attributes;
-                               HANDLE RegHandle;
-                               NTSTATUS Status;
-                               UNICODE_STRING ValueName;
-                               UCHAR buf[1024];
-                               PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
-                               ULONG ResultLength;
-                               ANSI_STRING AnsiAddress;
-                               UNICODE_STRING UnicodeAddress;
-                               ULONG AnsiLen;
-
-                               InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
-                               Status = ZwOpenKey(&RegHandle, GENERIC_READ, &Attributes);
-
-                               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? */
-                                               FreeTDPackets(Adapter);
-                                               IPDestroyInterface(Adapter->Context);
-                                               return;
-                                       }
-
-                               RtlInitUnicodeString(&ValueName, L"IPAddress");
-                               ZwQueryValueKey(RegHandle, &ValueName, KeyValuePartialInformation, Information, sizeof(buf), &ResultLength);
-                               ZwClose(RegHandle);
-
-                               /* 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)
-                                       {
-                                               TI_DbgPrint(MIN_TRACE, ("Unable to calculate address length\n"));
-                                               FreeTDPackets(Adapter);
-                                               IPDestroyInterface(Adapter->Context);
-                                               return;
-                                       }
-
-                               AnsiAddress.Buffer = ExAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
-                               if(!AnsiAddress.Buffer)
-                                       {
-                                               TI_DbgPrint(MIN_TRACE, ("ExAllocatePoolWithTag() failed.\n"));
-                                               FreeTDPackets(Adapter);
-                                               IPDestroyInterface(Adapter->Context);
-                                               return;
-                                       }
-        AnsiAddress.Length = AnsiLen;
-        AnsiAddress.MaximumLength = AnsiLen;
-
-                               Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
-        if (!NT_SUCCESS(Status))
-                                       {
-                                               TI_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToAnsiString() failed with Status 0x%lx.\n", Status));
-                                               FreeTDPackets(Adapter);
-                                               IPDestroyInterface(Adapter->Context);
-                                               return;
-                                       }
-
-                               AnsiAddress.Buffer[AnsiAddress.Length] = 0;
-                               Address = AddrBuildIPv4(inet_addr(AnsiAddress.Buffer));
-                               if (!Address) {
-                                               TI_DbgPrint(MIN_TRACE, ("AddrBuildIPv4() failed.\n"));
-                                               FreeTDPackets(Adapter);
-                                               IPDestroyInterface(Adapter->Context);
-                                               return;
-                               }
-
-        TI_DbgPrint(MID_TRACE, ("--> Our IP address on this interface: '%s'\n", A2S(Address)));
-                       }
-
-    /* Create a net table entry for this interface */
-    if (!IPCreateNTE(IF, Address, 8)) {
-        TI_DbgPrint(MIN_TRACE, ("IPCreateNTE() failed.\n"));
-        FreeTDPackets(Adapter);
-        IPDestroyInterface(IF);
-        return;
+    /*
+     * 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).
+     */
+
+    GetName( RegistryPath, &IF->Name );
+
+    Status = OpenRegistryKey( RegistryPath, &RegHandle );
+
+    if(NT_SUCCESS(Status)) {
+       Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
+        TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
+                    &IF->Description));
     }
 
-    /* Reference the interface for the NTE. The reference
-       for the address is just passed on to the NTE */
-    ReferenceObject(IF);
+    DefaultMask.Type = IP_ADDRESS_V4;
+
+    IF->Unicast = DefaultMask;
+    IF->Netmask = DefaultMask;
+
+    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,
+                          NdisRequestQueryInformation,
+                          OID_GEN_LINK_SPEED,
+                          &IF->Speed,
+                          sizeof(UINT));
+
+    if( !NT_SUCCESS(NdisStatus) )
+       IF->Speed = IP_DEFAULT_LINK_SPEED;
 
     /* Register interface with IP layer */
     IPRegisterInterface(IF);
@@ -762,15 +1006,14 @@ VOID BindAdapter(
                           OID_GEN_CURRENT_PACKET_FILTER,
                           &Adapter->PacketFilter,
                           sizeof(UINT));
+
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
-        FreeTDPackets(Adapter);
+        TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
         IPDestroyInterface(IF);
         return;
     }
 
     Adapter->Context = IF;
-
     Adapter->State = LAN_STATE_STARTED;
 }
 
@@ -791,16 +1034,13 @@ VOID UnbindAdapter(
         IPUnregisterInterface(IF);
 
         IPDestroyInterface(IF);
-
-        /* Free transfer data packets */
-        FreeTDPackets(Adapter);
     }
 }
 
 
 NDIS_STATUS LANRegisterAdapter(
     PNDIS_STRING AdapterName,
-               PNDIS_STRING RegistryPath)
+    PNDIS_STRING RegistryPath)
 /*
  * FUNCTION: Registers protocol with an NDIS adapter
  * ARGUMENTS:
@@ -813,7 +1053,6 @@ NDIS_STATUS LANRegisterAdapter(
     PLAN_ADAPTER IF;
     NDIS_STATUS NdisStatus;
     NDIS_STATUS OpenStatus;
-               PNDIS_CONFIGURATION_PARAMETER Parameter;
     UINT MediaIndex;
     NDIS_MEDIUM MediaArray[MAX_MEDIA];
     UINT AddressOID;
@@ -821,7 +1060,7 @@ NDIS_STATUS LANRegisterAdapter(
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
 
-    IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
+    IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
     if (!IF) {
         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
         return NDIS_STATUS_RESOURCES;
@@ -858,7 +1097,7 @@ NDIS_STATUS LANRegisterAdapter(
     if (NdisStatus == NDIS_STATUS_PENDING)
         KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
     else if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        ExFreePool(IF);
+       exFreePool(IF);
         return NdisStatus;
     }
 
@@ -874,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;
@@ -883,7 +1122,7 @@ NDIS_STATUS LANRegisterAdapter(
     default:
         /* Unsupported media */
         TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
-        ExFreePool(IF);
+        exFreePool(IF);
         return NDIS_STATUS_NOT_SUPPORTED;
     }
 
@@ -894,7 +1133,7 @@ NDIS_STATUS LANRegisterAdapter(
                           &IF->MTU,
                           sizeof(UINT));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        ExFreePool(IF);
+        exFreePool(IF);
         return NdisStatus;
     }
 
@@ -906,7 +1145,7 @@ NDIS_STATUS LANRegisterAdapter(
                           sizeof(UINT));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
-        ExFreePool(IF);
+        exFreePool(IF);
         return NdisStatus;
     }
 
@@ -929,7 +1168,7 @@ NDIS_STATUS LANRegisterAdapter(
                           IF->HWAddressLength);
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
-        ExFreePool(IF);
+        exFreePool(IF);
         return NdisStatus;
     }
 
@@ -941,7 +1180,7 @@ NDIS_STATUS LANRegisterAdapter(
                           sizeof(UINT));
     if (NdisStatus != NDIS_STATUS_SUCCESS) {
         TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
-        ExFreePool(IF);
+        exFreePool(IF);
         return NdisStatus;
     }
 
@@ -984,23 +1223,23 @@ NDIS_STATUS LANUnregisterAdapter(
     /* Unbind adapter from IP layer */
     UnbindAdapter(Adapter);
 
-    KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
+    TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
     NdisHandle = Adapter->NdisHandle;
     if (NdisHandle) {
         Adapter->NdisHandle = NULL;
-        KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+        TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
 
         NdisCloseAdapter(&NdisStatus, NdisHandle);
         if (NdisStatus == NDIS_STATUS_PENDING) {
-            KeWaitForSingleObject(&Adapter->Event,
-                                  UserRequest,
-                                  KernelMode,
-                                  FALSE,
-                                  NULL);
+            TcpipWaitForSingleObject(&Adapter->Event,
+                                     UserRequest,
+                                     KernelMode,
+                                     FALSE,
+                                     NULL);
             NdisStatus = Adapter->NdisStatus;
         }
     } else
-        KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+        TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
 
     FreeAdapter(Adapter);
 
@@ -1037,24 +1276,24 @@ NTSTATUS LANRegisterProtocol(
     ProtChars.CloseAdapterCompleteHandler    = ProtocolCloseAdapterComplete;
     ProtChars.ResetCompleteHandler           = ProtocolResetComplete;
     ProtChars.RequestCompleteHandler         = ProtocolRequestComplete;
-    ProtChars.u2.SendCompleteHandler         = ProtocolSendComplete;
-    ProtChars.u3.TransferDataCompleteHandler = ProtocolTransferDataComplete;
-    ProtChars.u4.ReceiveHandler              = ProtocolReceive;
+    ProtChars.SendCompleteHandler            = ProtocolSendComplete;
+    ProtChars.TransferDataCompleteHandler    = ProtocolTransferDataComplete;
+    ProtChars.ReceiveHandler                 = ProtocolReceive;
     ProtChars.ReceiveCompleteHandler         = ProtocolReceiveComplete;
     ProtChars.StatusHandler                  = ProtocolStatus;
     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;
 
@@ -1078,23 +1317,43 @@ VOID LANUnregisterProtocol(
         PLAN_ADAPTER Current;
         KIRQL OldIrql;
 
-        KeAcquireSpinLock(&AdapterListLock, &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);
+            Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
             /* Unregister it */
             LANUnregisterAdapter(Current);
             CurrentEntry = NextEntry;
         }
 
-        KeReleaseSpinLock(&AdapterListLock, OldIrql);
+        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 */