summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/loop
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/loop')
-rw-r--r--private/ntos/ndis/loop/debug.h47
-rw-r--r--private/ntos/ndis/loop/loop.c1378
-rw-r--r--private/ntos/ndis/loop/loop.h223
-rw-r--r--private/ntos/ndis/loop/loop.rc39
-rw-r--r--private/ntos/ndis/loop/makefile6
-rw-r--r--private/ntos/ndis/loop/request.c1255
-rw-r--r--private/ntos/ndis/loop/send.c717
-rw-r--r--private/ntos/ndis/loop/sources20
8 files changed, 3685 insertions, 0 deletions
diff --git a/private/ntos/ndis/loop/debug.h b/private/ntos/ndis/loop/debug.h
new file mode 100644
index 000000000..932be4267
--- /dev/null
+++ b/private/ntos/ndis/loop/debug.h
@@ -0,0 +1,47 @@
+#ifndef _DEBUG_
+#define _DEBUG_
+
+#if DBG
+ #define DEBUG DBG
+#endif
+//
+// Debug Levels used with DBGPRINT
+
+#define DBG_LEVEL_INFO 0
+#define DBG_LEVEL_WARN 1
+#define DBG_LEVEL_ERR 2
+#define DBG_LEVEL_FATAL 3
+
+// Component Types
+
+#define DBG_COMP_INIT 0x00000001
+#define DBG_COMP_DPC 0x00000002
+#define DBG_COMP_REGISTRY 0x00000004
+#define DBG_COMP_MEMORY 0x00000008
+#define DBG_COMP_SEND 0x00000010
+#define DBG_COMP_REQUEST 0x00000020
+#define DBG_COMP_MISC 0x00000040
+#define DBG_COMP_ALL 0xffffffff
+
+extern LONG LoopDebugLevel;
+extern LONG LoopDebugComponent;
+
+#ifdef DEBUG
+
+ #define DBGPRINT(Component, Level, Fmt) \
+ if ((LoopDebugComponent & Component) && (Level >= LoopDebugLevel)) { \
+ DbgPrint(" *** Loop - "); \
+ DbgPrint Fmt; \
+ }
+
+ #define DBGBREAK(Level) \
+ if (Level >= LoopDebugLevel) { \
+ DbgBreakPoint(); \
+ }
+
+#else
+ #define DBGPRINT(Component, Level, Fmt)
+ #define DBGBREAK(Level)
+#endif
+
+#endif // _DEBUG_
diff --git a/private/ntos/ndis/loop/loop.c b/private/ntos/ndis/loop/loop.c
new file mode 100644
index 000000000..39cfe2332
--- /dev/null
+++ b/private/ntos/ndis/loop/loop.c
@@ -0,0 +1,1378 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#include "debug.h"
+#include "loop.h"
+
+#if DBG
+extern LONG LoopDebugLevel = DBG_LEVEL_FATAL;
+extern LONG LoopDebugComponent = DBG_COMP_ALL;
+#endif
+
+NDIS_STATUS
+LoopAddAdapter(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ );
+
+NDIS_STATUS
+LoopCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+LoopOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingOptions OPTIONAL
+ );
+
+VOID
+LoopRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+NDIS_STATUS
+LoopReset(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+NDIS_STATUS
+LoopTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+VOID
+LoopUnload(
+ IN NDIS_HANDLE MacMacContext
+ );
+
+
+STATIC
+NDIS_STATUS
+LoopRegisterAdapter(
+ IN NDIS_HANDLE LoopMacHandle,
+ IN PNDIS_STRING AdapterName,
+ IN NDIS_MEDIUM AdapterMedium,
+ IN PVOID NetAddress,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+STATIC
+NDIS_STATUS
+LoopChangeFilter(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+VOID
+LoopCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ );
+
+STATIC
+NDIS_STATUS
+LoopEthChangeAddress(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCouunt,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+NDIS_STATUS
+LoopTrChangeAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddresses,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddresses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC
+NDIS_STATUS
+LoopFddiChangeAddress(
+ IN UINT OldLongAddressCount,
+ IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT NewLongAddressCouunt,
+ IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT OldShortAddressCount,
+ IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT NewShortAddressCouunt,
+ IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+STATIC NDIS_HANDLE LoopWrapperHandle;
+STATIC NDIS_HANDLE LoopMacHandle;
+
+// !! need to verify filters !!
+#define PACKET_FILTER_802_3 0xF07F
+#define PACKET_FILTER_802_5 0xF07F
+#define PACKET_FILTER_DIX 0xF07F
+#define PACKET_FILTER_FDDI 0xF07F
+#define PACKET_FILTER_LTALK 0x8009
+#define PACKET_FILTER_ARCNET 0x8009
+
+static const NDIS_PHYSICAL_ADDRESS physicalConst = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+{
+ NDIS_STATUS Status;
+ NDIS_MAC_CHARACTERISTICS LoopChar;
+ NDIS_STRING MacName = NDIS_STRING_CONST("LoopBack");
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, (" --> DriverEntry\n"));
+
+ NdisInitializeWrapper(
+ &LoopWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ LoopChar.MajorNdisVersion = LOOP_NDIS_MAJOR_VERSION;
+ LoopChar.MinorNdisVersion = LOOP_NDIS_MINOR_VERSION;
+ LoopChar.OpenAdapterHandler = LoopOpenAdapter;
+ LoopChar.CloseAdapterHandler = LoopCloseAdapter;
+ LoopChar.RequestHandler = LoopRequest;
+ LoopChar.SendHandler = LoopSend;
+ LoopChar.TransferDataHandler = LoopTransferData;
+ LoopChar.ResetHandler = LoopReset;
+ LoopChar.UnloadMacHandler = LoopUnload;
+ LoopChar.QueryGlobalStatisticsHandler = LoopQueryGlobalStats;
+ LoopChar.AddAdapterHandler = LoopAddAdapter;
+ LoopChar.RemoveAdapterHandler = LoopRemoveAdapter;
+ LoopChar.Name = MacName;
+
+ NdisRegisterMac(
+ &Status,
+ &LoopMacHandle,
+ LoopWrapperHandle,
+ NULL,
+ &LoopChar,
+ sizeof(LoopChar)
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ return STATUS_SUCCESS;
+
+ // Can only get here if something went wrong registering the MAC or
+ // all of the adapters
+ NdisTerminateWrapper(LoopWrapperHandle, DriverObject);
+ return STATUS_UNSUCCESSFUL;
+}
+
+NDIS_STATUS
+LoopAddAdapter(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING AdapterName
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HANDLE ConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+ NDIS_STRING MediumKey = NDIS_STRING_CONST("Medium");
+ PUCHAR NetAddressBuffer[6];
+ PVOID NetAddress;
+ UINT Length;
+ NDIS_MEDIUM AdapterMedium;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, (" --> LoopAddAdapter\n"));
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, ("Reading Config Info\n"));
+
+ // configuration info present, let's get it
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ // would like to log this, but adapter not registered yet
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("Unable to open configuration database!\n"));
+
+ return Status;
+ }
+
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigHandle,
+ &MediumKey,
+ NdisParameterInteger
+ );
+
+ AdapterMedium = (NDIS_MEDIUM)Parameter->ParameterData.IntegerData;
+
+ if ((Status != NDIS_STATUS_SUCCESS) ||
+ !((AdapterMedium == NdisMedium802_3) ||
+ (AdapterMedium == NdisMedium802_5) ||
+ (AdapterMedium == NdisMediumFddi) ||
+ (AdapterMedium == NdisMediumLocalTalk) ||
+ (AdapterMedium == NdisMediumArcnet878_2))) {
+
+ // would like to log this, but adapter not registered yet
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("Unable to find 'Medium' keyword or invalid value!\n"));
+
+ NdisCloseConfiguration(ConfigHandle);
+ return Status;
+ }
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetAddress,
+ &Length,
+ ConfigHandle
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ // verify the address is appropriate for the specific media and
+ // ensure that the locally administered address bit is set
+
+ switch (AdapterMedium) {
+ case NdisMedium802_3:
+ if ((Length != ETH_LENGTH_OF_ADDRESS) ||
+ ETH_IS_MULTICAST(NetAddress) ||
+ !(((PUCHAR)NetAddress)[0] & 0x02)) { // U/L bit
+ Length = 0;
+ }
+ break;
+ case NdisMedium802_5:
+ if ((Length != TR_LENGTH_OF_ADDRESS) ||
+ (((PUCHAR)NetAddress)[0] & 0x80) || // I/G bit
+ !(((PUCHAR)NetAddress)[0] & 0x40)) { // U/L bit
+ Length = 0;
+ }
+ break;
+ case NdisMediumFddi:
+ if ((Length != FDDI_LENGTH_OF_LONG_ADDRESS) ||
+ (((PUCHAR)NetAddress)[0] & 0x01) || // I/G bit
+ !(((PUCHAR)NetAddress)[0] & 0x02)) { // U/L bit
+ Length = 0;
+ }
+ break;
+ case NdisMediumLocalTalk:
+ if ((Length != 1) || LOOP_LT_IS_BROADCAST(*(PUCHAR)NetAddress)) {
+ Length = 0;
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ if ((Length != 1) || LOOP_ARC_IS_BROADCAST(*(PUCHAR)NetAddress)) {
+ Length = 0;
+ }
+ break;
+ }
+
+ if (Length == 0) {
+ DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
+ ("Invalid NetAddress in registry!\n"));
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ // have to save away the address as the info may be gone
+ // when we close the registry. we assume the length will
+ // be 6 bytes max
+
+ NdisMoveMemory(
+ NetAddressBuffer,
+ NetAddress,
+ Length
+ );
+ NetAddress = (PVOID)NetAddressBuffer;
+
+ }
+ else
+ NetAddress = NULL;
+
+ NdisCloseConfiguration(ConfigHandle);
+
+ Status = LoopRegisterAdapter(
+ LoopMacHandle,
+ AdapterName,
+ AdapterMedium,
+ NetAddress,
+ ConfigurationHandle
+ );
+ return Status;
+}
+
+NDIS_STATUS
+LoopCloseAdapter(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+{
+ PLOOP_ADAPTER Adapter;
+ PLOOP_OPEN Open;
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopCloseAdapter\n"));
+
+ Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Closing Open %lx, reference count = %ld\n",Open,Open->References));
+
+ if (!Open->BindingClosing) {
+
+ Open->BindingClosing = TRUE;
+ RemoveEntryList(&Open->OpenList);
+ Adapter->OpenCount--;
+ Adapter->References--;
+
+ //
+ // shouldn't be called unless there isn't anything running in the
+ // binding. if there is we're hosed.
+ //
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ StatusToReturn = EthDeleteFilterOpenAdapter(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ NULL
+ );
+ // needs to handle pending delete, but should be ok
+ // since our close action routine doesn't pend
+ break;
+ case NdisMedium802_5:
+ StatusToReturn = TrDeleteFilterOpenAdapter(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NULL
+ );
+ // needs to handle pending delete, but should be ok
+ // since our close action routine doesn't pend
+ break;
+ case NdisMediumFddi:
+ StatusToReturn = FddiDeleteFilterOpenAdapter(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NULL
+ );
+ // needs to handle pending delete, but should be ok
+ // since our close action routine doesn't pend
+ break;
+ case NdisMediumLocalTalk:
+ case NdisMediumArcnet878_2:
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ NdisFreeMemory(
+ Open,
+ sizeof(LOOP_OPEN),
+ 0
+ );
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+
+NDIS_STATUS
+LoopOpenAdapter(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT NDIS_HANDLE *MacBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingOptions OPTIONAL
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+ PLOOP_OPEN NewOpen;
+ NDIS_STATUS StatusToReturn;
+ UINT i;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopOpenAdapter\n"));
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Opening binding for Adapter %lx\n",Adapter));
+
+ for (i=0;i < MediumArraySize; i++) {
+ if (MediumArray[i] == Adapter->Medium)
+ break;
+ }
+
+ if (i == MediumArraySize)
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ *SelectedMediumIndex = i;
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ NdisAllocateMemory(
+ (PVOID)&NewOpen,
+ sizeof(LOOP_OPEN),
+ 0,
+ physicalConst
+ );
+
+ if (NewOpen != NULL) {
+
+ //
+ // Setup new Open Binding struct
+ //
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new Open = %lx\n",NewOpen));
+
+ NdisZeroMemory(
+ NewOpen,
+ sizeof(LOOP_OPEN)
+ );
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ StatusToReturn = (NDIS_STATUS)EthNoteFilterOpenAdapter(
+ Adapter->Filter.Eth,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new EthFilter Open = %lx\n",NewOpen->NdisFilterHandle));
+ break;
+ case NdisMedium802_5:
+ StatusToReturn = (NDIS_STATUS)TrNoteFilterOpenAdapter(
+ Adapter->Filter.Tr,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new TrFilter Open = %lx\n",NewOpen->NdisFilterHandle));
+ break;
+ case NdisMediumFddi:
+ StatusToReturn = (NDIS_STATUS)FddiNoteFilterOpenAdapter(
+ Adapter->Filter.Fddi,
+ NewOpen,
+ NdisBindingContext,
+ &NewOpen->NdisFilterHandle
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, ("new FddiFilter Open = %lx\n",NewOpen->NdisFilterHandle));
+ break;
+ default:
+ StatusToReturn = (NDIS_STATUS)TRUE;
+ break;
+ }
+
+ if (!StatusToReturn) {
+
+ DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
+ ("unable to create filter for binding %lx\n",NewOpen));
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ NdisFreeMemory(
+ NewOpen,
+ sizeof(LOOP_OPEN),
+ 0);
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ *MacBindingHandle = BINDING_HANDLE_FROM_PLOOP_OPEN(NewOpen);
+
+ InitializeListHead(&NewOpen->OpenList);
+ NewOpen->BindingClosing = FALSE;
+ NewOpen->Flags = 0;
+ NewOpen->NdisBindingContext = NdisBindingContext;
+ NewOpen->OwningLoop = Adapter;
+ NewOpen->References = 1;
+ NewOpen->CurrentLookAhead = LOOP_MAX_LOOKAHEAD;
+ NewOpen->CurrentPacketFilter = 0;
+
+ //
+ // Add the binding to the owning adapter
+ //
+
+ InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList);
+ Adapter->OpenCount++;
+ Adapter->References++;
+ Adapter->MaxLookAhead = LOOP_MAX_LOOKAHEAD;
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ }
+
+ else {
+
+ DBGPRINT(DBG_COMP_MEMORY, DBG_LEVEL_ERR,
+ ("unable to allocate binding struct for adapter %lx\n",Adapter));
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ }
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+
+VOID
+LoopRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ )
+//
+// All bindings should be closed before this gets called
+//
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+ BOOLEAN TimerCancel;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopRemoveAdapter\n"));
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Removing adapter %lx\n",Adapter));
+
+ NdisCancelTimer(&Adapter->LoopTimer,&TimerCancel);
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("deleting EthFilter %lx\n",Adapter->Filter.Eth));
+ EthDeleteFilter(Adapter->Filter.Eth);
+ break;
+ case NdisMedium802_5:
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("deleting TrFilter %lx\n",Adapter->Filter.Tr));
+ TrDeleteFilter(Adapter->Filter.Tr);
+ break;
+ case NdisMediumFddi:
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("deleting FddiFilter %lx\n",Adapter->Filter.Fddi));
+ FddiDeleteFilter(Adapter->Filter.Fddi);
+ break;
+ default:
+ break;
+ }
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(
+ Adapter->DeviceName.Buffer,
+ Adapter->DeviceNameLength,
+ 0
+ );
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+}
+
+
+NDIS_STATUS
+LoopReset(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopReset\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PLOOP_OPEN Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingClosing) {
+
+ Open->References++;
+
+ //
+ // notify all bindings of beginning of reset
+ //
+ {
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO,
+ ("Signaling reset start to binding %lx\n",Open));
+
+ if (Open->BindingClosing) {
+ CurrentLink = CurrentLink->Flink;
+ continue;
+ }
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET_START,
+ NULL,
+ 0
+ );
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ CurrentLink = CurrentLink->Flink;
+ }
+ }
+
+ Adapter->ResetInProgress = TRUE;
+
+ //
+ // Loop through the loopback queue and abort any pending sends
+ //
+
+ {
+ PNDIS_PACKET AbortPacket;
+ PLOOP_PACKET_RESERVED Reserved;
+ PLOOP_OPEN Open;
+
+ while (Adapter->Loopback != NULL) {
+
+ AbortPacket = Adapter->Loopback;
+ Reserved = PLOOP_RESERVED_FROM_PACKET(AbortPacket);
+ Adapter->Loopback = Reserved->Next;
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ AbortPacket,
+ NDIS_STATUS_REQUEST_ABORTED
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ }
+
+ Adapter->CurrentLoopback = NULL;
+ Adapter->LastLoopback = NULL;
+ }
+
+ //
+ // notify all bindings of reset end
+ //
+ {
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink;
+
+ CurrentLink = Adapter->OpenBindings.Flink;
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("Signaling reset end to binding %lx\n",Open));
+
+ if (Open->BindingClosing) {
+ CurrentLink = CurrentLink->Flink;
+ continue;
+ }
+ Open->References++;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisIndicateStatus(
+ Open->NdisBindingContext,
+ NDIS_STATUS_RESET_END,
+ NULL,
+ 0
+ );
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+ CurrentLink = CurrentLink->Flink;
+ }
+ }
+
+ Open->References--;
+ Adapter->ResetInProgress = FALSE;
+
+ }
+ else
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return Status;
+}
+
+
+NDIS_STATUS
+LoopTransferData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopTransferData\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+ PLOOP_OPEN Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingClosing) {
+
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ if (MacReceiveContext == NULL) {
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ Adapter->CurrentLoopback,
+ ByteOffset+(PLOOP_RESERVED_FROM_PACKET(Adapter->CurrentLoopback)->HeaderLength),
+ BytesTransferred
+ );
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ }
+ else {
+
+ //
+ // shouldn't get here as we never pass a non-NULL receive context
+ //
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_FATAL,
+ ("transfer data failed! passed a receive context of %lx\n",MacReceiveContext));
+ StatusToReturn = NDIS_STATUS_FAILURE;
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Open->References--;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_REQUEST_ABORTED;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return StatusToReturn;
+}
+
+
+VOID
+LoopUnload(
+ IN NDIS_HANDLE MacMacContext
+ )
+{
+ NDIS_STATUS Status;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopUnload\n"));
+
+ NdisDeregisterMac(
+ &Status,
+ LoopMacHandle
+ );
+ NdisTerminateWrapper(
+ LoopWrapperHandle,
+ NULL
+ );
+}
+
+STATIC
+NDIS_STATUS
+LoopRegisterAdapter(
+ IN NDIS_HANDLE LoopMacHandle,
+ IN PNDIS_STRING AdapterName,
+ IN NDIS_MEDIUM AdapterMedium,
+ IN PVOID NetAddress,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+{
+static const MEDIA_INFO MediaParams[] = {
+ /* NdisMedium802_3 */ { 1500, 14, PACKET_FILTER_802_3, 100000},
+ /* NdisMedium802_5 */ { 4082, 14, PACKET_FILTER_802_5, 40000},
+ /* NdisMediumFddi */ { 4486, 13, PACKET_FILTER_FDDI, 1000000},
+ /* NdisMediumWan */ { 0, 0, 0, 0},
+ /* NdisMediumLocalTalk */ { 600, 3, PACKET_FILTER_LTALK, 2300},
+ /* NdisMediumDix */ { 1500, 14, PACKET_FILTER_DIX, 100000},
+ /* NdisMediumArcnetRaw */ { 1512, 3, PACKET_FILTER_ARCNET, 25000},
+ /* NdisMediumArcnet878_2 */ {1512, 3, PACKET_FILTER_ARCNET, 25000} };
+
+ //
+ // Pointer to the adapter
+ //
+ PLOOP_ADAPTER Adapter;
+
+ //
+ // status of various NDIS calls
+ //
+ NDIS_STATUS Status;
+
+ //
+ // info for registering the adapter
+ //
+ NDIS_ADAPTER_INFORMATION AdapterInfo;
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, (" --> LoopRegisterAdapter\n"));
+
+ //
+ // allocate the adapter block
+ //
+ NdisAllocateMemory(
+ (PVOID)&Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0,
+ physicalConst
+ );
+
+ if (Adapter != NULL) {
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, ("new Adapter = %lx\n",Adapter));
+
+ NdisZeroMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER)
+ );
+ Adapter->NdisMacHandle = LoopMacHandle;
+
+ //
+ // allocate memory for the name of the device
+ //
+
+ NdisAllocateMemory(
+ (PVOID)&Adapter->DeviceName.Buffer,
+ AdapterName->Length+2,
+ 0,
+ physicalConst
+ );
+
+ if (Adapter->DeviceName.Buffer != NULL) {
+
+ Adapter->DeviceNameLength = AdapterName->Length+2;
+ Adapter->DeviceName.MaximumLength = AdapterName->Length+2;
+ NdisZeroMemory(
+ Adapter->DeviceName.Buffer,
+ AdapterName->Length+2
+ );
+
+ #ifdef NDIS_NT
+
+ RtlCopyUnicodeString(
+ &Adapter->DeviceName,
+ AdapterName
+ );
+
+ #else
+
+ #error Need to copy a NDIS_STRING.
+
+ #endif
+
+ //
+ // set up the AdapterInfo structure
+ //
+
+ NdisZeroMemory(
+ &AdapterInfo,
+ sizeof(NDIS_ADAPTER_INFORMATION)
+ );
+ AdapterInfo.DmaChannel = 0;
+ AdapterInfo.Master = FALSE;
+ AdapterInfo.Dma32BitAddresses = FALSE;
+ AdapterInfo.AdapterType = NdisInterfaceInternal;
+ AdapterInfo.PhysicalMapRegistersNeeded = 0;
+ AdapterInfo.MaximumPhysicalMapping = 0;
+ AdapterInfo.NumberOfPortDescriptors = 0;
+
+ if ((Status = NdisRegisterAdapter(
+ &Adapter->NdisAdapterHandle,
+ Adapter->NdisMacHandle,
+ Adapter,
+ ConfigurationHandle,
+ AdapterName,
+ &AdapterInfo
+ )) == NDIS_STATUS_SUCCESS) {
+
+ InitializeListHead(&Adapter->OpenBindings);
+ Adapter->OpenCount = 0;
+
+ NdisAllocateSpinLock(&Adapter->Lock);
+ Adapter->InTimerProc = FALSE;
+ Adapter->TimerSet = FALSE;
+ Adapter->References = 1;
+ Adapter->Loopback = NULL;
+ Adapter->LastLoopback = NULL;
+ Adapter->CurrentLoopback = NULL;
+ NdisZeroMemory(
+ &Adapter->LoopBuffer,
+ LOOP_MAX_LOOKAHEAD
+ );
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->MaxLookAhead = 0;
+
+ Adapter->Medium = AdapterMedium;
+ Adapter->MediumLinkSpeed = MediaParams[(UINT)AdapterMedium].LinkSpeed;
+ Adapter->MediumMinPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
+ Adapter->MediumMaxPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen+
+ MediaParams[(UINT)AdapterMedium].MaxFrameLen;
+ Adapter->MediumMacHeaderLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
+ Adapter->MediumMaxFrameLen = MediaParams[(UINT)AdapterMedium].MaxFrameLen;
+ Adapter->MediumPacketFilters = MediaParams[(UINT)AdapterMedium].PacketFilters;
+
+ switch (AdapterMedium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ NdisMoveMemory(
+ (PVOID)&Adapter->PermanentAddress,
+ LOOP_ETH_CARD_ADDRESS,
+ ETH_LENGTH_OF_ADDRESS
+ );
+
+ if (NetAddress != NULL) {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ NetAddress,
+ ETH_LENGTH_OF_ADDRESS
+ );
+ }
+ else {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ LOOP_ETH_CARD_ADDRESS,
+ ETH_LENGTH_OF_ADDRESS
+ );
+ }
+
+ Status = (NDIS_STATUS)EthCreateFilter(
+ LOOP_ETH_MAX_MULTICAST_ADDRESS,
+ LoopEthChangeAddress,
+ LoopChangeFilter,
+ LoopCloseAction,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->Filter.Eth
+ );
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("new EthFilter = %lx\n",Adapter->Filter.Eth));
+ break;
+
+ case NdisMedium802_5:
+
+ NdisMoveMemory(
+ (PVOID)&Adapter->PermanentAddress,
+ LOOP_TR_CARD_ADDRESS,
+ TR_LENGTH_OF_ADDRESS
+ );
+
+ if (NetAddress != NULL) {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ NetAddress,
+ TR_LENGTH_OF_ADDRESS
+ );
+ }
+ else {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ LOOP_TR_CARD_ADDRESS,
+ TR_LENGTH_OF_ADDRESS
+ );
+ }
+
+ Status = (NDIS_STATUS)TrCreateFilter(
+ LoopTrChangeAddress,
+ LoopTrChangeAddress,
+ LoopChangeFilter,
+ LoopCloseAction,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->Filter.Tr
+ );
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("new TrFilter = %lx\n",Adapter->Filter.Tr));
+ break;
+
+ case NdisMediumFddi:
+
+ // the short address will simply be the first 2
+ // bytes of the long address
+
+ NdisMoveMemory(
+ (PVOID)&Adapter->PermanentAddress,
+ LOOP_FDDI_CARD_ADDRESS,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ if (NetAddress != NULL) {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ NetAddress,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+ }
+ else {
+ NdisMoveMemory(
+ (PVOID)&Adapter->CurrentAddress,
+ LOOP_FDDI_CARD_ADDRESS,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+ }
+
+ Status = (NDIS_STATUS)FddiCreateFilter(
+ LOOP_FDDI_MAX_MULTICAST_LONG,
+ LOOP_FDDI_MAX_MULTICAST_SHORT,
+ LoopFddiChangeAddress,
+ LoopChangeFilter,
+ LoopCloseAction,
+ Adapter->CurrentAddress,
+ Adapter->CurrentAddress,
+ &Adapter->Lock,
+ &Adapter->Filter.Fddi
+ );
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
+ ("new FddiFilter = %lx\n",Adapter->Filter.Fddi));
+ break;
+
+ case NdisMediumLocalTalk:
+
+ Adapter->PermanentAddress[0] = LOOP_LTALK_CARD_ADDRESS;
+
+ if (NetAddress != NULL)
+ Adapter->CurrentAddress[0] = ((PUCHAR)NetAddress)[0];
+ else
+ Adapter->CurrentAddress[0] = LOOP_LTALK_CARD_ADDRESS;
+
+ // dumb line to satisfy the following status check
+ Status = (NDIS_STATUS)TRUE;
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ Adapter->PermanentAddress[0] = LOOP_ARC_CARD_ADDRESS;
+
+ if (NetAddress != NULL)
+ Adapter->CurrentAddress[0] = ((PUCHAR)NetAddress)[0];
+ else
+ Adapter->CurrentAddress[0] = LOOP_ARC_CARD_ADDRESS;
+
+ // dumb line to satisfy the following status check
+ Status = (NDIS_STATUS)TRUE;
+
+ break;
+
+ default:
+ // shouldn't get here...
+ ASSERTMSG("LoopRegisterAdapter: received invalid medium\n",FALSE);
+ break;
+ }
+
+ if (!Status) {
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to configure media specific information\n",AdapterName));
+
+ NdisWriteErrorLogEntry(
+ Adapter->NdisAdapterHandle,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 0
+ );
+
+ NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
+
+ NdisFreeSpinLock(&Adapter->Lock);
+
+ NdisFreeMemory(
+ Adapter->DeviceName.Buffer,
+ Adapter->DeviceNameLength,
+ 0
+ );
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ NdisInitializeTimer(
+ &(Adapter->LoopTimer),
+ LoopTimerProc,
+ (PVOID)Adapter
+ );
+
+ NdisZeroMemory(
+ &Adapter->GeneralMandatory,
+ GM_ARRAY_SIZE * sizeof(ULONG)
+ );
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+ else {
+
+ //
+ // NdisRegisterAdapter failed
+ //
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to register adapter, Error = %x\n",AdapterName,Status));
+
+ NdisFreeMemory(
+ Adapter->DeviceName.Buffer,
+ Adapter->DeviceNameLength,
+ 0
+ );
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+
+ return Status;
+ }
+
+ }
+ else {
+
+ //
+ // failed to allocate device name
+ //
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to allocate the device name\n",AdapterName));
+
+ NdisFreeMemory(
+ Adapter,
+ sizeof(LOOP_ADAPTER),
+ 0
+ );
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ }
+
+ else {
+
+ //
+ // failed to allocate Adapter object
+ //
+
+ DBGPRINT(DBG_COMP_MEMORY,DBG_LEVEL_FATAL,
+ ("%wS: Unable to allocate the adapter object\n",AdapterName));
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+LoopChangeFilter(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopChangeFilter\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
+
+STATIC
+VOID
+LoopCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+{
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopCloseAction\n"));
+
+ PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
+}
+
+STATIC
+NDIS_STATUS
+LoopEthChangeAddress(
+ IN UINT OldFilterCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewFilterCouunt,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopEthChangeAddress\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
+
+STATIC
+NDIS_STATUS
+LoopTrChangeAddress(
+ IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddresses,
+ IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddresses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopTrChangeAddress\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
+
+STATIC
+NDIS_STATUS
+LoopFddiChangeAddress(
+ IN UINT OldLongAddressCount,
+ IN CHAR OldLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT NewLongAddressCouunt,
+ IN CHAR NewLongAddresses[][FDDI_LENGTH_OF_LONG_ADDRESS],
+ IN UINT OldShortAddressCount,
+ IN CHAR OldShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN UINT NewShortAddressCouunt,
+ IN CHAR NewShortAddresses[][FDDI_LENGTH_OF_SHORT_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_MISC, DBG_LEVEL_INFO, (" --> LoopFddiChangeAddress\n"));
+
+ if (!Adapter->ResetInProgress)
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ return StatusToReturn;
+}
diff --git a/private/ntos/ndis/loop/loop.h b/private/ntos/ndis/loop/loop.h
new file mode 100644
index 000000000..6df8f7f80
--- /dev/null
+++ b/private/ntos/ndis/loop/loop.h
@@ -0,0 +1,223 @@
+// STATIC is used for items which will be static in the release build
+// but we want visible for debugging
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#define LOOP_MAJOR_VERSION 0x1
+#define LOOP_MINOR_VERSION 0x0
+
+#define LOOP_NDIS_MAJOR_VERSION 0x3
+#define LOOP_NDIS_MINOR_VERSION 0x0
+
+#define LOOP_ETH_CARD_ADDRESS " LOOP "
+#define LOOP_ETH_MAX_MULTICAST_ADDRESS 16
+#define LOOP_TR_CARD_ADDRESS " LOOP "
+#define LOOP_FDDI_CARD_ADDRESS " LOOP "
+#define LOOP_FDDI_MAX_MULTICAST_LONG 16
+#define LOOP_FDDI_MAX_MULTICAST_SHORT 16
+#define LOOP_LTALK_CARD_ADDRESS 0xAB
+#define LOOP_ARC_CARD_ADDRESS 'L'
+// arbitrary maximums...
+#define LOOP_MAX_LOOKAHEAD 256
+#define LOOP_INDICATE_MAXIMUM 256
+
+#define OID_TYPE_MASK 0xFFFF0000
+#define OID_TYPE 0xFF000000
+#define OID_TYPE_GENERAL 0x00000000
+#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000
+#define OID_TYPE_GENERAL_STATISTICS 0x00020000
+#define OID_TYPE_802_3 0x01000000
+#define OID_TYPE_802_3_OPERATIONAL 0x01010000
+#define OID_TYPE_802_3_STATISTICS 0x01020000
+#define OID_TYPE_802_5 0x02000000
+#define OID_TYPE_802_5_OPERATIONAL 0x02010000
+#define OID_TYPE_802_5_STATISTICS 0x02020000
+#define OID_TYPE_FDDI 0x03000000
+#define OID_TYPE_FDDI_OPERATIONAL 0x03010000
+#define OID_TYPE_LTALK 0x05000000
+#define OID_TYPE_LTALK_OPERATIONAL 0x05010000
+#define OID_TYPE_ARCNET 0x06000000
+#define OID_TYPE_ARCNET_OPERATIONAL 0x06010000
+
+#define OID_REQUIRED_MASK 0x0000FF00
+#define OID_REQUIRED_MANDATORY 0x00000100
+#define OID_REQUIRED_OPTIONAL 0x00000200
+
+#define OID_INDEX_MASK 0x000000FF
+
+#define GM_TRANSMIT_GOOD 0x00
+#define GM_RECEIVE_GOOD 0x01
+#define GM_TRANSMIT_BAD 0x02
+#define GM_RECEIVE_BAD 0x03
+#define GM_RECEIVE_NO_BUFFER 0x04
+#define GM_ARRAY_SIZE 0x05
+
+#define LOOP_LT_IS_BROADCAST(Address) \
+ (BOOLEAN)(Address == 0xFF)
+
+#define LOOP_ARC_IS_BROADCAST(Address) \
+ (BOOLEAN)(!(Address))
+
+typedef
+struct _MEDIA_INFO {
+ ULONG MaxFrameLen;
+ UINT MacHeaderLen;
+ ULONG PacketFilters;
+ ULONG LinkSpeed;
+} MEDIA_INFO, *PMEDIA_INFO;
+
+typedef
+struct _LOOP_ADAPTER {
+
+ // this adapter's name
+ NDIS_STRING DeviceName;
+ UINT DeviceNameLength;
+
+ // MP and syncronization variables
+ NDIS_SPIN_LOCK Lock;
+ NDIS_TIMER LoopTimer;
+ BOOLEAN InTimerProc;
+ BOOLEAN TimerSet;
+
+ // reference count
+ UINT References;
+
+ // List of Bindings
+ UINT OpenCount;
+ LIST_ENTRY OpenBindings;
+
+ // the rest of the adapters
+ LIST_ENTRY AdapterList;
+
+ // handles for the adapter and mac driver
+ NDIS_HANDLE NdisMacHandle;
+ NDIS_HANDLE NdisAdapterHandle;
+
+ // loopback params
+ PNDIS_PACKET Loopback;
+ PNDIS_PACKET LastLoopback;
+ PNDIS_PACKET CurrentLoopback;
+ UCHAR LoopBuffer[LOOP_MAX_LOOKAHEAD];
+
+ BOOLEAN ResetInProgress;
+ UINT MaxLookAhead;
+
+ // media specific info
+ UCHAR PermanentAddress[6];
+ UCHAR CurrentAddress[6];
+ NDIS_MEDIUM Medium;
+ ULONG MediumLinkSpeed;
+ ULONG MediumMinPacketLen;
+ ULONG MediumMaxPacketLen;
+ UINT MediumMacHeaderLen;
+ ULONG MediumMaxFrameLen;
+ ULONG MediumPacketFilters;
+ union {
+ PETH_FILTER Eth;
+ PTR_FILTER Tr;
+ PFDDI_FILTER Fddi;
+ } Filter;
+
+ // statistics
+ ULONG GeneralMandatory[GM_ARRAY_SIZE];
+} LOOP_ADAPTER, *PLOOP_ADAPTER;
+
+#define BINDING_OPEN 0x00000001
+#define BINDING_CLOSING 0x00000002
+#define BINDING_RECEIVED_PACKET 0x00000004
+
+typedef
+struct _LOOP_OPEN {
+ LIST_ENTRY OpenList;
+ BOOLEAN BindingClosing;
+ UINT Flags;
+ PLOOP_ADAPTER OwningLoop;
+ NDIS_HANDLE NdisBindingContext;
+ NDIS_HANDLE NdisFilterHandle;
+ UINT References;
+ UINT CurrentLookAhead;
+ UINT CurrentPacketFilter;
+} LOOP_OPEN, *PLOOP_OPEN;
+
+typedef struct _LOOP_PACKET_RESERVED {
+ PNDIS_PACKET Next;
+ NDIS_HANDLE MacBindingHandle;
+ USHORT PacketLength;
+ UCHAR HeaderLength;
+} LOOP_PACKET_RESERVED, *PLOOP_PACKET_RESERVED;
+
+//
+// Given a MacBindingHandle this macro returns a pointer to the
+// LOOP_ADAPTER.
+//
+#define PLOOP_ADAPTER_FROM_BINDING_HANDLE(Handle) \
+ (((PLOOP_OPEN)((PVOID)(Handle)))->OwningLoop)
+
+//
+// Given a MacContextHandle return the PLOOP_ADAPTER
+// it represents.
+//
+#define PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PLOOP_ADAPTER)((PVOID)(Handle)))
+
+//
+// Given a pointer to a LOOP_ADAPTER return the
+// proper MacContextHandle.
+//
+#define CONTEXT_HANDLE_FROM_PLOOP_ADAPTER(Ptr) \
+ ((NDIS_HANDLE)((PVOID)(Ptr)))
+
+//
+// This macro returns a pointer to a PLOOP_OPEN given a MacBindingHandle.
+//
+#define PLOOP_OPEN_FROM_BINDING_HANDLE(Handle) \
+ ((PLOOP_OPEN)((PVOID)Handle))
+
+//
+// This macro returns a NDIS_HANDLE from a PLOOP_OPEN
+//
+#define BINDING_HANDLE_FROM_PLOOP_OPEN(Open) \
+ ((NDIS_HANDLE)((PVOID)Open))
+
+//
+// This macro returns a pointer to the LOOP reserved portion of the packet
+//
+#define PLOOP_RESERVED_FROM_PACKET(Packet) \
+ ((PLOOP_PACKET_RESERVED)((PVOID)((Packet)->MacReserved)))
+
+#define PLOOP_PACKET_FROM_RESERVED(Reserved) \
+ ((PNDIS_PACKET)((PVOID)((Reserved)->Packet)))
+
+extern
+NDIS_STATUS
+LoopQueryGlobalStats(
+ IN NDIS_HANDLE MacBindingContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+NDIS_STATUS
+LoopRequest(
+ IN NDIS_HANDLE MacBindingContext,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+NDIS_STATUS
+LoopSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ );
+
+extern
+VOID
+LoopTimerProc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
diff --git a/private/ntos/ndis/loop/loop.rc b/private/ntos/ndis/loop/loop.rc
new file mode 100644
index 000000000..5761474d9
--- /dev/null
+++ b/private/ntos/ndis/loop/loop.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Loopback network driver"
+#define VER_INTERNALNAME_STR "LOOP.SYS"
+#define VER_ORIGINALFILENAME_STR "LOOP.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/loop/makefile b/private/ntos/ndis/loop/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/ndis/loop/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/loop/request.c b/private/ntos/ndis/loop/request.c
new file mode 100644
index 000000000..e0bc9e151
--- /dev/null
+++ b/private/ntos/ndis/loop/request.c
@@ -0,0 +1,1255 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#include "debug.h"
+#include "loop.h"
+
+STATIC NDIS_OID LoopGlobalSupportedOids[] = {
+
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+ OID_802_5_LAST_OPEN_STATUS,
+ OID_802_5_CURRENT_RING_STATUS,
+ OID_802_5_CURRENT_RING_STATE,
+
+ OID_802_5_LINE_ERRORS,
+ OID_802_5_LOST_FRAMES,
+
+ OID_FDDI_LONG_PERMANENT_ADDR,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ OID_FDDI_SHORT_PERMANENT_ADDR,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+
+ OID_LTALK_CURRENT_NODE_ID,
+
+ OID_ARCNET_PERMANENT_ADDRESS,
+ OID_ARCNET_CURRENT_ADDRESS
+
+ };
+
+
+STATIC NDIS_OID LoopProtocolSupportedOids[] = {
+
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ OID_802_5_PERMANENT_ADDRESS,
+ OID_802_5_CURRENT_ADDRESS,
+ OID_802_5_CURRENT_FUNCTIONAL,
+ OID_802_5_CURRENT_GROUP,
+
+ OID_FDDI_LONG_PERMANENT_ADDR,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ OID_FDDI_LONG_MULTICAST_LIST,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ OID_FDDI_SHORT_PERMANENT_ADDR,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ OID_FDDI_SHORT_MULTICAST_LIST,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+
+ OID_LTALK_CURRENT_NODE_ID,
+
+ OID_ARCNET_PERMANENT_ADDRESS,
+ OID_ARCNET_CURRENT_ADDRESS
+
+ };
+
+STATIC
+NDIS_STATUS
+LoopQueryInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN Global,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PUINT BytesWritten,
+ OUT PUINT BytesNeeded
+ );
+
+STATIC
+NDIS_STATUS
+LoopSetInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+STATIC
+VOID
+LoopAdjustLookahead(
+ IN PLOOP_ADAPTER Adapter
+ );
+
+STATIC
+ULONG
+LoopQueryPacketFilter(
+ IN PLOOP_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+LoopRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopRequest\n"));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (! Adapter->ResetInProgress) {
+ PLOOP_OPEN Open;
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, ("Request from binding %lx\n",Open));
+
+ if (! Open->BindingClosing) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestSetInformation:
+
+ Open->References++;
+ StatusToReturn = LoopSetInformation(
+ Adapter,
+ Open,
+ NdisRequest
+ );
+ Open->References--;
+ break;
+
+ case NdisRequestQueryInformation:
+
+ Open->References++;
+ StatusToReturn = LoopQueryInformation(
+ Adapter,
+ Open,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ FALSE,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+ Open->References--;
+ break;
+
+ default:
+
+ // Unkown request
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ } else {
+ StatusToReturn = NDIS_STATUS_CLOSING;
+ }
+ } else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+NDIS_STATUS
+LoopQueryGlobalStats(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ NDIS_STATUS StatusToReturn;
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopQueryGlobalStats\n"));
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, ("Request from adapter %lx\n",Adapter));
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (! Adapter->ResetInProgress) {
+
+ if (NdisRequest->RequestType == NdisRequestQueryStatistics) {
+
+ StatusToReturn = LoopQueryInformation(
+ Adapter,
+ NULL,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ TRUE,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten),
+ &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+ }
+ else
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ } else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ return StatusToReturn;
+
+}
+
+STATIC
+NDIS_STATUS
+LoopSetInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN PNDIS_REQUEST NdisRequest
+ )
+{
+ NDIS_STATUS StatusToReturn;
+ ULONG PacketFilter, CurrentLookahead;
+ NDIS_OID Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+ PVOID InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
+ INT InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopSetInformation\n"));
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
+ NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
+
+ //
+ // Now check for the most common OIDs
+ //
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, ("OID = %lx\n",Oid));
+ switch (Oid) {
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ } else {
+
+ NdisMoveMemory(
+ (PVOID)&PacketFilter,
+ InformationBuffer,
+ sizeof(ULONG)
+ );
+ }
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ StatusToReturn = EthFilterAdjust(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ StatusToReturn = TrFilterAdjust(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ StatusToReturn = FddiFilterAdjust(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ PacketFilter,
+ TRUE
+ );
+ break;
+
+ default:
+
+ if (PacketFilter == (PacketFilter & Adapter->MediumPacketFilters)) {
+
+ Open->CurrentPacketFilter = PacketFilter;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ } else
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+
+ break;
+ }
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = InformationBufferLength;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (InformationBufferLength != 4) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ }
+
+ NdisMoveMemory(
+ (PVOID)&CurrentLookahead,
+ InformationBuffer,
+ sizeof(ULONG)
+ );
+
+ if (CurrentLookahead > LOOP_MAX_LOOKAHEAD) {
+
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+
+ }
+
+ if (CurrentLookahead >= Adapter->MaxLookAhead)
+ Adapter->MaxLookAhead = CurrentLookahead;
+ else {
+ if (Open->CurrentLookAhead == Adapter->MaxLookAhead)
+ LoopAdjustLookahead(Adapter);
+ }
+
+ Open->CurrentLookAhead = CurrentLookahead;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ NdisRequest->DATA.SET_INFORMATION.BytesRead = 4;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (Adapter->Medium != NdisMedium802_3) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if ((InformationBufferLength % ETH_LENGTH_OF_ADDRESS) != 0) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = EthChangeFilterAddresses(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ (UINT)(InformationBufferLength/ETH_LENGTH_OF_ADDRESS),
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (Adapter->Medium != NdisMedium802_5) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = TrChangeFunctionalAddress(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ if (Adapter->Medium != NdisMedium802_5) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = TrChangeGroupAddress(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ if (Adapter->Medium != NdisMediumFddi) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if ((InformationBufferLength % FDDI_LENGTH_OF_LONG_ADDRESS) != 0) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = FddiChangeFilterLongAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ (UINT)(InformationBufferLength/FDDI_LENGTH_OF_LONG_ADDRESS),
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ if (Adapter->Medium != NdisMediumFddi) {
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if ((InformationBufferLength % FDDI_LENGTH_OF_SHORT_ADDRESS) != 0) {
+ StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ StatusToReturn = FddiChangeFilterShortAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ NdisRequest,
+ (UINT)(InformationBufferLength/FDDI_LENGTH_OF_SHORT_ADDRESS),
+ InformationBuffer,
+ TRUE
+ );
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ StatusToReturn = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+ return(StatusToReturn);
+
+}
+
+STATIC
+NDIS_STATUS
+LoopQueryInformation(
+ IN PLOOP_ADAPTER Adapter,
+ IN PLOOP_OPEN Open,
+ IN NDIS_OID Oid,
+ IN BOOLEAN Global,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PUINT BytesWritten,
+ OUT PUINT BytesNeeded
+ )
+{
+
+ INT i;
+ PNDIS_OID SupportedOidArray;
+ INT SupportedOids;
+ PVOID SourceBuffer;
+ UINT SourceBufferLength;
+ ULONG GenericUlong;
+ USHORT GenericUshort;
+ static UCHAR VendorDescription[] = "MS LoopBack Driver";
+ static UCHAR VendorId[3] = {0xFF, 0xFF, 0xFF};
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO, (" --> LoopQueryInformation\n"));
+
+ DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
+ ("OID = %lx, Global = %c\n",Oid,(Global)?'Y':'N'));
+
+ //
+ // Check that the OID is valid.
+ //
+
+ if (Global) {
+ SupportedOidArray = LoopGlobalSupportedOids;
+ SupportedOids = sizeof(LoopGlobalSupportedOids)/sizeof(ULONG);
+ }
+ else {
+ SupportedOidArray = LoopProtocolSupportedOids;
+ SupportedOids = sizeof(LoopProtocolSupportedOids)/sizeof(ULONG);
+ }
+
+ for (i=0; i<SupportedOids; i++) {
+ if (Oid == SupportedOidArray[i])
+ break;
+ }
+
+ if ((i == SupportedOids) || (((Oid & OID_TYPE) != OID_TYPE_GENERAL) &&
+ (((Adapter->Medium == NdisMedium802_3) && ((Oid & OID_TYPE) != OID_TYPE_802_3)) ||
+ ((Adapter->Medium == NdisMedium802_5) && ((Oid & OID_TYPE) != OID_TYPE_802_5)) ||
+ ((Adapter->Medium == NdisMediumFddi) && ((Oid & OID_TYPE) != OID_TYPE_FDDI)) ||
+ ((Adapter->Medium == NdisMediumLocalTalk) && ((Oid & OID_TYPE) != OID_TYPE_LTALK)) ||
+ ((Adapter->Medium == NdisMediumArcnet878_2) && ((Oid & OID_TYPE) != OID_TYPE_ARCNET))))) {
+ *BytesWritten = 0;
+ return NDIS_STATUS_INVALID_OID;
+ }
+
+ //
+ // Initialize these once, since this is the majority
+ // of cases.
+ //
+
+ SourceBuffer = (PVOID)&GenericUlong;
+ SourceBufferLength = sizeof(ULONG);
+
+ switch (Oid & OID_TYPE_MASK) {
+
+ case OID_TYPE_GENERAL_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(0);
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ SourceBuffer = SupportedOidArray;
+ SourceBufferLength = SupportedOids * sizeof(ULONG);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ if (Adapter->ResetInProgress)
+ GenericUlong = NdisHardwareStatusReset;
+ else
+ GenericUlong = NdisHardwareStatusReady;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ GenericUlong = Adapter->Medium;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericUlong = LOOP_MAX_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = Adapter->MediumMaxFrameLen;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = Adapter->MediumLinkSpeed;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = Adapter->MediumMaxPacketLen;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = Adapter->MediumMaxPacketLen;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericUlong = 1;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericUlong = 1;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ SourceBuffer = VendorId;
+ SourceBufferLength = sizeof(VendorId);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ SourceBuffer = VendorDescription;
+ SourceBufferLength = sizeof(VendorDescription);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ if (Global)
+ GenericUlong = ETH_QUERY_FILTER_CLASSES(Adapter->Filter.Eth);
+ else
+ GenericUlong = ETH_QUERY_PACKET_FILTER(Adapter->Filter.Eth,
+ Open->NdisFilterHandle);
+ break;
+ case NdisMedium802_5:
+ if (Global)
+ GenericUlong = TR_QUERY_FILTER_CLASSES(Adapter->Filter.Tr);
+ else
+ GenericUlong = TR_QUERY_PACKET_FILTER(Adapter->Filter.Tr,
+ Open->NdisFilterHandle);
+ break;
+ case NdisMediumFddi:
+ if (Global)
+ GenericUlong = FDDI_QUERY_FILTER_CLASSES(Adapter->Filter.Fddi);
+ else
+ GenericUlong = FDDI_QUERY_PACKET_FILTER(Adapter->Filter.Fddi,
+ Open->NdisFilterHandle);
+ break;
+ default:
+ if (Global)
+ GenericUlong = LoopQueryPacketFilter(Adapter);
+ else
+ GenericUlong = Open->CurrentPacketFilter;
+ break;
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (Global)
+ GenericUlong = Adapter->MaxLookAhead;
+ else
+ GenericUlong = Open->CurrentLookAhead;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUshort = (LOOP_MAJOR_VERSION << 8) + LOOP_MINOR_VERSION;
+ SourceBuffer = &GenericUshort;
+ SourceBufferLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = Adapter->MediumMaxPacketLen;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_GENERAL_STATISTICS:
+
+ if (Global) {
+
+ NDIS_OID MaskOid = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ ASSERT (MaskOid < GM_ARRAY_SIZE);
+
+ GenericUlong = Adapter->GeneralMandatory[MaskOid];
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ } else {
+
+ //
+ // None of the general stats are available per-open.
+ //
+
+ ASSERT(FALSE);
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = ETH_LENGTH_OF_ADDRESS;
+ break;
+ case OID_802_3_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ {
+ NDIS_STATUS StatusToReturn;
+ UINT NumAddresses;
+
+ if (Global) {
+
+ NumAddresses = ETH_NUMBER_OF_GLOBAL_FILTER_ADDRESSES(Adapter->Filter.Eth);
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ EthQueryGlobalFilterAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Eth,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+
+ } else {
+
+ NumAddresses = EthNumberOfOpenFilterAddresses(
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * ETH_LENGTH_OF_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * ETH_LENGTH_OF_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ EthQueryOpenFilterAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Eth,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+ }
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = LOOP_ETH_MAX_MULTICAST_ADDRESS;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_802_3_STATISTICS:
+
+ switch (Oid) {
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ GenericUlong = 0;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_802_5_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_5_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = TR_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_5_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = TR_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_5_CURRENT_FUNCTIONAL:
+
+ if (Global)
+ GenericUlong = TR_QUERY_FILTER_ADDRESSES(Adapter->Filter.Tr);
+ else
+ GenericUlong = TR_QUERY_FILTER_BINDING_ADDRESS(
+ Adapter->Filter.Tr,
+ Open->NdisFilterHandle);
+
+ GenericUlong = (ULONG)(((GenericUlong >> 24) & 0xFF) |
+ ((GenericUlong >> 8) & 0xFF00) |
+ ((GenericUlong << 8) & 0xFF0000) |
+ ((GenericUlong << 24) & 0xFF000000));
+ break;
+
+ case OID_802_5_CURRENT_GROUP:
+
+ GenericUlong = TR_QUERY_FILTER_Group(Adapter->Filter.Tr);
+
+ GenericUlong = (ULONG)(((GenericUlong >> 24) & 0xFF) |
+ ((GenericUlong >> 8) & 0xFF00) |
+ ((GenericUlong << 8) & 0xFF0000) |
+ ((GenericUlong << 24) & 0xFF000000));
+ break;
+
+ case OID_802_5_LAST_OPEN_STATUS:
+
+ // just return 0 since we never return NDIS_STATUS_OPEN_ERROR
+
+ GenericUlong = 0;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATUS:
+
+ // need to verify validity
+
+ GenericUlong = NDIS_RING_SINGLE_STATION;
+ break;
+
+ case OID_802_5_CURRENT_RING_STATE:
+
+ // might want to return NdisRingStateClosed if there are no bindings
+
+ GenericUlong = NdisRingStateOpened;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_802_5_STATISTICS:
+
+ switch (Oid) {
+
+ case OID_802_5_LINE_ERRORS:
+ case OID_802_5_LOST_FRAMES:
+
+ GenericUlong = 0;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_FDDI_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_FDDI_LONG_PERMANENT_ADDR:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
+ break;
+
+ case OID_FDDI_LONG_CURRENT_ADDR:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
+ break;
+
+ case OID_FDDI_LONG_MULTICAST_LIST:
+
+ {
+ NDIS_STATUS StatusToReturn;
+ UINT NumAddresses;
+
+ if (Global) {
+
+ NumAddresses = FDDI_NUMBER_OF_GLOBAL_FILTER_LONG_ADDRESSES(Adapter->Filter.Fddi);
+ if ((NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryGlobalFilterLongAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+
+ } else {
+
+ NumAddresses = FddiNumberOfOpenFilterLongAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryOpenFilterLongAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+ }
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_FDDI_LONG_MAX_LIST_SIZE:
+
+ GenericUlong = LOOP_FDDI_MAX_MULTICAST_LONG;
+ break;
+
+ case OID_FDDI_SHORT_PERMANENT_ADDR:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ break;
+
+ case OID_FDDI_SHORT_CURRENT_ADDR:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ break;
+
+ case OID_FDDI_SHORT_MULTICAST_LIST:
+
+ {
+ NDIS_STATUS StatusToReturn;
+ UINT NumAddresses;
+
+ if (Global) {
+
+ NumAddresses = FDDI_NUMBER_OF_GLOBAL_FILTER_SHORT_ADDRESSES(Adapter->Filter.Fddi);
+ if ((NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryGlobalFilterShortAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+
+ } else {
+
+ NumAddresses = FddiNumberOfOpenFilterShortAddresses(
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle
+ );
+
+ if ((NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS) > InformationBufferLength) {
+
+ *BytesNeeded = (NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS);
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+ FddiQueryOpenFilterShortAddresses(
+ &StatusToReturn,
+ Adapter->Filter.Fddi,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &NumAddresses,
+ InformationBuffer
+ );
+ }
+
+ //
+ // Should not be an error since we held the spinlock
+ // nothing should have changed.
+ //
+
+ ASSERT(StatusToReturn == NDIS_STATUS_SUCCESS);
+
+ *BytesWritten = NumAddresses * FDDI_LENGTH_OF_SHORT_ADDRESS;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case OID_FDDI_SHORT_MAX_LIST_SIZE:
+
+ GenericUlong = LOOP_FDDI_MAX_MULTICAST_SHORT;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_LTALK_OPERATIONAL:
+
+ switch(Oid) {
+ case OID_LTALK_CURRENT_NODE_ID:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = 1;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ case OID_TYPE_ARCNET_OPERATIONAL:
+
+ switch(Oid) {
+ case OID_ARCNET_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentAddress;
+ SourceBufferLength = 1;
+ break;
+
+ case OID_ARCNET_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentAddress;
+ SourceBufferLength = 1;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ if (SourceBufferLength > InformationBufferLength) {
+ *BytesNeeded = SourceBufferLength;
+ return NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+
+ NdisMoveMemory(
+ InformationBuffer,
+ SourceBuffer,
+ SourceBufferLength);
+
+ *BytesWritten = SourceBufferLength;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+STATIC
+VOID
+LoopAdjustLookahead(
+ IN PLOOP_ADAPTER Adapter
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY OpenCurrentLink;
+ ULONG Lookahead=0;
+
+ OpenCurrentLink = Adapter->OpenBindings.Flink;
+
+ while(OpenCurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ OpenCurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ if (Open->CurrentLookAhead > Lookahead)
+ Lookahead = Open->CurrentLookAhead;
+
+ OpenCurrentLink = OpenCurrentLink->Flink;
+ }
+
+ Adapter->MaxLookAhead = Lookahead;
+}
+
+STATIC
+ULONG
+LoopQueryPacketFilter(
+ IN PLOOP_ADAPTER Adapter
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY OpenCurrentLink;
+ ULONG Filter=0;
+
+ OpenCurrentLink = Adapter->OpenBindings.Flink;
+
+ while(OpenCurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ OpenCurrentLink,
+ LOOP_OPEN,
+ OpenList
+ );
+
+ Filter |= Open->CurrentPacketFilter;
+ OpenCurrentLink = OpenCurrentLink->Flink;
+ }
+
+ return Filter;
+}
diff --git a/private/ntos/ndis/loop/send.c b/private/ntos/ndis/loop/send.c
new file mode 100644
index 000000000..8eda49360
--- /dev/null
+++ b/private/ntos/ndis/loop/send.c
@@ -0,0 +1,717 @@
+#include <ndis.h>
+#include <efilter.h>
+#include <tfilter.h>
+#include <ffilter.h>
+
+#include "debug.h"
+#include "loop.h"
+
+STATIC
+VOID
+LoopProcessLoopback(
+ PLOOP_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+LoopCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+STATIC
+VOID
+LtIndicateReceive(
+ IN PLOOP_ADAPTER Adapter,
+ IN UINT PacketType,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+STATIC
+VOID
+LtIndicateReceiveComplete(
+ IN PLOOP_ADAPTER Adapter
+ );
+
+
+NDIS_STATUS
+LoopSend(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_PACKET Packet
+ )
+{
+ PLOOP_ADAPTER Adapter = PLOOP_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ PLOOP_OPEN Open = PLOOP_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+ UINT PacketLength;
+ NDIS_STATUS StatusToReturn;
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, (" --> LoopSend\n"));
+
+ //
+ // Verify that the packet is correctly sized for the medium
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ NULL,
+ &PacketLength
+ );
+
+ if ((PacketLength < Adapter->MediumMinPacketLen) ||
+ (PacketLength > Adapter->MediumMaxPacketLen)) {
+
+ return NDIS_STATUS_INVALID_PACKET;
+
+ }
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ if (!Open->BindingClosing) {
+
+ PLOOP_PACKET_RESERVED Reserved = PLOOP_RESERVED_FROM_PACKET(Packet);
+ BOOLEAN LoopIt=FALSE;
+ PNDIS_BUFFER FirstBuffer;
+ PVOID BufferVirtualAddress;
+ UINT BufferLength;
+
+ Open->References++;
+
+ Reserved->Next = NULL;
+ Reserved->MacBindingHandle = MacBindingHandle;
+ Reserved->PacketLength = PacketLength;
+ Reserved->HeaderLength = Adapter->MediumMacHeaderLen;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &FirstBuffer,
+ NULL
+ );
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ &BufferVirtualAddress,
+ &BufferLength
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Ethernet Dest Addr: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ *((PUCHAR)BufferVirtualAddress),*((PUCHAR)BufferVirtualAddress+1),
+ *((PUCHAR)BufferVirtualAddress+2),*((PUCHAR)BufferVirtualAddress+3),
+ *((PUCHAR)BufferVirtualAddress+4),*((PUCHAR)BufferVirtualAddress+5)));
+
+ LoopIt = EthShouldAddressLoopBack(
+ Adapter->Filter.Eth,
+ BufferVirtualAddress
+ );
+ break;
+ case NdisMedium802_5:
+
+ // check for source routing info and adjust header
+
+ if (*((PUCHAR)BufferVirtualAddress+8) & 0x80)
+ Reserved->HeaderLength += (*((PUCHAR)BufferVirtualAddress+14) & 0x1f);
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("TokenRing Dest Addr: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ *((PUCHAR)BufferVirtualAddress+2),*((PUCHAR)BufferVirtualAddress+3),
+ *((PUCHAR)BufferVirtualAddress+4),*((PUCHAR)BufferVirtualAddress+5),
+ *((PUCHAR)BufferVirtualAddress+6),*((PUCHAR)BufferVirtualAddress+7)));
+
+ LoopIt = TrShouldAddressLoopBack(
+ Adapter->Filter.Tr,
+ (PCHAR)BufferVirtualAddress+2,
+ Adapter->CurrentAddress
+ );
+
+ if (!LoopIt) {
+
+ // check if it's directed at ourselves
+
+ TR_COMPARE_NETWORK_ADDRESSES_EQ(
+ (PUCHAR)BufferVirtualAddress+2,
+ (PUCHAR)(Adapter->Filter.Tr)->AdapterAddress,
+ &BufferLength
+ );
+ if (!BufferLength)
+ LoopIt = TRUE;
+ }
+
+ break;
+ case NdisMediumFddi:
+
+ // check the address length bit and adjust the header length
+ // if it is short. by default we assume a long address
+
+ if (!(*((PUCHAR)BufferVirtualAddress) & 0x40)) {
+ Reserved->HeaderLength = 2*FDDI_LENGTH_OF_SHORT_ADDRESS+1;
+ BufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
+ }
+ else
+ BufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
+
+ // hmmm... the DBGPRINT macro doesn't work too well to
+ // dump out dest addr of varying lengths
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Fddi Dest Addr: L(%d) %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",BufferLength,
+ *((PUCHAR)BufferVirtualAddress+1),*((PUCHAR)BufferVirtualAddress+2),
+ *((PUCHAR)BufferVirtualAddress+3),*((PUCHAR)BufferVirtualAddress+4),
+ *((PUCHAR)BufferVirtualAddress+5),*((PUCHAR)BufferVirtualAddress+6)));
+
+ LoopIt = FddiShouldAddressLoopBack(
+ Adapter->Filter.Fddi,
+ (PCHAR)BufferVirtualAddress+1,
+ BufferLength
+ );
+ break;
+ case NdisMediumWan:
+ case NdisMediumLocalTalk:
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("LocalTalk Dest Addr: %.2x\n",((PUCHAR)BufferVirtualAddress)[0]));
+
+ if ((((PUCHAR)BufferVirtualAddress)[1] == Adapter->CurrentAddress[0]) ||
+ LOOP_LT_IS_BROADCAST(((PUCHAR)BufferVirtualAddress)[0]))
+ LoopIt = TRUE;
+ else
+ LoopIt = FALSE;
+
+ break;
+ case NdisMediumArcnet878_2:
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Arcnet Dest Addr: %.2x\n",((PUCHAR)BufferVirtualAddress)[1]));
+
+ if ((((PUCHAR)BufferVirtualAddress)[1] == Adapter->CurrentAddress[0]) ||
+ LOOP_ARC_IS_BROADCAST(((PUCHAR)BufferVirtualAddress)[1]))
+ LoopIt = TRUE;
+ else
+ LoopIt = FALSE;
+
+ break;
+ default:
+ // we should never get here...
+ ASSERT(FALSE);
+ break;
+ }
+
+ DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO, ("LoopIt = %c\n",(LoopIt)?'Y':'N'));
+
+ if (LoopIt) {
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("Queueing packet %lx for loopback\n",Packet));
+
+ if (Adapter->LastLoopback == NULL)
+ Adapter->Loopback = Packet;
+ else
+ PLOOP_RESERVED_FROM_PACKET(Adapter->LastLoopback)->Next = Packet;
+ Adapter->LastLoopback = Packet;
+
+ StatusToReturn = NDIS_STATUS_PENDING;
+
+ }
+ else {
+ //
+ // Since we're not looping this packet back, there's
+ // nothing for us to do. just return success and make
+ // like the packet was successfully sent out
+ //
+
+ Adapter->GeneralMandatory[GM_TRANSMIT_GOOD]++;
+ Open->References--;
+ StatusToReturn = NDIS_STATUS_SUCCESS;
+ }
+ }
+ else
+ StatusToReturn = NDIS_STATUS_CLOSING;
+
+ }
+ else
+ StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ Adapter->References--;
+
+ // might not queue a packet, but setting the timer anyway ensures
+ // we don't miss any packets sitting in the queue
+
+ if (!Adapter->TimerSet) {
+ Adapter->TimerSet = TRUE;
+ NdisReleaseSpinLock(&Adapter->Lock);
+ NdisSetTimer(
+ &Adapter->LoopTimer,
+ 25
+ );
+ }
+ else
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ return StatusToReturn;
+}
+
+
+VOID
+LoopTimerProc(
+ IN PVOID SystemSpecific1,
+ IN PVOID Context,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+{
+ PLOOP_ADAPTER Adapter = (PLOOP_ADAPTER)Context;
+
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, (" --> LoopTimerProc\n"));
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+ Adapter->TimerSet = FALSE;
+
+ if ((Adapter->Loopback != NULL) && !Adapter->InTimerProc) {
+ Adapter->InTimerProc = TRUE;
+ LoopProcessLoopback(Adapter);
+ Adapter->InTimerProc = FALSE;
+ }
+
+ Adapter->References--;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+}
+
+
+STATIC
+VOID
+LoopProcessLoopback(
+ PLOOP_ADAPTER Adapter
+ )
+{
+ PNDIS_PACKET LoopPacket;
+ PLOOP_PACKET_RESERVED Reserved;
+ PLOOP_OPEN Open;
+ UINT BufferLength;
+ UINT IndicateLen;
+ UINT AddressType;
+ UCHAR DestAddress[FDDI_LENGTH_OF_LONG_ADDRESS];
+
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, (" --> LoopProcessLoopback\n"));
+
+ while ((Adapter->Loopback != NULL) && !Adapter->ResetInProgress) {
+
+ // dequeue the packet at the head of the loopback queue
+
+ LoopPacket = Adapter->Loopback;
+ Adapter->CurrentLoopback = LoopPacket;
+ Reserved = PLOOP_RESERVED_FROM_PACKET(LoopPacket);
+ Adapter->Loopback = Reserved->Next;
+ if (Adapter->Loopback == NULL)
+ Adapter->LastLoopback = NULL;
+
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, ("Dequeued packet %lx\n",LoopPacket));
+
+ IndicateLen = (Reserved->PacketLength > Adapter->MaxLookAhead) ?
+ Adapter->MaxLookAhead : Reserved->PacketLength;
+
+ Adapter->GeneralMandatory[GM_RECEIVE_GOOD]++;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ LoopCopyFromPacketToBuffer(
+ LoopPacket,
+ 0,
+ IndicateLen,
+ Adapter->LoopBuffer,
+ &BufferLength
+ );
+
+ // indicate the packet as appropriate
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ EthFilterIndicateReceive(
+ Adapter->Filter.Eth,
+ (NDIS_HANDLE)NULL,
+ (PCHAR)Adapter->LoopBuffer,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMedium802_5:
+ TrFilterIndicateReceive(
+ Adapter->Filter.Tr,
+ (NDIS_HANDLE)NULL,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMediumFddi:
+
+ // just copy over the long address size, even though it may
+ // be a short address
+
+ NdisMoveMemory(
+ DestAddress,
+ Adapter->LoopBuffer+1,
+ FDDI_LENGTH_OF_LONG_ADDRESS
+ );
+
+ FddiFilterIndicateReceive(
+ Adapter->Filter.Fddi,
+ (NDIS_HANDLE)NULL,
+ (PCHAR)DestAddress,
+ ((*(Adapter->LoopBuffer) & 0x40) ? FDDI_LENGTH_OF_LONG_ADDRESS :
+ FDDI_LENGTH_OF_SHORT_ADDRESS),
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMediumLocalTalk:
+ if (LOOP_LT_IS_BROADCAST(Adapter->LoopBuffer[0]))
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ else
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ LtIndicateReceive(
+ Adapter,
+ AddressType,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ case NdisMediumArcnet878_2:
+ if (LOOP_ARC_IS_BROADCAST(Adapter->LoopBuffer[1]))
+ AddressType = NDIS_PACKET_TYPE_BROADCAST;
+ else
+ AddressType = NDIS_PACKET_TYPE_DIRECTED;
+
+ LtIndicateReceive(
+ Adapter,
+ AddressType,
+ Adapter->LoopBuffer,
+ Reserved->HeaderLength,
+ (Adapter->LoopBuffer)+(Reserved->HeaderLength),
+ IndicateLen-(Reserved->HeaderLength),
+ (Reserved->PacketLength)-(Reserved->HeaderLength)
+ );
+ break;
+ default:
+ ASSERT(FALSE); // should never get here
+ break;
+ }
+
+ // complete the send
+
+ Open = PLOOP_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO,
+ ("Completing Send for binding %lx\n",Open));
+ NdisCompleteSend(
+ Open->NdisBindingContext,
+ LoopPacket,
+ NDIS_STATUS_SUCCESS
+ );
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Adapter->GeneralMandatory[GM_TRANSMIT_GOOD]++;
+ // remove reference for send just completed
+ Open->References--;
+ }
+
+ // rearm timer if there are still packets to loop back and the timer is
+ // not already ticking away
+
+ if (Adapter->Loopback != NULL && !Adapter->TimerSet) {
+ DBGPRINT(DBG_COMP_DPC, DBG_LEVEL_INFO, ("More packets to loopback\n"));
+ Adapter->TimerSet = TRUE;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ NdisSetTimer(
+ &Adapter->LoopTimer,
+ 25
+ );
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ }
+
+ // issue indicate receive completes as necessary
+
+ switch (Adapter->Medium) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ EthFilterIndicateReceiveComplete(Adapter->Filter.Eth);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ case NdisMedium802_5:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ TrFilterIndicateReceiveComplete(Adapter->Filter.Tr);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ case NdisMediumFddi:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ FddiFilterIndicateReceiveComplete(Adapter->Filter.Fddi);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ case NdisMediumLocalTalk:
+ case NdisMediumArcnet878_2:
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+ LtIndicateReceiveComplete(Adapter);
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ break;
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+}
+
+STATIC
+VOID
+LoopCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+{
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove = ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ NdisMoveMemory(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+ }
+
+ *BytesCopied = LocalBytesCopied;
+}
+
+
+STATIC
+VOID
+LtIndicateReceive(
+ IN PLOOP_ADAPTER Adapter,
+ IN UINT PacketType,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink = Adapter->OpenBindings.Flink;
+ NDIS_STATUS Status;
+
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList);
+
+ if (PacketType & Open->CurrentPacketFilter) {
+
+ NdisIndicateReceive(
+ &Status,
+ Open->NdisBindingContext,
+ NULL,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->Flags |= BINDING_RECEIVED_PACKET;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+ CurrentLink = CurrentLink->Flink;
+ }
+}
+
+
+STATIC
+VOID
+LtIndicateReceiveComplete(
+ IN PLOOP_ADAPTER Adapter
+ )
+{
+ PLOOP_OPEN Open;
+ PLIST_ENTRY CurrentLink = Adapter->OpenBindings.Flink;
+
+ while(CurrentLink != &Adapter->OpenBindings) {
+
+ Open = CONTAINING_RECORD(
+ CurrentLink,
+ LOOP_OPEN,
+ OpenList);
+
+ if (Open->Flags & BINDING_RECEIVED_PACKET) {
+
+ NdisIndicateReceiveComplete(Open->NdisBindingContext);
+
+ NdisDprAcquireSpinLock(&Adapter->Lock);
+ Open->Flags &= ~BINDING_RECEIVED_PACKET;
+ NdisDprReleaseSpinLock(&Adapter->Lock);
+
+ }
+
+ CurrentLink = CurrentLink->Flink;
+ }
+}
diff --git a/private/ntos/ndis/loop/sources b/private/ntos/ndis/loop/sources
new file mode 100644
index 000000000..9e1c063fb
--- /dev/null
+++ b/private/ntos/ndis/loop/sources
@@ -0,0 +1,20 @@
+MAJORCOMP=ntos
+MINORCOMP=ndis2
+
+TARGETNAME=loop
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc
+
+SOURCES=loop.c \
+ request.c \
+ send.c \
+ loop.rc
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+