You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
6.9 KiB
290 lines
6.9 KiB
/*++
|
|
|
|
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);
|
|
}
|