291 lines
6.7 KiB
C
291 lines
6.7 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
loopback.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the routines to implement loopback
|
||
|
||
Author:
|
||
|
||
Sanjay Anand (SanjayAn) 2/6/96
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// Global lock to control access to the Loopback queue
|
||
//
|
||
DEFINE_LOCK_STRUCTURE(LoopLock)
|
||
|
||
//
|
||
// Head and tail of the Loopback queue
|
||
//
|
||
PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL;
|
||
PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL;
|
||
|
||
CTEEvent LoopXmitEvent;
|
||
BOOLEAN LoopXmitRtnRunning = 0;
|
||
|
||
//
|
||
// MaximumPacket sized buffer to hold the lookahead data.
|
||
//
|
||
// In PnP this value can change
|
||
//
|
||
// PUCHAR LookaheadBuffer=NULL;
|
||
#define LOOP_LOOKAHEAD_SIZE 128 + sizeof(IPX_HEADER) + 8 + 34
|
||
|
||
|
||
VOID
|
||
IpxDoLoopback(
|
||
IN CTEEvent *Event,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Does the actual loopback.
|
||
|
||
Arguments:
|
||
|
||
Event - Pointer to event structure.
|
||
|
||
Context - Pointer to ZZ
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PNDIS_PACKET Packet; // Pointer to packet being transmitted
|
||
PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
|
||
ULONG TotalLength; // Total length of send.
|
||
ULONG LookaheadLength; // Bytes in lookahead.
|
||
ULONG Copied; // Bytes copied so far.
|
||
PUCHAR CopyPtr; // Pointer to buffer being copied into.
|
||
PUCHAR SrcPtr; // Pointer to buffer being copied from.
|
||
ULONG SrcLength; // Length of src buffer.
|
||
BOOLEAN Rcvd = FALSE;
|
||
PIPX_SEND_RESERVED Reserved;
|
||
ULONG MacSize;
|
||
PNDIS_PACKET *PacketPtr;
|
||
UCHAR LookaheadBuffer[LOOP_LOOKAHEAD_SIZE];
|
||
|
||
IPX_DEFINE_LOCK_HANDLE(Handle)
|
||
|
||
KIRQL OldIrql;
|
||
|
||
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
||
|
||
//
|
||
// Raise IRQL so we can acquire locks at DPC level in the receive code.
|
||
// Also to be able to ReceiveIndicate at DPC
|
||
//
|
||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
|
||
IPX_GET_LOCK(&LoopLock, &Handle);
|
||
|
||
if (LoopXmitRtnRunning) {
|
||
IPX_FREE_LOCK(&LoopLock, Handle);
|
||
KeLowerIrql(OldIrql);
|
||
return;
|
||
}
|
||
|
||
LoopXmitRtnRunning = 1;
|
||
|
||
for (;;) {
|
||
|
||
//
|
||
// Get the next packet from the list.
|
||
//
|
||
Packet = LoopXmitHead;
|
||
|
||
if (Packet != (PNDIS_PACKET)NULL) {
|
||
Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
|
||
LoopXmitHead = (PNDIS_PACKET)(Reserved->PaddingBuffer);
|
||
IPX_FREE_LOCK(&LoopLock, Handle);
|
||
} else { // Nothing left to do.
|
||
LoopXmitRtnRunning = 0;
|
||
IPX_FREE_LOCK(&LoopLock, Handle);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We use the PaddingBuffer section as the next ptr.
|
||
//
|
||
Reserved->PaddingBuffer = NULL;
|
||
|
||
IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
|
||
|
||
NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
|
||
|
||
NdisQueryBuffer(Buffer, NULL, &MacSize);
|
||
|
||
IPX_DEBUG(LOOPB, ("Buffer: %lx Totalpktlen: %lx MacSize: %lx\n", Buffer, TotalLength, MacSize));
|
||
|
||
LookaheadLength = MIN(LOOP_LOOKAHEAD_SIZE, TotalLength);
|
||
Copied = 0;
|
||
CopyPtr = LookaheadBuffer;
|
||
while (Copied < LookaheadLength) {
|
||
ULONG ThisCopy; // Bytes to copy this time.
|
||
|
||
#ifdef DBG
|
||
if (!Buffer) {
|
||
DbgBreakPoint();
|
||
IPX_GET_LOCK(&LoopLock, &Handle);
|
||
LoopXmitRtnRunning = 0;
|
||
IPX_FREE_LOCK(&LoopLock, Handle);
|
||
KeLowerIrql(OldIrql);
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
NdisQueryBufferSafe(Buffer, &SrcPtr, &SrcLength, HighPagePriority);
|
||
|
||
if (SrcPtr == NULL) {
|
||
DbgPrint("IpxDoLoopback: NdisQuerybufferSafe returned null pointer\n");
|
||
IPX_GET_LOCK(&LoopLock, &Handle);
|
||
LoopXmitRtnRunning = 0;
|
||
IPX_FREE_LOCK(&LoopLock, Handle);
|
||
KeLowerIrql(OldIrql);
|
||
return;
|
||
}
|
||
|
||
ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
|
||
CTEMemCopy(CopyPtr, SrcPtr, ThisCopy);
|
||
Copied += ThisCopy;
|
||
CopyPtr += ThisCopy;
|
||
NdisGetNextBuffer(Buffer, &Buffer);
|
||
}
|
||
|
||
Rcvd = TRUE;
|
||
|
||
#ifdef BACK_FILL
|
||
//
|
||
// For Backfill packets, the MAC header is not yet set up; for others, it is the size
|
||
// of the first MDL (17).
|
||
//
|
||
if ((Reserved->Identifier == IDENTIFIER_IPX) &&
|
||
(Reserved->BackFill)) {
|
||
MacSize = 0;
|
||
}
|
||
#endif
|
||
IpxReceiveIndication( (NDIS_HANDLE)IPX_LOOPBACK_COOKIE, // BindingContext
|
||
Packet, // ReceiveContext
|
||
(MacSize) ? LookaheadBuffer : NULL, // HeaderBuffer
|
||
MacSize, // HeaderBufferSize
|
||
LookaheadBuffer+MacSize, // LookAheadBuffer
|
||
LookaheadLength-MacSize, // LookAheadBufferSize
|
||
TotalLength-MacSize); // PacketSize
|
||
|
||
IpxSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
|
||
|
||
//
|
||
// Give other threads a chance to run.
|
||
//
|
||
KeLowerIrql(OldIrql);
|
||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
IPX_GET_LOCK(&LoopLock, &Handle);
|
||
}
|
||
|
||
if (Rcvd) {
|
||
IpxReceiveComplete(Context);
|
||
}
|
||
|
||
KeLowerIrql(OldIrql);
|
||
}
|
||
|
||
|
||
VOID
|
||
IpxInitLoopback()
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes various loopback structures.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
CTEInitLock(&LoopLock);
|
||
CTEInitEvent(&LoopXmitEvent, IpxDoLoopback);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
IpxLoopbackEnque(
|
||
IN PNDIS_PACKET Packet,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enqueues a packet to the loopbackQ
|
||
|
||
Arguments:
|
||
|
||
Packet - The packet to be enqueued.
|
||
|
||
Context - Pointer to the adapter corresp to the first binding.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
|
||
IPX_DEFINE_LOCK_HANDLE(LockHandle)
|
||
|
||
//
|
||
// We use the PaddingBuffer as the next ptr.
|
||
//
|
||
Reserved->PaddingBuffer = NULL;
|
||
|
||
IPX_GET_LOCK(&LoopLock, &LockHandle);
|
||
|
||
//
|
||
// LoopbackQ is empty
|
||
//
|
||
if (LoopXmitHead == (PNDIS_PACKET)NULL) {
|
||
LoopXmitHead = Packet;
|
||
} else {
|
||
Reserved = (PIPX_SEND_RESERVED)(LoopXmitTail->ProtocolReserved);
|
||
(PNDIS_PACKET)(Reserved->PaddingBuffer) = Packet;
|
||
}
|
||
LoopXmitTail = Packet;
|
||
|
||
IPX_DEBUG(LOOPB, ("Enqued packet: %lx, Reserved: %lx\n", Packet, Reserved));
|
||
|
||
//
|
||
// If this routine is not already running, schedule it as a work item.
|
||
//
|
||
if (!LoopXmitRtnRunning) {
|
||
CTEScheduleEvent(&LoopXmitEvent, Context);
|
||
}
|
||
|
||
IPX_FREE_LOCK(&LoopLock, LockHandle);
|
||
}
|