summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/loop/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/loop/send.c')
-rw-r--r--private/ntos/ndis/loop/send.c717
1 files changed, 717 insertions, 0 deletions
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;
+ }
+}