diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/loop | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/ndis/loop')
-rw-r--r-- | private/ntos/ndis/loop/debug.h | 47 | ||||
-rw-r--r-- | private/ntos/ndis/loop/loop.c | 1378 | ||||
-rw-r--r-- | private/ntos/ndis/loop/loop.h | 223 | ||||
-rw-r--r-- | private/ntos/ndis/loop/loop.rc | 39 | ||||
-rw-r--r-- | private/ntos/ndis/loop/makefile | 6 | ||||
-rw-r--r-- | private/ntos/ndis/loop/request.c | 1255 | ||||
-rw-r--r-- | private/ntos/ndis/loop/send.c | 717 | ||||
-rw-r--r-- | private/ntos/ndis/loop/sources | 20 |
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 + |