From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/ndis/loop/send.c | 717 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100644 private/ntos/ndis/loop/send.c (limited to 'private/ntos/ndis/loop/send.c') 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 +#include +#include +#include + +#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; + } +} -- cgit v1.2.3