|
|
/*++
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); }
|