lan.sys is a simple driver providing access to ndis. This stuff is
authorArt Yerkes <art.yerkes@gmail.com>
Fri, 17 Sep 2004 15:50:16 +0000 (15:50 +0000)
committerArt Yerkes <art.yerkes@gmail.com>
Fri, 17 Sep 2004 15:50:16 +0000 (15:50 +0000)
ripped from tcpip.sys in preparation for a big breakup.

svn path=/trunk/; revision=10884

reactos/drivers/net/lan/include/debug.h [new file with mode: 0644]
reactos/drivers/net/lan/include/lan.h [new file with mode: 0644]
reactos/drivers/net/lan/include/memtrack.h [new file with mode: 0644]
reactos/drivers/net/lan/include/precomp.h [new file with mode: 0644]
reactos/drivers/net/lan/lan.rc [new file with mode: 0644]
reactos/drivers/net/lan/lan/lan.c [new file with mode: 0644]
reactos/drivers/net/lan/lan/routines.c [new file with mode: 0644]
reactos/drivers/net/lan/makefile [new file with mode: 0644]

diff --git a/reactos/drivers/net/lan/include/debug.h b/reactos/drivers/net/lan/include/debug.h
new file mode 100644 (file)
index 0000000..4b296b8
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/debug.h
+ * PURPOSE:     Debugging support macros
+ * DEFINES:     DBG     - Enable debug output
+ *              NASSERT - Disable assertions
+ */
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#define NORMAL_MASK    0x000000FF
+#define SPECIAL_MASK   0xFFFFFF00
+#define MIN_TRACE      0x00000001
+#define MID_TRACE      0x00000002
+#define MAX_TRACE      0x00000003
+
+#define DEBUG_CHECK    0x00000100
+#define DEBUG_MEMORY   0x00000200
+#define DEBUG_PBUFFER  0x00000400
+#define DEBUG_IRP      0x00000800
+#define DEBUG_REFCOUNT 0x00001000
+#define DEBUG_ADDRFILE 0x00002000
+#define DEBUG_DATALINK 0x00004000
+#define DEBUG_ARP      0x00008000
+#define DEBUG_IP       0x00010000
+#define DEBUG_UDP      0x00020000
+#define DEBUG_TCP      0x00040000
+#define DEBUG_ICMP     0x00080000
+#define DEBUG_ROUTER   0x00100000
+#define DEBUG_RCACHE   0x00200000
+#define DEBUG_NCACHE   0x00400000
+#define DEBUG_CPOINT   0x00800000
+#define DEBUG_ULTRA    0xFFFFFFFF
+
+#ifdef DBG
+
+extern DWORD DebugTraceLevel;
+
+#ifdef _MSC_VER
+
+#define LA_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d) ", __FILE__, __LINE__); \
+        DbgPrint _x_ ; \
+    }
+
+#else /* _MSC_VER */
+
+#define LA_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
+        DbgPrint _x_ ; \
+    }
+
+#endif /* _MSC_VER */
+
+#if 0
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef NASSERT
+#define ASSERT(x)
+#else /* NASSERT */
+#define ASSERT(x) if (!(x)) { LA_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); }
+#endif /* NASSERT */
+#endif
+
+#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x))
+
+#else /* DBG */
+
+#define LA_DbgPrint(_t_, _x_)
+
+#if 0
+#define ASSERT_IRQL(x)
+#define ASSERT(x)
+#endif
+
+#endif /* DBG */
+
+
+#define assert(x) ASSERT(x)
+#define assert_irql(x) ASSERT_IRQL(x)
+
+
+#ifdef _MSC_VER
+
+#define UNIMPLEMENTED \
+    LA_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \
+        but come back another day.\n", __FILE__, __LINE__));
+
+#else /* _MSC_VER */
+
+#define UNIMPLEMENTED \
+    LA_DbgPrint(MIN_TRACE, ("(%s:%d)(%s) is unimplemented, \
+        but come back another day.\n", __FILE__, __LINE__, __FUNCTION__));
+
+#endif /* _MSC_VER */
+
+
+#define CHECKPOINT \
+    do { LA_DbgPrint(DEBUG_CHECK, ("(%s:%d)\n", __FILE__, __LINE__)); } while(0);
+
+#define CP CHECKPOINT
+
+#include <memtrack.h>
+
+#endif /* __DEBUG_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/lan/include/lan.h b/reactos/drivers/net/lan/include/lan.h
new file mode 100644 (file)
index 0000000..431441f
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/lan.h
+ * PURPOSE:     LAN adapter definitions
+ */
+#ifndef __LAN_H
+#define __LAN_H
+
+/* NDIS version this driver supports */
+#define NDIS_VERSION_MAJOR 4
+#define NDIS_VERSION_MINOR 0
+
+/* Macros */
+
+#define MIN(value1, value2) \
+    ((value1 < value2)? value1 : value2)
+
+#define MAX(value1, value2) \
+    ((value1 > value2)? value1 : value2)
+
+#define NDIS_BUFFER_TAG FOURCC('n','b','u','f')
+#define NDIS_PACKET_TAG FOURCC('n','p','k','t')
+
+/* Media we support */
+#define MEDIA_ETH 0
+
+#define MAX_MEDIA 1
+
+#define IEEE_802_ADDR_LENGTH 6
+
+/* Ethernet header layout */
+typedef struct ETH_HEADER {
+    UCHAR DstAddr[IEEE_802_ADDR_LENGTH]; /* Destination MAC address */
+    UCHAR SrcAddr[IEEE_802_ADDR_LENGTH]; /* Source MAC address */
+    USHORT EType;                        /* Ethernet protocol type */
+} ETH_HEADER, *PETH_HEADER;
+
+#define MAX_MEDIA_ETH sizeof(ETH_HEADER)
+
+/* Broadcast masks */
+#define BCAST_ETH_MASK 0x01
+
+/* Broadcast values to check against */
+#define BCAST_ETH_CHECK 0x01
+
+/* Offset of broadcast address */
+#define BCAST_ETH_OFFSET 0x00
+
+typedef struct _LAN_ADDRESS_C {
+    LIST_ENTRY  ListEntry;
+    LAN_ADDRESS ClientPart;
+} LAN_ADDRESS_C, *PLAN_ADDRESS_C;
+
+/* Per adapter information */
+typedef struct LAN_ADAPTER {
+    LIST_ENTRY ListEntry;                   /* Entry on list */
+    LIST_ENTRY AddressList;                 /* Addresses associated */
+    LIST_ENTRY ForeignList;                 /* List of known addresses */
+    KSPIN_LOCK Lock;                        /* Lock for this structure */
+    UINT Index;                             /* Adapter Index */
+    UCHAR State;                            /* State of the adapter */
+    KEVENT Event;                           /* Opening event */
+    PVOID Context;                          /* Upper layer context information */
+    NDIS_HANDLE NdisHandle;                 /* NDIS binding handle */
+    NDIS_STATUS NdisStatus;                 /* NDIS status of last request */
+    NDIS_MEDIUM Media;                      /* Media type */
+    UCHAR HWAddress[IEEE_802_ADDR_LENGTH];  /* Local HW address */
+    UINT HWAddressLength;                   /* Length of HW address */
+    UCHAR BCastMask;                        /* Mask for checking broadcast */
+    UCHAR BCastCheck;                       /* Value to check against */
+    UCHAR BCastOffset;                      /* Offset in frame to check against */
+    UCHAR HeaderSize;                       /* Size of link-level header */
+    USHORT MTU;                             /* Maximum Transfer Unit */
+    UINT MinFrameSize;                      /* Minimum frame size in bytes */
+    UINT MaxPacketSize;                     /* Maximum packet size when sending */
+    UINT MaxSendPackets;                    /* Maximum number of packets per send */
+    UINT MacOptions;                        /* MAC options for NIC driver/adapter */
+    UINT Speed;                             /* Link speed */
+    UINT PacketFilter;                      /* Packet filter for this adapter */
+    UINT Lookahead;                         /* Lookahead for adapter */
+    UNICODE_STRING RegistryPath;            /* Registry path for later query */
+} LAN_ADAPTER, *PLAN_ADAPTER;
+
+typedef struct _LAN_PACKET {
+    PNDIS_PACKET NdisPacket;
+    PETH_HEADER  EthHeader;
+    UINT         TotalSize;
+} LAN_PACKET, *PLAN_PACKET;
+
+typedef struct _LAN_PROTOCOL {
+    LIST_ENTRY   ListEntry;
+    LIST_ENTRY   ReadIrpListHead;
+    UINT         Id;
+    UINT         LastServicePass;
+    UINT         Buffered;
+    UINT         NumEtherTypes;
+    USHORT       EtherType[1];
+} LAN_PROTOCOL, *PLAN_PROTOCOL;
+
+typedef struct _LAN_DEVICE_EXT {
+    NDIS_HANDLE NdisProtocolHandle;
+    KSPIN_LOCK  Lock;
+    LIST_ENTRY  AdapterListHead;
+    LIST_ENTRY  ProtocolListHead;
+    UINT        AdapterId;
+    UINT        ProtoId;
+} LAN_DEVICE_EXT, *PLAN_DEVICE_EXT;
+
+/* LAN adapter state constants */
+#define LAN_STATE_OPENING   0
+#define LAN_STATE_RESETTING 1
+#define LAN_STATE_STARTED   2
+#define LAN_STATE_STOPPED   3
+
+/* Size of out lookahead buffer */
+#define LOOKAHEAD_SIZE  128
+
+/* Ethernet types. We swap constants so we can compare values at runtime
+   without swapping them there */
+#define ETYPE_IPv4 WH2N(0x0800)
+#define ETYPE_IPv6 WH2N(0x86DD)
+#define ETYPE_ARP  WH2N(0x0806)
+
+/* Protocols */
+#define LAN_PROTO_IPv4 0x0000 /* Internet Protocol version 4 */
+#define LAN_PROTO_IPv6 0x0001 /* Internet Protocol version 6 */
+#define LAN_PROTO_ARP  0x0002 /* Address Resolution Protocol */
+
+
+NDIS_STATUS LANRegisterAdapter(
+    PNDIS_STRING AdapterName,
+               PNDIS_STRING RegistryPath);
+
+NDIS_STATUS LANUnregisterAdapter(PLAN_ADAPTER Adapter);
+
+NTSTATUS LANRegisterProtocol(PNDIS_STRING Name);
+
+VOID LANUnregisterProtocol(VOID);
+
+NDIS_STATUS NDISCall(
+    PLAN_ADAPTER Adapter,
+    NDIS_REQUEST_TYPE Type,
+    NDIS_OID OID,
+    PVOID Buffer,
+    UINT Length);
+
+void GetDataPtr( PNDIS_PACKET Packet,
+                UINT Offset,
+                PCHAR *DataOut,
+                PUINT Size );
+
+NDIS_STATUS AllocatePacketWithBufferX( PNDIS_PACKET *NdisPacket,
+                                      PCHAR Data, UINT Len,
+                                      PCHAR File, UINT Line );
+
+VOID FreeNdisPacketX( PNDIS_PACKET Packet, PCHAR File, UINT Line );
+
+NDIS_STATUS InitNdisPools();
+VOID CloseNdisPools();
+
+PLAN_ADAPTER FindAdapterByIndex( PLAN_DEVICE_EXT DeviceExt, UINT Index );
+
+#endif /* __LAN_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/lan/include/memtrack.h b/reactos/drivers/net/lan/include/memtrack.h
new file mode 100644 (file)
index 0000000..62f45cc
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef MEMTRACK_H
+#define MEMTRACK_H
+
+#ifndef FOURCC
+#define FOURCC(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))
+#endif
+
+#define AllocatePacketWithBuffer(x,y,z) AllocatePacketWithBufferX(x,y,z,__FILE__,__LINE__)
+#define FreeNdisPacket(x) FreeNdisPacketX(x,__FILE__,__LINE__)
+
+#define MTMARK()
+#define Track(x,y)
+#define TrackingInit()
+#define TrackDump()
+#define Untrack(x)
+#define TrackTag(x)
+#define exAllocatePoolWithTag(x,y,z) ExAllocatePoolWithTag(x,y,z)
+#define exAllocatePool(x,y) ExAllocatePool(x,y)
+#define exFreePool(x) ExFreePool(x)
+#define TrackWithTag(w,x,y,z)
+#define UntrackFL(x,y,z)
+
+#endif/*MEMMTRAC_H*/
diff --git a/reactos/drivers/net/lan/include/precomp.h b/reactos/drivers/net/lan/include/precomp.h
new file mode 100644 (file)
index 0000000..14d92b9
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _LAN_PRECOMP_H
+#define _LAN_PRECOMP_H
+
+#include <limits.h>
+#include <ddk/ntddk.h>
+#include <ddk/ndis.h>
+#include <rosrtl/string.h>
+#include <roscfg.h>
+#include <debug.h>
+#include <pseh.h>
+#include "net/lan.h"
+#include "lan.h"
+#include "arp.h"
+
+#endif/*_LAN_PRECOMP_H*/
diff --git a/reactos/drivers/net/lan/lan.rc b/reactos/drivers/net/lan/lan.rc
new file mode 100644 (file)
index 0000000..6f31df8
--- /dev/null
@@ -0,0 +1,38 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",         RES_STR_COMPANY_NAME
+            VALUE "FileDescription",  "TCP/IP protocol driver\0"
+            VALUE "FileVersion",         "0.0.0\0"
+            VALUE "InternalName",        "tcpip\0"
+            VALUE "LegalCopyright",      RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalFilename", "tcpip.sys\0"
+            VALUE "ProductName",         RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",      RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
diff --git a/reactos/drivers/net/lan/lan/lan.c b/reactos/drivers/net/lan/lan/lan.c
new file mode 100644 (file)
index 0000000..905dadb
--- /dev/null
@@ -0,0 +1,1342 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        datalink/lan.c
+ * PURPOSE:     Local Area Network media routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ *   arty -- Separate service 09/2004
+ */
+
+#include "precomp.h"
+
+ULONG DebugTraceLevel = 0x7ffffff;
+PDEVICE_OBJECT LanDeviceObject  = NULL;
+
+NDIS_STATUS NDISCall(
+    PLAN_ADAPTER Adapter,
+    NDIS_REQUEST_TYPE Type,
+    NDIS_OID OID,
+    PVOID Buffer,
+    UINT Length)
+/*
+ * FUNCTION: Send a request to NDIS
+ * ARGUMENTS:
+ *     Adapter     = Pointer to a LAN_ADAPTER structure
+ *     Type        = Type of request (Set or Query)
+ *     OID         = Value to be set/queried for
+ *     Buffer      = Pointer to a buffer to use
+ *     Length      = Number of bytes in Buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_REQUEST Request;
+    NDIS_STATUS NdisStatus;
+
+    Request.RequestType = Type;
+    if (Type == NdisRequestSetInformation) {
+        Request.DATA.SET_INFORMATION.Oid                     = OID;
+        Request.DATA.SET_INFORMATION.InformationBuffer       = Buffer;
+        Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
+    } else {
+        Request.DATA.QUERY_INFORMATION.Oid                     = OID;
+        Request.DATA.QUERY_INFORMATION.InformationBuffer       = Buffer;
+        Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
+    }
+
+    if (Adapter->State != LAN_STATE_RESETTING) {
+        NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
+    } else {
+        NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
+    }
+
+    /* Wait for NDIS to complete the request */
+    if (NdisStatus == NDIS_STATUS_PENDING) {
+        KeWaitForSingleObject(&Adapter->Event,
+                              UserRequest,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+        NdisStatus = Adapter->NdisStatus;
+    }
+
+    return NdisStatus;
+}
+
+
+VOID FreeAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure to free
+ */
+{
+    exFreePool(Adapter);
+}
+
+
+VOID STDCALL ProtocolOpenAdapterComplete(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS Status,
+    NDIS_STATUS OpenErrorStatus)
+/*
+ * FUNCTION: Called by NDIS to complete opening of an adapter
+ * ARGUMENTS:
+ *     BindingContext  = Pointer to a device context (LAN_ADAPTER)
+ *     Status          = Status of the operation
+ *     OpenErrorStatus = Additional status information
+ */
+{
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID STDCALL ProtocolCloseAdapterComplete(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete closing an adapter
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     Status         = Status of the operation
+ */
+{
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    Adapter->NdisStatus = Status;
+
+    KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID STDCALL ProtocolResetComplete(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete resetting an adapter
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     Status         = Status of the operation
+ */
+{
+    LA_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID STDCALL ProtocolRequestComplete(
+    NDIS_HANDLE BindingContext,
+    PNDIS_REQUEST NdisRequest,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete a request
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     NdisRequest    = Pointer to an object describing the request
+ *     Status         = Status of the operation
+ */
+{
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    /* Save status of request and signal an event */
+    Adapter->NdisStatus = Status;
+
+    KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID STDCALL ProtocolSendComplete(
+    NDIS_HANDLE BindingContext,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete sending process
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     Packet         = Pointer to a packet descriptor
+ *     Status         = Status of the operation
+ */
+{
+    /*PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;*/
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+    /*(*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);*/
+    LA_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
+}
+
+
+VOID STDCALL ProtocolTransferDataComplete(
+    NDIS_HANDLE BindingContext,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS Status,
+    UINT BytesTransferred)
+/*
+ * FUNCTION: Called by NDIS to complete reception of data
+ * ARGUMENTS:
+ *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
+ *     Packet           = Pointer to a packet descriptor
+ *     Status           = Status of the operation
+ *     BytesTransferred = Number of bytes transferred
+ * NOTES:
+ *     If the packet was successfully received, determine the protocol
+ *     type and pass it to the correct receive handler
+ */
+{
+    PLIST_ENTRY ListEntry, ReadListEntry;
+    PLAN_PROTOCOL Proto;
+    PLAN_PACKET_HEADER Header;
+    PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
+    UINT i;
+    UINT PacketType;
+    UINT ContigSize;
+    PIRP ReadIrp;
+    KIRQL OldIrql;
+    LAN_PACKET LPPacket;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+    
+    if (Status == NDIS_STATUS_SUCCESS) {
+        PNDIS_BUFFER NdisBuffer;
+
+        NdisGetFirstBufferFromPacket(Packet,
+                                     &NdisBuffer,
+                                     &LPPacket.EthHeader,
+                                     &ContigSize,
+                                     &LPPacket.TotalSize);
+       
+       LPPacket.TotalSize = BytesTransferred;
+       
+        /* Determine which upper layer protocol that should receive
+           this packet and pass it to the correct receive handler */
+
+        /*OskitDumpBuffer( IPPacket.Header, BytesTransferred );*/
+
+        PacketType = LPPacket.EthHeader->EType;
+
+       LA_DbgPrint
+           (DEBUG_DATALINK,
+            ("Ether Type = %x Total = %d Packet %x Payload %x\n",
+             PacketType, LPPacket.TotalSize, LPPacket.EthHeader,
+             LPPacket.EthHeader + 1));
+       
+       NdisBuffer->Next = NULL;
+
+       for( ListEntry = DeviceExt->ProtocolListHead.Flink;
+            ListEntry != &DeviceExt->ProtocolListHead;
+            ListEntry = ListEntry->Flink ) {
+           Proto = CONTAINING_RECORD(ListEntry, LAN_PROTOCOL, ListEntry);
+           LA_DbgPrint(MID_TRACE,("Examining protocol %x\n", Proto));
+           for( i = 0; i < Proto->NumEtherTypes; i++ ) {
+               LA_DbgPrint(MID_TRACE,(".Accepts proto %x\n", 
+                                      Proto->EtherType[i]));
+               if( Proto->EtherType[i] == PacketType &&
+                   !IsListEmpty( &Proto->ReadIrpListHead ) ) {
+                   ReadListEntry = RemoveHeadList( &Proto->ReadIrpListHead );
+                   ReadIrp = CONTAINING_RECORD(ReadListEntry, IRP,
+                                               Tail.Overlay.ListEntry );
+                   LA_DbgPrint(MID_TRACE,("..Irp %x\n", ReadIrp));
+                   _SEH_TRY {
+                       Header = ReadIrp->AssociatedIrp.SystemBuffer;
+                       LA_DbgPrint
+                           (MID_TRACE,
+                            ("Writing packet at %x\n", Header));
+                       Header->Fixed.Adapter = Adapter->Index;
+                       Header->Fixed.AddressType = Adapter->Media;
+                       Header->Fixed.AddressLen = IEEE_802_ADDR_LENGTH;
+                       Header->Fixed.PacketType = PacketType;
+                       RtlCopyMemory( Header->Address,
+                                      LPPacket.EthHeader->SrcAddr,
+                                      IEEE_802_ADDR_LENGTH );
+                       if( Proto->Buffered ) {
+                           LA_DbgPrint(MID_TRACE,("Buffered copy\n"));
+                           RtlCopyMemory
+                               ( Header->Address + 
+                                 IEEE_802_ADDR_LENGTH,
+                                 LPPacket.EthHeader + 1,
+                                 LPPacket.TotalSize - 
+                                 sizeof(*LPPacket.EthHeader) );
+                           Header->Fixed.Mdl = NULL;
+                       } else 
+                           Header->Fixed.Mdl = NdisBuffer;
+                       
+                       ReadIrp->IoStatus.Status = 0;
+                       ReadIrp->IoStatus.Information = 
+                           (Header->Address + IEEE_802_ADDR_LENGTH + 
+                            LPPacket.TotalSize - 
+                            sizeof(*LPPacket.EthHeader)) -
+                           (PCHAR)Header;
+
+                       LA_DbgPrint(MID_TRACE,("Bytes returned %d\n",
+                                              ReadIrp->IoStatus.Information));
+
+                       IoCompleteRequest( ReadIrp, IO_NETWORK_INCREMENT );
+                   } _SEH_HANDLE {
+                       LA_DbgPrint
+                           (MIN_TRACE,
+                            ("Failed write to packet in client\n"));
+                       ReadIrp->IoStatus.Status = STATUS_ACCESS_VIOLATION;
+                       ReadIrp->IoStatus.Information = 0;
+                       IoCompleteRequest( ReadIrp, IO_NETWORK_INCREMENT );
+                   } _SEH_END;
+                   break;
+               }
+           }
+       }
+    }
+    
+    KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+    
+    FreeNdisPacket( Packet );
+}
+
+
+NDIS_STATUS STDCALL ProtocolReceive(
+    NDIS_HANDLE BindingContext,
+    NDIS_HANDLE MacReceiveContext,
+    PVOID HeaderBuffer,
+    UINT HeaderBufferSize,
+    PVOID LookaheadBuffer,
+    UINT LookaheadBufferSize,
+    UINT PacketSize)
+/*
+ * FUNCTION: Called by NDIS when a packet has been received on the physical link
+ * ARGUMENTS:
+ *     BindingContext      = Pointer to a device context (LAN_ADAPTER)
+ *     MacReceiveContext   = Handle used by underlying NIC driver
+ *     HeaderBuffer        = Pointer to a buffer containing the packet header
+ *     HeaderBufferSize    = Number of bytes in HeaderBuffer
+ *     LookaheadBuffer     = Pointer to a buffer containing buffered packet data
+ *     LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
+ *     PacketSize          = Overall size of the packet (not including header)
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    USHORT EType;
+    UINT PacketType, BytesTransferred;
+    PCHAR BufferData;
+    NDIS_STATUS NdisStatus;
+    PNDIS_PACKET NdisPacket;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
+
+    if (Adapter->State != LAN_STATE_STARTED) {
+        LA_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
+        return NDIS_STATUS_NOT_ACCEPTED;
+    }
+
+    if (HeaderBufferSize < Adapter->HeaderSize) {
+        LA_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
+        return NDIS_STATUS_NOT_ACCEPTED;
+    }
+
+    PacketType = EType;
+
+    /* Get a transfer data packet */
+    KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+    NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Adapter->MTU );
+    if( NdisStatus != NDIS_STATUS_SUCCESS ) return NDIS_STATUS_NOT_ACCEPTED;
+    LA_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
+    {
+       UINT temp;
+       temp = PacketSize;
+       GetDataPtr( NdisPacket, 0, &BufferData, &temp );
+    }
+
+    LA_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d HeaderBufferSize %d packsize %d\n",LookaheadBufferSize,HeaderBufferSize,PacketSize));
+    /* Get the data */
+    NdisTransferData(&NdisStatus,
+                    Adapter->NdisHandle,
+                    MacReceiveContext,
+                    0,
+                    PacketSize + HeaderBufferSize,
+                    NdisPacket,
+                    &BytesTransferred);
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
+
+    if (NdisStatus != NDIS_STATUS_PENDING)
+       ProtocolTransferDataComplete(BindingContext,
+                                    NdisPacket,
+                                    NdisStatus,
+                                    PacketSize + HeaderBufferSize);
+
+    /* Release the packet descriptor */
+    KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+    LA_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID STDCALL ProtocolReceiveComplete(
+    NDIS_HANDLE BindingContext)
+/*
+ * FUNCTION: Called by NDIS when we're done receiving data
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+}
+
+
+VOID STDCALL ProtocolStatus(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS GenerelStatus,
+    PVOID StatusBuffer,
+    UINT StatusBufferSize)
+/*
+ * FUNCTION: Called by NDIS when the underlying driver has changed state
+ * ARGUMENTS:
+ *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
+ *     GenerelStatus    = A generel status code
+ *     StatusBuffer     = Pointer to a buffer with medium-specific data
+ *     StatusBufferSize = Number of bytes in StatusBuffer
+ */
+{
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+}
+
+
+VOID STDCALL ProtocolStatusComplete(
+    NDIS_HANDLE NdisBindingContext)
+/*
+ * FUNCTION: Called by NDIS when a status-change has occurred
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+}
+
+VOID STDCALL ProtocolBindAdapter(
+    OUT PNDIS_STATUS   Status,
+    IN  NDIS_HANDLE    BindContext,
+    IN  PNDIS_STRING   DeviceName,
+    IN  PVOID          SystemSpecific1,
+    IN  PVOID          SystemSpecific2)
+/*
+ * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
+ *           bindings, and periodically thereafer as new adapters come online
+ * ARGUMENTS:
+ *     Status: Return value to NDIS
+ *     BindContext: Handle provided by NDIS to track pending binding operations
+ *     DeviceName: Name of the miniport device to bind to
+ *     SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
+ *     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 */
+    LA_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ\n", SystemSpecific1));
+    *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
+}
+
+
+VOID LANTransmit(
+    PLAN_ADAPTER Adapter,
+    PNDIS_PACKET NdisPacket,
+    PVOID LinkAddress,
+    USHORT Type)
+/*
+ * FUNCTION: Transmits a packet
+ * ARGUMENTS:
+ *     Context     = Pointer to context information (LAN_ADAPTER)
+ *     NdisPacket  = Pointer to NDIS packet to send
+ *     LinkAddress = Pointer to link address of destination (NULL = broadcast)
+ *     Type        = LAN protocol type (LAN_PROTO_*)
+ */
+{
+    NDIS_STATUS NdisStatus;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    if (Adapter->State == LAN_STATE_STARTED) {
+        NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
+        if (NdisStatus != NDIS_STATUS_PENDING)
+            ProtocolSendComplete((NDIS_HANDLE)Adapter, NdisPacket, NdisStatus);
+    } else {
+        ProtocolSendComplete((NDIS_HANDLE)Adapter, NdisPacket, NDIS_STATUS_CLOSED);
+    }
+}
+
+/* For use internally */
+UINT LANTransmitInternal(PLAN_PACKET_HEADER ToWrite, UINT OverallLength) {
+    NDIS_STATUS NdisStatus;
+    PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
+    PLAN_ADAPTER Adapter;
+    PETH_HEADER EthHeader;
+    KIRQL OldIrql;
+    PNDIS_PACKET NdisPacket;
+    UINT Size, PayloadSize = OverallLength -
+       ((ToWrite->Address + ToWrite->Fixed.AddressLen) - (PCHAR)ToWrite);
+
+    NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, 
+                                          PayloadSize + sizeof(ETH_HEADER) );
+    
+    KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+
+    if( !NT_SUCCESS(NdisStatus) ) goto end;
+
+    Adapter = FindAdapterByIndex( DeviceExt, ToWrite->Fixed.Adapter );
+
+    if( !Adapter ) goto end;
+
+    GetDataPtr( NdisPacket, 0, (PCHAR *)&EthHeader, &Size );
+    if( !EthHeader ) goto end;
+
+    LA_DbgPrint(MID_TRACE,("Writing %d bytes of Dst\n", 
+                          ToWrite->Fixed.AddressLen));
+
+    /* Handle broadcast for other media types here */
+    if( ToWrite->Fixed.AddressLen )
+       RtlCopyMemory( EthHeader->DstAddr, 
+                      ToWrite->Address, 
+                      ToWrite->Fixed.AddressLen );
+    else
+       memset( EthHeader->DstAddr, -1, sizeof(EthHeader->DstAddr) );
+
+    LA_DbgPrint(MID_TRACE,("Writing %d bytes of Src\n", Adapter->HWAddressLength));
+    RtlCopyMemory( EthHeader->SrcAddr, 
+                  Adapter->HWAddress,
+                  Adapter->HWAddressLength );
+    LA_DbgPrint(MID_TRACE,("Writing %d bytes of payload\n", PayloadSize));
+    EthHeader->EType = ToWrite->Fixed.PacketType;
+    RtlCopyMemory( EthHeader + 1, 
+                  ToWrite->Address + ToWrite->Fixed.AddressLen,
+                  PayloadSize );
+
+    LANTransmit( Adapter, NdisPacket, ToWrite->Address, 
+                ToWrite->Fixed.PacketType );
+
+end:
+    KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );    
+
+    return OverallLength;
+}
+
+VOID BindAdapter(PLAN_ADAPTER Adapter, PNDIS_STRING RegistryPath)
+/*
+ * FUNCTION: Binds a LAN adapter to IP layer
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure
+ * NOTES:
+ *    We set the lookahead buffer size, set the packet filter and
+ *    bind the adapter to IP layer
+ */
+{
+    /*NDIS_STATUS NdisStatus;*/
+    /*ULONG Lookahead = LOOKAHEAD_SIZE;*/
+    /*NTSTATUS Status;*/
+    /*HANDLE RegHandle = 0;*/
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+}
+
+NDIS_STATUS LANRegisterAdapter( PNDIS_STRING AdapterName,
+                               PNDIS_STRING RegistryPath)
+/*
+ * FUNCTION: Registers protocol with an NDIS adapter
+ * ARGUMENTS:
+ *     AdapterName = Pointer to string with name of adapter to register
+ *     Adapter     = Address of pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PLAN_ADAPTER Adapter;
+    NDIS_MEDIUM MediaArray[MAX_MEDIA];
+    NDIS_STATUS NdisStatus;
+    NDIS_STATUS OpenStatus;
+    UINT MediaIndex;
+    UINT AddressOID;
+    UINT Speed;
+    PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    Adapter = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
+    if (!Adapter) {
+        LA_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NDIS_STATUS_RESOURCES;
+    }
+
+    RtlZeroMemory(Adapter, sizeof(LAN_ADAPTER));
+
+    /* Put adapter in stopped state */
+    Adapter->State = LAN_STATE_STOPPED;
+    Adapter->Index = DeviceExt->AdapterId++;
+
+    InitializeListHead( &Adapter->AddressList );
+    InitializeListHead( &Adapter->ForeignList );
+
+    /* Initialize protecting spin lock */
+    KeInitializeSpinLock(&Adapter->Lock);
+
+    KeInitializeEvent(&Adapter->Event, SynchronizationEvent, FALSE);
+
+    /* Initialize array with media IDs we support */
+    MediaArray[MEDIA_ETH] = NdisMedium802_3;
+
+    LA_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
+    /* Open the adapter. */
+    NdisOpenAdapter(&NdisStatus,
+                    &OpenStatus,
+                    &Adapter->NdisHandle,
+                    &MediaIndex,
+                    MediaArray,
+                    MAX_MEDIA,
+                    DeviceExt->NdisProtocolHandle,
+                    Adapter,
+                    AdapterName,
+                    0,
+                    NULL);
+
+    /* Wait until the adapter is opened */
+    if (NdisStatus == NDIS_STATUS_PENDING)
+        KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL);
+    else if (NdisStatus != NDIS_STATUS_SUCCESS) {
+       exFreePool(Adapter);
+        return NdisStatus;
+    }
+
+    Adapter->Media = MediaArray[MediaIndex];
+
+    /* Fill LAN_ADAPTER structure with some adapter specific information */
+    switch (Adapter->Media) {
+    case NdisMedium802_3:
+        Adapter->HWAddressLength = IEEE_802_ADDR_LENGTH;
+        Adapter->BCastMask       = BCAST_ETH_MASK;
+        Adapter->BCastCheck      = BCAST_ETH_CHECK;
+        Adapter->BCastOffset     = BCAST_ETH_OFFSET;
+        Adapter->HeaderSize      = sizeof(ETH_HEADER);
+        Adapter->MinFrameSize    = 60;
+        AddressOID          = OID_802_3_CURRENT_ADDRESS;
+        Adapter->PacketFilter    = 
+            NDIS_PACKET_TYPE_BROADCAST |
+            NDIS_PACKET_TYPE_DIRECTED  |
+            NDIS_PACKET_TYPE_MULTICAST;
+        break;
+
+    default:
+        /* Unsupported media */
+        LA_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
+        exFreePool(Adapter);
+        return NDIS_STATUS_NOT_SUPPORTED;
+    }
+
+    /* Get maximum frame size */
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestQueryInformation,
+                          OID_GEN_MAXIMUM_FRAME_SIZE,
+                          &Adapter->MTU,
+                          sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        exFreePool(Adapter);
+        return NdisStatus;
+    }
+
+    /* Get maximum packet size */
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestQueryInformation,
+                          OID_GEN_MAXIMUM_TOTAL_SIZE,
+                          &Adapter->MaxPacketSize,
+                          sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        LA_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
+        exFreePool(Adapter);
+        return NdisStatus;
+    }
+
+    /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestQueryInformation,
+                          OID_GEN_MAXIMUM_SEND_PACKETS,
+                          &Adapter->MaxSendPackets,
+                          sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS)
+        /* Legacy NIC drivers may not support this query, if it fails we
+           assume it can send at least one packet per call to NdisSend(Packets) */
+        Adapter->MaxSendPackets = 1;
+
+    /* Get current hardware address */
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestQueryInformation,
+                          AddressOID,
+                          Adapter->HWAddress,
+                          Adapter->HWAddressLength);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        LA_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
+        exFreePool(Adapter);
+        return NdisStatus;
+    }
+
+    /* Get maximum link speed */
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestQueryInformation,
+                          OID_GEN_LINK_SPEED,
+                          &Speed,
+                          sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        LA_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
+        exFreePool(Adapter);
+        return NdisStatus;
+    }
+
+    /* Convert returned link speed to bps (it is in 100bps increments) */
+    Adapter->Speed = Speed * 100L;
+
+    /* Add adapter to the adapter list */
+    ExInterlockedInsertTailList(&DeviceExt->AdapterListHead,
+                                &Adapter->ListEntry,
+                                &DeviceExt->Lock);
+
+    Adapter->RegistryPath.Buffer = 
+       ExAllocatePool( NonPagedPool, RegistryPath->MaximumLength );
+    if( !Adapter->RegistryPath.Buffer )
+       return NDIS_STATUS_RESOURCES;
+    
+    RtlCopyUnicodeString( &Adapter->RegistryPath,
+                         RegistryPath );
+
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestSetInformation,
+                          OID_GEN_CURRENT_LOOKAHEAD,
+                          &Adapter->Lookahead,
+                          sizeof(ULONG));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        LA_DbgPrint(MID_TRACE, 
+                   ("Could not set lookahead buffer size (0x%X).\n", 
+                    NdisStatus));
+        return NdisStatus;
+    }
+
+    /* Set packet filter so we can send and receive packets */
+    NdisStatus = NDISCall(Adapter,
+                          NdisRequestSetInformation,
+                          OID_GEN_CURRENT_PACKET_FILTER,
+                          &Adapter->PacketFilter,
+                          sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        LA_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", 
+                               NdisStatus));
+        return NdisStatus;
+    }
+
+    Adapter->State = LAN_STATE_STARTED;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS LANUnregisterAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unregisters protocol with NDIS adapter
+ * ARGUMENTS:
+ *     Adapter = Pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    KIRQL OldIrql;
+    NDIS_HANDLE NdisHandle;
+    NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    /* Unlink the adapter from the list */
+    RemoveEntryList(&Adapter->ListEntry);
+
+    KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
+    NdisHandle = Adapter->NdisHandle;
+    if (NdisHandle) {
+        Adapter->NdisHandle = NULL;
+        KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+        NdisCloseAdapter(&NdisStatus, NdisHandle);
+        if (NdisStatus == NDIS_STATUS_PENDING) {
+            KeWaitForSingleObject(&Adapter->Event,
+                                  UserRequest,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
+            NdisStatus = Adapter->NdisStatus;
+        }
+    } else
+        KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+    FreeAdapter(Adapter);
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+NTSTATUS LANRegisterProtocol(PNDIS_STRING Name)
+/*
+ * FUNCTION: Registers this protocol driver with NDIS
+ * ARGUMENTS:
+ *     Name = Name of this protocol driver
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_STATUS NdisStatus;
+    NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
+    PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
+
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    InitializeListHead(&DeviceExt->AdapterListHead);
+    InitializeListHead(&DeviceExt->ProtocolListHead);
+
+    /* Set up protocol characteristics */
+    RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+    ProtChars.MajorNdisVersion               = NDIS_VERSION_MAJOR;
+    ProtChars.MinorNdisVersion               = NDIS_VERSION_MINOR;
+    ProtChars.Name.Length                    = Name->Length;
+    ProtChars.Name.Buffer                    = Name->Buffer;
+    ProtChars.Name.MaximumLength             = Name->MaximumLength;
+    ProtChars.OpenAdapterCompleteHandler     = ProtocolOpenAdapterComplete;
+    ProtChars.CloseAdapterCompleteHandler    = ProtocolCloseAdapterComplete;
+    ProtChars.ResetCompleteHandler           = ProtocolResetComplete;
+    ProtChars.RequestCompleteHandler         = ProtocolRequestComplete;
+    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 */
+    NdisRegisterProtocol(&NdisStatus,
+                         &DeviceExt->NdisProtocolHandle,
+                         &ProtChars,
+                         sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+    if (NdisStatus != NDIS_STATUS_SUCCESS)
+    {
+       LA_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
+        return (NTSTATUS)NdisStatus;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+VOID LANUnregisterProtocol(VOID)
+/*
+ * FUNCTION: Unregisters this protocol driver with NDIS
+ * NOTES: Does not care wether we are already registered
+ */
+{
+    PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
+    
+    LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+    NDIS_STATUS NdisStatus;
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PLAN_ADAPTER Current;
+    KIRQL OldIrql;
+    
+    KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
+    
+    /* Search the list and remove every adapter we find */
+    CurrentEntry = DeviceExt->AdapterListHead.Flink;
+    while (CurrentEntry != &DeviceExt->AdapterListHead) {
+       NextEntry = CurrentEntry->Flink;
+       Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
+       /* Unregister it */
+       LANUnregisterAdapter(Current);
+       CurrentEntry = NextEntry;
+    }
+    
+    NdisDeregisterProtocol(&NdisStatus, DeviceExt->NdisProtocolHandle);
+}
+
+NTSTATUS STDCALL
+LanCreateProtocol( PDEVICE_OBJECT DeviceObject, PIRP Irp, 
+                  PIO_STACK_LOCATION IrpSp ) {
+    PLAN_PROTOCOL Proto;
+    PFILE_FULL_EA_INFORMATION EaInfo;
+    PLAN_DEVICE_EXT DeviceExt = 
+       (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PCHAR ProtoNumbersToMatch;
+    UINT Size = sizeof( *Proto );
+    NTSTATUS Status = STATUS_SUCCESS;
+    
+    EaInfo = Irp->AssociatedIrp.SystemBuffer;
+    Size += EaInfo->EaValueLength;
+    Proto = ExAllocatePool( NonPagedPool, Size );
+
+    if( !Proto ) {
+       Status = Irp->IoStatus.Status = STATUS_NO_MEMORY;
+       IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+       return Status;
+    }
+
+    RtlZeroMemory( Proto, Size );
+
+    Proto->Id = DeviceExt->ProtoId++;
+    Proto->NumEtherTypes = EaInfo->EaValueLength / sizeof(USHORT);
+    ProtoNumbersToMatch = EaInfo->EaName + EaInfo->EaNameLength + 1;
+
+    LA_DbgPrint(MID_TRACE,("NumEtherTypes: %d\n", Proto->NumEtherTypes));
+
+    RtlCopyMemory( Proto->EtherType, 
+                  ProtoNumbersToMatch,
+                  sizeof(USHORT) * Proto->NumEtherTypes );
+
+    InitializeListHead( &Proto->ReadIrpListHead );
+
+    FileObject->FsContext = Proto;
+
+    LA_DbgPrint(MID_TRACE,("DeviceExt: %x, Proto %x\n", DeviceExt, Proto));
+
+    ExInterlockedInsertTailList( &DeviceExt->ProtocolListHead,
+                                &Proto->ListEntry,
+                                &DeviceExt->Lock );
+
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+
+    LA_DbgPrint(MID_TRACE,("Status %x\n", Irp->IoStatus.Status));
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+LanCloseProtocol( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                 PIO_STACK_LOCATION IrpSp ) {
+    PLAN_DEVICE_EXT DeviceExt = 
+       (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PLAN_PROTOCOL Proto = FileObject->FsContext;
+    KIRQL OldIrql;
+    PLIST_ENTRY ReadIrpListEntry;
+    PIRP ReadIrp;
+    NTSTATUS Status;
+
+    LA_DbgPrint(MID_TRACE,("Called\n"));
+
+    KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+
+    while( !IsListEmpty( &Proto->ReadIrpListHead ) ) {
+       ReadIrpListEntry = RemoveHeadList( &Proto->ReadIrpListHead );
+
+       ReadIrp = CONTAINING_RECORD( ReadIrpListEntry, IRP, 
+                                    Tail.Overlay.ListEntry );
+       ReadIrp->IoStatus.Information = 0;
+       ReadIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+       IoCompleteRequest( ReadIrp, IO_NO_INCREMENT );
+    }
+
+    RemoveEntryList( &Proto->ListEntry );
+
+    KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+
+    LA_DbgPrint(MID_TRACE,("Deleting %x\n"));
+
+    ExFreePool( Proto );
+
+    Status = Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+    return Status;
+}
+
+PLAN_ADAPTER FindAdapterByIndex( PLAN_DEVICE_EXT DeviceExt, UINT Index ) {
+    PLIST_ENTRY ListEntry;
+    PLAN_ADAPTER Current, Target = NULL;
+
+    for( ListEntry = DeviceExt->AdapterListHead.Flink;
+        ListEntry != &DeviceExt->AdapterListHead;
+        ListEntry = ListEntry->Flink ) {
+       Current = CONTAINING_RECORD(ListEntry, LAN_ADAPTER, ListEntry);
+       if( Current->Index == Index ) {
+           Target = Current; 
+           break;
+       }
+    }
+
+    return Target;
+}
+
+/* Write data to an adapter:
+ * |<-              16               >| |<-- variable ... -->|
+ * [indx] [addrtype] [addrlen ] [ptype] [packet-data ...]
+ */
+NTSTATUS STDCALL
+LanWriteData( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+             PIO_STACK_LOCATION IrpSp ) {
+    PLAN_PACKET_HEADER ToWrite = Irp->AssociatedIrp.SystemBuffer;
+    NTSTATUS Status = STATUS_SUCCESS;
+    
+    LA_DbgPrint(MID_TRACE,("Called\n"));
+
+    Irp->IoStatus.Information = 
+       LANTransmitInternal( ToWrite, IrpSp->Parameters.Write.Length );
+    Irp->IoStatus.Status = Status;
+    
+    IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+    return Status;
+}
+
+NTSTATUS STDCALL
+LanReadData( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+            PIO_STACK_LOCATION IrpSp ) {
+    PLAN_DEVICE_EXT DeviceExt = 
+       (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PLAN_PROTOCOL Proto = FileObject->FsContext;
+
+    LA_DbgPrint(MID_TRACE,("Called on %x (%x)\n", Proto, Irp));
+
+    ExInterlockedInsertTailList( &Proto->ReadIrpListHead,
+                                &Irp->Tail.Overlay.ListEntry,
+                                &DeviceExt->Lock );
+
+    LA_DbgPrint(MID_TRACE,("List: %x %x\n",
+                          Proto->ReadIrpListHead.Flink,
+                          Irp->Tail.Overlay.ListEntry.Flink));
+
+    IoMarkIrpPending( Irp );
+    return STATUS_PENDING;
+}
+
+NTSTATUS STDCALL
+LanEnumAdapters( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                PIO_STACK_LOCATION IrpSp ) {
+    PLIST_ENTRY ListEntry;
+    PLAN_DEVICE_EXT DeviceExt = 
+       (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PLAN_ADAPTER Adapter;
+    UINT AdapterCount = 0;
+    PUINT Output = Irp->AssociatedIrp.SystemBuffer;
+    KIRQL OldIrql;
+
+    LA_DbgPrint(MID_TRACE,("Called\n"));
+
+    KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+    
+    for( ListEntry = DeviceExt->AdapterListHead.Flink;
+        ListEntry != &DeviceExt->AdapterListHead;
+        ListEntry = ListEntry->Flink ) AdapterCount++;
+
+    if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
+       AdapterCount * sizeof(UINT) ) {
+       for( ListEntry = DeviceExt->AdapterListHead.Flink;
+            ListEntry != &DeviceExt->AdapterListHead;
+            ListEntry = ListEntry->Flink ) {
+           Adapter = CONTAINING_RECORD(ListEntry, LAN_ADAPTER, ListEntry);
+           *Output++ = Adapter->Index;
+       }
+    } else Status = STATUS_BUFFER_TOO_SMALL;
+
+    KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+
+    LA_DbgPrint(MID_TRACE,("Ending\n"));
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = (PCHAR)Output - 
+       (PCHAR)Irp->AssociatedIrp.SystemBuffer;
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+    return Status;
+}
+
+NTSTATUS STDCALL
+LanAdapterInfo( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+               PIO_STACK_LOCATION IrpSp ) {
+    PLAN_DEVICE_EXT DeviceExt = 
+       (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
+    PLAN_ADAPTER Adapter;
+    PLAN_ADDRESS_C Address;
+    PUINT AdapterIndexPtr = Irp->AssociatedIrp.SystemBuffer;
+    PLIST_ENTRY ListEntry;
+    UINT BytesNeeded = sizeof( LAN_ADAPTER_INFO ), AddrSize;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCHAR Writing = Irp->AssociatedIrp.SystemBuffer;
+    PLAN_ADAPTER_INFO_S Info;
+    KIRQL OldIrql;
+
+    LA_DbgPrint(MID_TRACE,("Called\n"));
+
+    KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+
+    if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < 
+       sizeof(*AdapterIndexPtr) )
+       Adapter = NULL;
+    else
+       Adapter = FindAdapterByIndex( DeviceExt, *AdapterIndexPtr );
+
+    if( Adapter ) {
+       /* Local Addresses */
+       for( ListEntry = Adapter->AddressList.Flink;
+            ListEntry != &Adapter->AddressList;
+            ListEntry = ListEntry->Flink ) {
+           Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C, ListEntry);
+           BytesNeeded += LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
+                                        Address->ClientPart.HWAddressLen);
+       }
+
+       /* Foreign Addresses */
+       for( ListEntry = Adapter->ForeignList.Flink;
+            ListEntry != &Adapter->ForeignList;
+            ListEntry = ListEntry->Flink ) {
+           Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C, ListEntry);
+           BytesNeeded += LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
+                                        Address->ClientPart.HWAddressLen);
+       }
+       BytesNeeded += Adapter->RegistryPath.Length;
+
+       if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
+           BytesNeeded ) {
+           /* Write common info */
+           Info = (PLAN_ADAPTER_INFO_S)Writing;
+           Info->Index      = Adapter->Index;
+           Info->Media      = Adapter->Media;
+           Info->Speed      = Adapter->Speed;
+           /* Ethernet specific XXX */
+           Info->AddressLen = IEEE_802_ADDR_LENGTH; 
+           Info->Overhead   = Adapter->HeaderSize;
+           Info->MTU        = Adapter->MTU;
+           Info->RegKeySize = Adapter->RegistryPath.Length;
+
+           /* Copy the name */
+           Writing += sizeof(*Info);
+           RtlCopyMemory( Adapter->RegistryPath.Buffer,
+                          Writing,
+                          Adapter->RegistryPath.Length );
+
+           /* Write the address info */
+           Writing += Adapter->RegistryPath.Length;
+           
+           for( ListEntry = Adapter->AddressList.Flink;
+                ListEntry != &Adapter->AddressList;
+                ListEntry = ListEntry->Flink ) {
+               Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C, 
+                                           ListEntry);
+               AddrSize = LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
+                                        Address->ClientPart.HWAddressLen);
+               RtlCopyMemory( Writing, &Address->ClientPart, AddrSize );
+               Writing += AddrSize;
+           }
+
+           for( ListEntry = Adapter->ForeignList.Flink;
+                ListEntry != &Adapter->ForeignList;
+                ListEntry = ListEntry->Flink ) {
+               Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C, 
+                                           ListEntry);
+               AddrSize = LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
+                                        Address->ClientPart.HWAddressLen);
+               RtlCopyMemory( Writing, &Address->ClientPart, AddrSize );
+               Writing += AddrSize;
+           }
+
+           ASSERT( BytesNeeded == Writing - Irp->AssociatedIrp.SystemBuffer );
+       } else Status = STATUS_BUFFER_TOO_SMALL;
+    } else Status = STATUS_NO_SUCH_DEVICE;
+    
+    KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+
+    LA_DbgPrint(MID_TRACE,("Ending (%d bytes)\n", BytesNeeded));
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = BytesNeeded;
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+    return Status;
+}
+
+NTSTATUS STDCALL
+LanSetBufferedMode( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                   PIO_STACK_LOCATION IrpSp ) {
+    PLAN_DEVICE_EXT DeviceExt = 
+       (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PLAN_PROTOCOL Proto = FileObject->FsContext;
+    NTSTATUS Status = STATUS_SUCCESS;
+    KIRQL OldIrql;
+
+    LA_DbgPrint(MID_TRACE,("Called %x\n", Proto));
+
+    KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );    
+
+    if( IrpSp->Parameters.DeviceIoControl.InputBufferLength >= 
+       sizeof(Proto->Buffered) )
+       RtlCopyMemory( &Proto->Buffered, Irp->AssociatedIrp.SystemBuffer,
+                      sizeof(Proto->Buffered) );
+    else
+       Status = STATUS_INVALID_PARAMETER;
+    
+    KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+
+    LA_DbgPrint(MID_TRACE,("Set buffered for %x to %d\n", Proto->Buffered));
+
+    Status = Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = 0;
+
+    IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+    return Status;
+}
+
+NTSTATUS STDCALL
+LanDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+    NTSTATUS Status = STATUS_SUCCESS;
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+
+    LA_DbgPrint(MID_TRACE,("LanDispatch: %d\n", IrpSp->MajorFunction));
+    if( IrpSp->MajorFunction != IRP_MJ_CREATE) {
+       LA_DbgPrint(MID_TRACE,("FO %x, IrpSp->FO %x\n",
+                              FileObject, IrpSp->FileObject));
+       ASSERT(FileObject == IrpSp->FileObject);
+    }
+
+    switch(IrpSp->MajorFunction)
+    {
+       /* opening and closing handles to the device */
+    case IRP_MJ_CREATE:
+       /* Mostly borrowed from the named pipe file system */
+       return LanCreateProtocol(DeviceObject, Irp, IrpSp);
+
+    case IRP_MJ_CLOSE:
+       /* Ditto the borrowing */
+       return LanCloseProtocol(DeviceObject, Irp, IrpSp);
+
+       /* write data */
+    case IRP_MJ_WRITE:
+       return LanWriteData( DeviceObject, Irp, IrpSp );
+    
+       /* read data */
+    case IRP_MJ_READ:
+       return LanReadData( DeviceObject, Irp, IrpSp );
+
+    case IRP_MJ_DEVICE_CONTROL:
+    {
+       LA_DbgPrint(MID_TRACE,("DeviceIoControl: %x\n", 
+                              IrpSp->Parameters.DeviceIoControl.
+                              IoControlCode));
+       switch( IrpSp->Parameters.DeviceIoControl.IoControlCode ) {
+       case IOCTL_IF_ENUM_ADAPTERS:
+           return LanEnumAdapters( DeviceObject, Irp, IrpSp );
+
+       case IOCTL_IF_BUFFERED_MODE:
+           return LanSetBufferedMode( DeviceObject, Irp, IrpSp );
+
+       case IOCTL_IF_ADAPTER_INFO:
+           return LanAdapterInfo( DeviceObject, Irp, IrpSp );
+
+       default:
+           Status = STATUS_NOT_IMPLEMENTED;
+           Irp->IoStatus.Information = 0;
+           LA_DbgPrint(MIN_TRACE, ("Unknown IOCTL (0x%x)\n",
+                                   IrpSp->Parameters.DeviceIoControl.
+                                   IoControlCode));
+           break;
+       }
+       break;
+    }
+
+    /* unsupported operations */
+    default:
+    {
+       Status = STATUS_NOT_IMPLEMENTED;
+       LA_DbgPrint(MIN_TRACE,
+                   ("Irp: Unknown Major code was %x\n", 
+                    IrpSp->MajorFunction));
+       break;
+    }
+    }
+    
+    LA_DbgPrint(MID_TRACE, ("Returning %x\n", Status));
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    
+    return (Status);
+}
+
+/* Do i need a global here?  I think i need to do this a different way XXX */
+VOID STDCALL LanUnload(PDRIVER_OBJECT DriverObject) {
+    LANUnregisterProtocol();
+    CloseNdisPools();
+}
+
+NTSTATUS STDCALL DriverEntry( PDRIVER_OBJECT DriverObject, 
+                             PUNICODE_STRING RegsitryPath ) {
+    PDEVICE_OBJECT DeviceObject;
+    PLAN_DEVICE_EXT DeviceExt;
+    UNICODE_STRING wstrDeviceName, LanString;
+    NTSTATUS Status;
+
+    InitNdisPools();
+
+    /* register driver routines */
+    DriverObject->MajorFunction[IRP_MJ_CLOSE] = LanDispatch;
+    DriverObject->MajorFunction[IRP_MJ_CREATE] = LanDispatch;
+    DriverObject->MajorFunction[IRP_MJ_WRITE] = LanDispatch;
+    DriverObject->MajorFunction[IRP_MJ_READ] = LanDispatch;
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = LanDispatch;
+    DriverObject->DriverUnload = LanUnload;
+
+    /* create lan device */
+    RtlRosInitUnicodeStringFromLiteral(&wstrDeviceName, L"\\Device\\Lan");
+    RtlRosInitUnicodeStringFromLiteral(&LanString, L"LAN");
+
+    Status = IoCreateDevice
+       ( DriverObject,
+         sizeof(LAN_DEVICE_EXT),
+         &wstrDeviceName,
+         FILE_DEVICE_NAMED_PIPE,
+         0,
+         FALSE,
+         &DeviceObject );
+
+    /* failure */
+    if(!NT_SUCCESS(Status))
+    {
+       return (Status);
+    }
+
+    LanDeviceObject = DeviceObject;
+    DeviceExt = DeviceObject->DeviceExtension;
+    RtlZeroMemory( DeviceExt, sizeof(*DeviceExt) );
+    InitializeListHead( &DeviceExt->AdapterListHead );
+    InitializeListHead( &DeviceExt->ProtocolListHead );
+    KeInitializeSpinLock( &DeviceExt->Lock );
+
+    LANRegisterProtocol( &LanString );
+
+    DeviceObject->Flags |= DO_BUFFERED_IO;
+    
+    LA_DbgPrint(MID_TRACE,("Device created: object %x ext %x\n",
+                          DeviceObject, DeviceExt));
+    
+    return (Status);    
+}
+
+/* EOF */
diff --git a/reactos/drivers/net/lan/lan/routines.c b/reactos/drivers/net/lan/lan/routines.c
new file mode 100644 (file)
index 0000000..a8ddf03
--- /dev/null
@@ -0,0 +1,149 @@
+#include "precomp.h"
+
+NDIS_HANDLE    GlobalPacketPool = NULL;
+NDIS_HANDLE    GlobalBufferPool = NULL;
+
+NDIS_STATUS InitNdisPools() {
+    NDIS_STATUS NdisStatus;
+    /* Last argument is extra space size */
+    NdisAllocatePacketPool( &NdisStatus, &GlobalPacketPool, 100, 0 );
+    if( !NT_SUCCESS(NdisStatus) ) return NdisStatus;
+    
+    NdisAllocateBufferPool( &NdisStatus, &GlobalBufferPool, 100 );
+    if( !NT_SUCCESS(NdisStatus) )
+       NdisFreePacketPool(GlobalPacketPool);
+
+    return NdisStatus;
+}
+
+VOID CloseNdisPools() {
+    if( GlobalPacketPool ) NdisFreePacketPool( GlobalPacketPool );
+    if( GlobalBufferPool ) NdisFreeBufferPool( GlobalBufferPool );
+}
+
+__inline INT SkipToOffset(
+    PNDIS_BUFFER Buffer,
+    UINT Offset,
+    PCHAR *Data,
+    PUINT Size)
+/*
+ * FUNCTION: Skip Offset bytes into a buffer chain
+ * ARGUMENTS:
+ *     Buffer = Pointer to NDIS buffer
+ *     Offset = Number of bytes to skip
+ *     Data   = Address of a pointer that on return will contain the
+ *              address of the offset in the buffer
+ *     Size   = Address of a pointer that on return will contain the
+ *              size of the destination buffer
+ * RETURNS:
+ *     Offset into buffer, -1 if buffer chain was smaller than Offset bytes
+ * NOTES:
+ *     Buffer may be NULL
+ */
+{
+    for (;;) {
+
+        if (!Buffer)
+            return -1;
+
+        NdisQueryBuffer(Buffer, (PVOID)Data, Size);
+
+        if (Offset < *Size) {
+            *Data = (PCHAR)((ULONG_PTR) *Data + Offset);
+            *Size              -= Offset;
+            break;
+        }
+
+        Offset -= *Size;
+
+        NdisGetNextBuffer(Buffer, &Buffer);
+    }
+
+    return Offset;
+}
+
+void GetDataPtr( PNDIS_PACKET Packet,
+                UINT Offset, 
+                PCHAR *DataOut,
+                PUINT Size ) {
+    PNDIS_BUFFER Buffer;
+
+    NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
+    if( !Buffer ) return;
+    SkipToOffset( Buffer, Offset, DataOut, Size );
+}
+
+
+#undef NdisAllocatePacket
+#undef NdisAllocateBuffer
+#undef NdisFreeBuffer
+#undef NdisFreePacket
+
+NDIS_STATUS AllocatePacketWithBufferX( PNDIS_PACKET *NdisPacket,
+                                      PCHAR Data, UINT Len,
+                                      PCHAR File, UINT Line ) {
+    PNDIS_PACKET Packet;
+    PNDIS_BUFFER Buffer;
+    NDIS_STATUS Status;
+    PCHAR NewData;
+
+    NewData = ExAllocatePool( NonPagedPool, Len );
+    if( !NewData ) return NDIS_STATUS_NOT_ACCEPTED; // XXX 
+    TrackWithTag(EXALLOC_TAG, NewData, File, Line);
+
+    if( Data ) 
+       RtlCopyMemory(NewData, Data, Len);
+
+    NdisAllocatePacket( &Status, &Packet, GlobalPacketPool );
+    if( Status != NDIS_STATUS_SUCCESS ) {
+       ExFreePool( NewData );
+       return Status;
+    }
+    TrackWithTag(NDIS_PACKET_TAG, Packet, File, Line);
+
+    NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewData, Len );
+    if( Status != NDIS_STATUS_SUCCESS ) {
+       ExFreePool( NewData );
+       FreeNdisPacket( Packet );
+    }
+    TrackWithTag(NDIS_BUFFER_TAG, Buffer, File, Line);
+
+    NdisChainBufferAtFront( Packet, Buffer );
+    *NdisPacket = Packet;
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID FreeNdisPacketX
+( PNDIS_PACKET Packet,
+  PCHAR File,
+  UINT Line )
+/*
+ * FUNCTION: Frees an NDIS packet
+ * ARGUMENTS:
+ *     Packet = Pointer to NDIS packet to be freed
+ */
+{
+    PNDIS_BUFFER Buffer, NextBuffer;
+
+    LA_DbgPrint(DEBUG_PBUFFER, ("Packet (0x%X)\n", Packet));
+
+    /* Free all the buffers in the packet first */
+    NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
+    for (; Buffer != NULL; Buffer = NextBuffer) {
+        PVOID Data;
+        UINT Length;
+
+        NdisGetNextBuffer(Buffer, &NextBuffer);
+        NdisQueryBuffer(Buffer, &Data, &Length);
+        NdisFreeBuffer(Buffer);
+       UntrackFL(File,Line,Buffer);
+        ExFreePool(Data);
+       UntrackFL(File,Line,Data);
+    }
+
+    /* Finally free the NDIS packet discriptor */
+    NdisFreePacket(Packet);
+    UntrackFL(File,Line,Packet);
+}
diff --git a/reactos/drivers/net/lan/makefile b/reactos/drivers/net/lan/makefile
new file mode 100644 (file)
index 0000000..3675ce5
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id: makefile,v 1.1 2004/09/17 15:50:15 arty Exp $
+
+PATH_TO_TOP = ../../..
+
+# TARGET_REGTESTS = yes
+
+TARGET_TYPE = driver
+
+TARGET_NAME = lan
+
+TARGET_PCH = include/precomp.h
+
+# -DMEMTRACK
+TARGET_CFLAGS = \
+       -D__USE_W32API \
+       -DNDIS40 \
+       -DMEMTRACK \
+       -Wall -Werror \
+       -I./include \
+       -I$(PATH_TO_TOP)/w32api/include \
+       -I$(PATH_TO_TOP)/include
+
+TARGET_DDKLIBS = ndis.a \
+       $(PATH_TO_TOP)/dk/w32/lib/pseh.a
+
+TARGET_CLEAN = \
+       lan/*.o
+
+TARGET_OBJECTS = lan/lan.o lan/routines.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk