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.
2202 lines
61 KiB
2202 lines
61 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
afilter.c
|
|
|
|
Abstract:
|
|
|
|
This module implements a set of library routines to handle packet
|
|
filtering for NDIS MAC drivers. It also provides routines for collecting fragmented packets and
|
|
breaking up a packet into fragmented packets
|
|
|
|
Author:
|
|
|
|
Alireza Dabagh 3-22-1993, (partially borrowed from EFILTER.C)
|
|
|
|
|
|
Revision History:
|
|
|
|
Jameel Hyder (JameelH) Re-organization 01-Jun-95
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#if ARCNET
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_AFILTER
|
|
|
|
//
|
|
// Given an NDIS_PACKET this macro will tell us if it is
|
|
// encapsulated ethernet.
|
|
//
|
|
#define ARC_PACKET_IS_ENCAPSULATED(_NSR) \
|
|
((_NSR)->Open->Flags & fMINIPORT_OPEN_USING_ETH_ENCAPSULATION)
|
|
|
|
//
|
|
// Defines for resource growth
|
|
//
|
|
#define ARC_BUFFER_SIZE 1024
|
|
#define ARC_BUFFER_ALLOCATION_UNIT 8
|
|
#define ARC_PACKET_ALLOCATION_UNIT 2
|
|
|
|
|
|
NDIS_STATUS
|
|
ArcAllocateBuffers(
|
|
IN PARC_FILTER Filter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates Receive buffers for the filter database.
|
|
|
|
Arguments:
|
|
|
|
Filter - The filter db to allocate for.
|
|
|
|
Returns:
|
|
|
|
NDIS_STATUS_SUCCESS if any buffer was allocated.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
PARC_BUFFER_LIST Buffer;
|
|
PVOID DataBuffer;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
|
|
for (i = ARC_BUFFER_ALLOCATION_UNIT; i != 0; i--)
|
|
{
|
|
Buffer = ALLOC_FROM_POOL(sizeof(ARC_BUFFER_LIST), NDIS_TAG_ARC_BUFFER);
|
|
if (Buffer == NULL)
|
|
{
|
|
if (i == ARC_BUFFER_ALLOCATION_UNIT)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DataBuffer = ALLOC_FROM_POOL(ARC_BUFFER_SIZE, NDIS_TAG_ARC_DATA);
|
|
|
|
if (DataBuffer == NULL)
|
|
{
|
|
FREE_POOL(Buffer);
|
|
|
|
if (i == ARC_BUFFER_ALLOCATION_UNIT)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
//
|
|
// We allocated some packets, that is good enough for now
|
|
//
|
|
break;
|
|
}
|
|
|
|
Buffer->BytesLeft = Buffer->Size = ARC_BUFFER_SIZE;
|
|
Buffer->Buffer = DataBuffer;
|
|
Buffer->Next = Filter->FreeBufferList;
|
|
Filter->FreeBufferList = Buffer;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArcAllocatePackets(
|
|
IN PARC_FILTER Filter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates Receive packets for the filter database.
|
|
|
|
Arguments:
|
|
|
|
Filter - The filter db to allocate for.
|
|
|
|
Returns:
|
|
|
|
NDIS_STATUS_SUCCESS if any packet was allocated.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
PARC_PACKET Packet;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
|
|
for (i = ARC_PACKET_ALLOCATION_UNIT; i != 0; i--)
|
|
{
|
|
Packet = ALLOC_FROM_POOL(sizeof(ARC_PACKET), NDIS_TAG_ARC_PACKET);
|
|
if (Packet == NULL)
|
|
{
|
|
if (i == ARC_PACKET_ALLOCATION_UNIT)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(Packet, sizeof(ARC_PACKET));
|
|
|
|
NdisReinitializePacket(&(Packet->TmpNdisPacket));
|
|
|
|
Packet->Next = Filter->FreePackets;
|
|
Filter->FreePackets = Packet;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArcDiscardPacketBuffers(
|
|
IN PARC_FILTER Filter,
|
|
IN PARC_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This routine takes an arcnet packet that contains buffers of data and
|
|
puts the buffers on the free list.
|
|
|
|
NOTE: This assumes that LastBuffer points to the real last buffer
|
|
in the chain.
|
|
|
|
Arguments:
|
|
|
|
Filter - The filter to free the buffers to.
|
|
|
|
Packet - The packet to free up.
|
|
|
|
Return values:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PARC_BUFFER_LIST Buffer;
|
|
|
|
//
|
|
// Reset Packet info
|
|
//
|
|
Packet->LastFrame = FALSE;
|
|
Packet->TotalLength = 0;
|
|
|
|
//
|
|
// Reset buffer sizes
|
|
//
|
|
Buffer = Packet->FirstBuffer;
|
|
while (Buffer != NULL)
|
|
{
|
|
Buffer->BytesLeft = Buffer->Size;
|
|
Buffer = Buffer->Next;
|
|
}
|
|
|
|
//
|
|
// Put buffers on free list
|
|
//
|
|
if (Packet->LastBuffer != NULL)
|
|
{
|
|
Packet->LastBuffer->Next = Filter->FreeBufferList;
|
|
Filter->FreeBufferList = Packet->FirstBuffer;
|
|
Packet->FirstBuffer = Packet->LastBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArcDestroyPacket(
|
|
IN PARC_FILTER Filter,
|
|
IN PARC_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This routine takes an arcnet packet and frees up the entire packet.
|
|
|
|
Arguments:
|
|
|
|
Filter - Filter to free to.
|
|
|
|
Packet - The packet to free up.
|
|
|
|
Return values:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER NdisBuffer, NextNdisBuffer;
|
|
|
|
NdisQueryPacket(&Packet->TmpNdisPacket,
|
|
NULL,
|
|
NULL,
|
|
&NdisBuffer,
|
|
NULL);
|
|
|
|
while (NdisBuffer != NULL)
|
|
{
|
|
NdisGetNextBuffer(NdisBuffer, &NextNdisBuffer);
|
|
|
|
NdisFreeBuffer(NdisBuffer);
|
|
|
|
NdisBuffer = NextNdisBuffer;
|
|
}
|
|
|
|
NdisReinitializePacket(&(Packet->TmpNdisPacket));
|
|
|
|
ArcDiscardPacketBuffers(Filter, Packet);
|
|
|
|
//
|
|
// Now put packet on free list
|
|
//
|
|
Packet->Next = Filter->FreePackets;
|
|
Filter->FreePackets = Packet;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ArcConvertToNdisPacket(
|
|
IN PARC_FILTER Filter,
|
|
IN PARC_PACKET Packet,
|
|
IN BOOLEAN ConvertWholePacket
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This routine builds a corresponding NDIS_PACKET in TmpNdisPacket,
|
|
that corresponds to the arcnet packet. The flag ConvertWholePacket
|
|
is used to convert only part of the arcnet packet, or the whole
|
|
stream. If the flag is FALSE, then only the buffers that have
|
|
free space (starting with buffer LastBuffer on up) are converted.
|
|
|
|
NOTE: It assumes TmpNdisPacket is an initialized ndis_packet structure.
|
|
|
|
Arguments:
|
|
|
|
Filter - Filter to allocate from.
|
|
|
|
Packet - The packet to convert.
|
|
|
|
ConvertWholePacket - Convert the whole stream, or only part?
|
|
|
|
Return values:
|
|
|
|
TRUE - If successful, else FALSE
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER NdisBuffer;
|
|
PARC_BUFFER_LIST Buffer;
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
UNREFERENCED_PARAMETER(ConvertWholePacket);
|
|
|
|
Buffer = Packet->FirstBuffer;
|
|
|
|
while (Buffer != NULL)
|
|
{
|
|
NdisAllocateBuffer(&NdisStatus,
|
|
&NdisBuffer,
|
|
Filter->ReceiveBufferPool,
|
|
Buffer->Buffer,
|
|
Buffer->Size - Buffer->BytesLeft);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NdisChainBufferAtBack(&(Packet->TmpNdisPacket), NdisBuffer);
|
|
|
|
Buffer = Buffer->Next;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
ArcFilterDprIndicateReceive(
|
|
IN PARC_FILTER Filter, // Pointer to filter database
|
|
IN PUCHAR pRawHeader, // Pointer to Arcnet frame header
|
|
IN PUCHAR pData, // Pointer to data portion of Arcnet frame
|
|
IN UINT Length // Data Length
|
|
)
|
|
{
|
|
ARC_PACKET_HEADER NewFrameInfo;
|
|
PARC_PACKET Packet, PrevPacket;
|
|
BOOLEAN NewFrame, LastFrame;
|
|
PARC_BUFFER_LIST Buffer;
|
|
UCHAR TmpUchar;
|
|
UINT TmpLength;
|
|
USHORT TmpUshort;
|
|
|
|
//
|
|
// if filter is null, the adapter is indicating too early
|
|
//
|
|
if (Filter == NULL)
|
|
{
|
|
#if DBG
|
|
DbgPrint("Driver is indicating packets too early\n");
|
|
if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
|
|
{
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
if (!MINIPORT_TEST_FLAG(Filter->Miniport, fMINIPORT_MEDIA_CONNECTED))
|
|
{
|
|
return;
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
//
|
|
// Check for ethernet encapsulation first
|
|
//
|
|
TmpUchar = ((ARC_PROTOCOL_HEADER *)pRawHeader)->ProtId;
|
|
|
|
if ( TmpUchar == 0xE8 )
|
|
{
|
|
if ((Length < (ARC_MAX_FRAME_SIZE + 4)) && (Length > 0))
|
|
{
|
|
//
|
|
// Yes! Indicate it to the wrapper for indicating to all
|
|
// protocols running ethernet on top of the arcnet miniport
|
|
// driver.
|
|
//
|
|
ndisMArcIndicateEthEncapsulatedReceive(Filter->Miniport,// miniport.
|
|
pRawHeader, // 878.2 header.
|
|
pData, // ethernet header.
|
|
Length); // length of ethernet frame.
|
|
//
|
|
// Ethernet header should be pData now
|
|
// Length should be data now
|
|
// We're done.
|
|
//
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
|
|
// If the data portion is greater than 507 its a bad deal
|
|
if ((Length > ARC_MAX_FRAME_SIZE + 3) || (Length == 0))
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get information from packet
|
|
//
|
|
NewFrameInfo.ProtHeader.SourceId[0] = *((PUCHAR)pRawHeader);
|
|
NewFrameInfo.ProtHeader.DestId[0] = *((PUCHAR)pRawHeader + 1);
|
|
|
|
NewFrameInfo.ProtHeader.ProtId = TmpUchar;
|
|
|
|
//
|
|
// Read the split flag. If this is an exception packet (i.e.
|
|
// TmpUChar == 0xFF then we need to add an extra 3 onto
|
|
// pData to skip the series of 0xFF 0xFF 0xFF.
|
|
//
|
|
TmpUchar = *((PUCHAR)pData);
|
|
|
|
if (TmpUchar == 0xFF)
|
|
{
|
|
pData += 4;
|
|
Length -= 4;
|
|
|
|
//
|
|
// Re-read the split flag.
|
|
//
|
|
TmpUchar = *((PUCHAR)pData);
|
|
}
|
|
|
|
//
|
|
// Save off the split flag.
|
|
//
|
|
NewFrameInfo.SplitFlag = TmpUchar;
|
|
|
|
//
|
|
// Read the sequence number, which follows the split flag.
|
|
//
|
|
TmpUshort = 0;
|
|
TmpUshort = *((PUCHAR)pData + 1);
|
|
TmpUchar = *((PUCHAR)pData + 2);
|
|
|
|
TmpUshort = TmpUshort | (TmpUchar << 8);
|
|
NewFrameInfo.FrameSequence = TmpUshort;
|
|
//
|
|
// Point pData at protocol data.
|
|
//
|
|
Length -= 3; //... Length of protocol data.
|
|
pData += 3; //... Beginning of protocol data.
|
|
// Length is decreased by SF + SEQ0 + SEQ 1 = 3
|
|
|
|
//
|
|
// NOTE: Length is now the Length of the data portion of this packet
|
|
//
|
|
DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
|
|
("ArcFilter: Frame received: SourceId= %#1x\nDestId=%#1x\nProtId=%#1x\nSplitFlag=%#1x\nFrameSeq=%d\n",
|
|
(USHORT)NewFrameInfo.ProtHeader.SourceId[0],
|
|
(USHORT)NewFrameInfo.ProtHeader.DestId[0],
|
|
(USHORT)NewFrameInfo.ProtHeader.ProtId,
|
|
(USHORT)NewFrameInfo.SplitFlag,
|
|
NewFrameInfo.FrameSequence));
|
|
DBGPRINT(DBG_COMP_FILTER, DBG_LEVEL_INFO,
|
|
("ArcFilter: Data at address: %p, Length = %ld\n", pData, Length));
|
|
|
|
NewFrame = TRUE;
|
|
LastFrame = TRUE;
|
|
|
|
PrevPacket = NULL;
|
|
Packet = Filter->OutstandingPackets;
|
|
|
|
//
|
|
// Walk throgh all outstanding packet to see if this frame belongs to any one of them
|
|
//
|
|
|
|
while ( Packet != NULL )
|
|
{
|
|
if (Packet->Header.ProtHeader.SourceId[0] == NewFrameInfo.ProtHeader.SourceId[0])
|
|
{
|
|
//
|
|
// A packet received from the same source, check packet Sequence number and throw away
|
|
// outstanding packet if they don't match. We are allowed to do this since we know
|
|
// all the frames belonging to one packet are sent before starting a new packet. We
|
|
// HAVE to do this, because this is how we find out that a send at the other end, was aborted
|
|
// after some of the frames were already sent and received here.
|
|
//
|
|
|
|
if((Packet->Header.FrameSequence == NewFrameInfo.FrameSequence) &&
|
|
(Packet->Header.ProtHeader.DestId[0] == NewFrameInfo.ProtHeader.DestId[0]) &&
|
|
(Packet->Header.ProtHeader.ProtId == NewFrameInfo.ProtHeader.ProtId))
|
|
{
|
|
//
|
|
// We found a packet that this frame belongs to, check split flag
|
|
//
|
|
if (Packet->Header.FramesReceived * 2 == NewFrameInfo.SplitFlag)
|
|
{
|
|
//
|
|
// A packet found for this frame and SplitFlag is OK, check to see if it is
|
|
// the last frame of the packet
|
|
//
|
|
NewFrame = FALSE;
|
|
LastFrame = (BOOLEAN)(NewFrameInfo.SplitFlag == Packet->Header.LastSplitFlag);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// compare current split flag with the one from the last frame, if not equal
|
|
// the whole packet should be dropped.
|
|
//
|
|
|
|
if (Packet->Header.SplitFlag != NewFrameInfo.SplitFlag)
|
|
{
|
|
//
|
|
// Corrupted incomplete packet, get rid of it, but keep the new frame
|
|
// and we will re-use this Packet pointer.
|
|
//
|
|
ArcDiscardPacketBuffers(Filter, Packet);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We see to have received a duplicate frame. Ignore it.
|
|
//
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We received a frame from a source that already has an incomplete packet outstanding
|
|
// But Frame Seq. or DestId or ProtId are not the same.
|
|
// We have to discard the old packet and check the new frame for validity,
|
|
// we will re-use this packet pointer below.
|
|
//
|
|
ArcDiscardPacketBuffers(Filter, Packet);
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
PrevPacket = Packet;
|
|
Packet = Packet->Next;
|
|
}
|
|
}
|
|
|
|
if (NewFrame)
|
|
{
|
|
//
|
|
// first frame of a packet, split flag must be odd or zero
|
|
// NewFrame is already TRUE
|
|
// LastFrame is already TRUE
|
|
//
|
|
if (NewFrameInfo.SplitFlag)
|
|
{
|
|
if (!(NewFrameInfo.SplitFlag & 0x01))
|
|
{
|
|
//
|
|
// This frame is the middle of another split, but we
|
|
// don't have it on file. Drop the frame.
|
|
//
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// First Frame of a multiple frame packet
|
|
//
|
|
NewFrameInfo.LastSplitFlag = NewFrameInfo.SplitFlag + 1;
|
|
NewFrameInfo.FramesReceived = 1;
|
|
LastFrame = FALSE; // New packet and SplitFlag not zero
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The frame is fully contained in this packet.
|
|
//
|
|
}
|
|
|
|
//
|
|
// allocate a new packet descriptor if it is a new packet
|
|
//
|
|
if (Packet == NULL)
|
|
{
|
|
if (Filter->FreePackets == NULL)
|
|
{
|
|
ArcAllocatePackets(Filter);
|
|
|
|
if (Filter->FreePackets == NULL)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Packet = Filter->FreePackets;
|
|
Filter->FreePackets = Packet->Next;
|
|
|
|
if (!LastFrame)
|
|
{
|
|
//
|
|
// Insert the packet in list of outstanding packets
|
|
//
|
|
Packet->Next = Filter->OutstandingPackets;
|
|
Filter->OutstandingPackets = Packet;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (LastFrame)
|
|
{
|
|
//
|
|
// remove it from the list
|
|
//
|
|
if (PrevPacket == NULL)
|
|
{
|
|
Filter->OutstandingPackets = Packet->Next;
|
|
}
|
|
else
|
|
{
|
|
PrevPacket->Next = Packet->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
Packet->Header = NewFrameInfo;
|
|
}
|
|
else
|
|
{
|
|
if (LastFrame)
|
|
{
|
|
//
|
|
// Remove it from the queue
|
|
//
|
|
|
|
if (PrevPacket == NULL)
|
|
{
|
|
Filter->OutstandingPackets = Packet->Next;
|
|
}
|
|
else
|
|
{
|
|
PrevPacket->Next = Packet->Next;
|
|
}
|
|
}
|
|
|
|
Packet->Header.FramesReceived++;
|
|
|
|
//
|
|
// keep track of last split flag to detect duplicate frames
|
|
//
|
|
Packet->Header.SplitFlag=NewFrameInfo.SplitFlag;
|
|
}
|
|
|
|
//
|
|
// At this point we know Packet points to the packet to receive
|
|
// the buffer into. If this is the LastFrame, then Packet will
|
|
// have been removed from the OutstandingPackets list, otw it will
|
|
// be in the list.
|
|
//
|
|
// Now get around to getting space for the buffer.
|
|
//
|
|
|
|
//
|
|
// Find the last buffer in the packet
|
|
//
|
|
Buffer = Packet->LastBuffer;
|
|
|
|
if (Buffer == NULL)
|
|
{
|
|
//
|
|
// Allocate a new buffer to hold the packet
|
|
//
|
|
if (Filter->FreeBufferList == NULL)
|
|
{
|
|
if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ArcDiscardPacketBuffers(Filter,Packet);
|
|
//
|
|
// Do not have to discard any packet that may have
|
|
// been allocated above, as it will get discarded
|
|
// the next time a packet comes in from that source.
|
|
//
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Buffer = Filter->FreeBufferList;
|
|
Filter->FreeBufferList = Buffer->Next;
|
|
|
|
Packet->FirstBuffer = Packet->LastBuffer = Buffer;
|
|
Buffer->Next = NULL;
|
|
}
|
|
|
|
// Copy the data off into the ARC_PACKET list.
|
|
// If it doesn't fit within the current buffer, we'll need to
|
|
// allocate more
|
|
|
|
TmpLength = Length;
|
|
|
|
while ( Buffer->BytesLeft < TmpLength )
|
|
{
|
|
//
|
|
// Copy the data
|
|
//
|
|
|
|
NdisMoveFromMappedMemory((PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
|
|
pData,
|
|
Buffer->BytesLeft);
|
|
|
|
pData += Buffer->BytesLeft;
|
|
TmpLength -= Buffer->BytesLeft;
|
|
Buffer->BytesLeft = 0;
|
|
|
|
//
|
|
// Need to allocate more
|
|
//
|
|
if (Filter->FreeBufferList == NULL)
|
|
{
|
|
if (ArcAllocateBuffers(Filter) != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ArcDiscardPacketBuffers(Filter,Packet);
|
|
//
|
|
// Do not have to discard any packet that may have
|
|
// been allocated above, as it will get discarded
|
|
// the next time a packet comes in from that source.
|
|
//
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Buffer->Next = Filter->FreeBufferList;
|
|
Filter->FreeBufferList = Filter->FreeBufferList->Next;
|
|
Buffer = Buffer->Next;
|
|
Buffer->Next = NULL;
|
|
|
|
Packet->LastBuffer->Next = Buffer;
|
|
Packet->LastBuffer = Buffer;
|
|
}
|
|
|
|
//
|
|
// Copy the last bit
|
|
//
|
|
|
|
NdisMoveFromMappedMemory((PUCHAR) Buffer->Buffer + (Buffer->Size - Buffer->BytesLeft),
|
|
pData,
|
|
TmpLength);
|
|
|
|
|
|
Buffer->BytesLeft -= TmpLength;
|
|
Packet->TotalLength += Length;
|
|
|
|
//
|
|
// And now we can start indicating the packet to the bindings that want it
|
|
//
|
|
if (LastFrame)
|
|
{
|
|
ArcFilterDoIndication(Filter, Packet);
|
|
ArcDestroyPacket(Filter, Packet);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
ArcCreateFilter(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN UCHAR AdapterAddress,
|
|
OUT PARC_FILTER * Filter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to create and initialize the Arcnet filter database.
|
|
|
|
Arguments:
|
|
|
|
Miniport - Pointer to the mini-port object.
|
|
|
|
AdapterAddress - the address of the adapter associated with this filter
|
|
database.
|
|
|
|
Lock - Pointer to the lock that should be held when mutual exclusion
|
|
is required.
|
|
|
|
Filter - A pointer to an ARC_FILTER. This is what is allocated and
|
|
created by this routine.
|
|
|
|
Return Value:
|
|
|
|
If the function returns false then one of the parameters exceeded
|
|
what the filter was willing to support.
|
|
|
|
--*/
|
|
{
|
|
PARC_FILTER LocalFilter;
|
|
BOOLEAN rc = TRUE;
|
|
|
|
do
|
|
{
|
|
|
|
*Filter = LocalFilter = ALLOC_FROM_POOL(sizeof(ARC_FILTER), NDIS_TAG_FILTER);
|
|
if (LocalFilter == NULL)
|
|
{
|
|
rc = FALSE;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(LocalFilter, sizeof(ARC_FILTER));
|
|
|
|
LocalFilter->Miniport = Miniport;
|
|
LocalFilter->OpenList = NULL;
|
|
LocalFilter->AdapterAddress = AdapterAddress;
|
|
|
|
ArcReferencePackage();
|
|
} while (FALSE);
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// NOTE: THIS CANNOT BE PAGEABLE
|
|
//
|
|
VOID
|
|
ArcDeleteFilter(
|
|
IN PARC_FILTER Filter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to delete the memory associated with a filter
|
|
database. Note that this routines *ASSUMES* that the database
|
|
has been cleared of any active filters.
|
|
|
|
Arguments:
|
|
|
|
Filter - A pointer to an ARC_FILTER to be deleted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PARC_PACKET Packet;
|
|
PARC_BUFFER_LIST Buffer;
|
|
|
|
ASSERT(Filter->OpenList == NULL);
|
|
|
|
|
|
//
|
|
// Free all ARC_PACKETS
|
|
//
|
|
|
|
//
|
|
// get rid of received partial packets
|
|
//
|
|
while (Filter->OutstandingPackets != NULL)
|
|
{
|
|
Packet = Filter->OutstandingPackets;
|
|
Filter->OutstandingPackets = Packet->Next;
|
|
|
|
//
|
|
// This puts all the component parts on the free lists.
|
|
//
|
|
ArcDestroyPacket(Filter, Packet);
|
|
}
|
|
|
|
while (Filter->FreePackets != NULL)
|
|
{
|
|
Packet = Filter->FreePackets;
|
|
Filter->FreePackets = Packet->Next;
|
|
|
|
FREE_POOL(Packet);
|
|
}
|
|
|
|
while (Filter->FreeBufferList)
|
|
{
|
|
Buffer = Filter->FreeBufferList;
|
|
Filter->FreeBufferList = Buffer->Next;
|
|
|
|
FREE_POOL(Buffer->Buffer);
|
|
FREE_POOL(Buffer);
|
|
}
|
|
|
|
FREE_POOL(Filter);
|
|
|
|
ArcDereferencePackage();
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ArcNoteFilterOpenAdapter(
|
|
IN PARC_FILTER Filter,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
OUT PNDIS_HANDLE NdisFilterHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to add a new binding to the filter database.
|
|
|
|
NOTE: THIS ROUTINE ASSUMES THAT THE DATABASE IS LOCKED WHEN
|
|
IT IS CALLED.
|
|
|
|
Arguments:
|
|
|
|
Filter - A pointer to the previously created and initialized filter
|
|
database.
|
|
|
|
NdisBindingHandle - a pointer to Ndis Open block
|
|
|
|
NdisFilterHandle - A pointer to filter open.
|
|
|
|
Return Value:
|
|
|
|
Will return false if creating a new filter index will cause the maximum
|
|
number of filter indexes to be exceeded.
|
|
|
|
--*/
|
|
{
|
|
PARC_BINDING_INFO LocalOpen;
|
|
|
|
|
|
//
|
|
// Get the first free binding slot and remove that slot from
|
|
// the free list. We check to see if the list is empty.
|
|
//
|
|
LocalOpen = ALLOC_FROM_POOL(sizeof(ARC_BINDING_INFO), NDIS_TAG_ARC_BINDING_INFO);
|
|
if (LocalOpen == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LocalOpen->NextOpen = Filter->OpenList;
|
|
Filter->OpenList = LocalOpen;
|
|
|
|
LocalOpen->References = 1;
|
|
LocalOpen->NdisBindingHandle = NdisBindingHandle;
|
|
LocalOpen->PacketFilters = 0;
|
|
LocalOpen->ReceivedAPacket = FALSE;
|
|
|
|
*NdisFilterHandle = (NDIS_HANDLE)LocalOpen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArcDeleteFilterOpenAdapter(
|
|
IN PARC_FILTER Filter,
|
|
IN NDIS_HANDLE NdisFilterHandle,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When an adapter is being closed this routine should
|
|
be called to delete knowledge of the adapter from
|
|
the filter database. This routine is likely to call
|
|
action routines associated with clearing filter classes
|
|
and addresses.
|
|
|
|
NOTE: THIS ROUTINE SHOULD ****NOT**** BE CALLED IF THE ACTION
|
|
ROUTINES FOR DELETING THE FILTER CLASSES OR THE MULTICAST ADDRESSES
|
|
HAVE ANY POSSIBILITY OF RETURNING A STATUS OTHER THAN NDIS_STATUS_PENDING
|
|
OR NDIS_STATUS_SUCCESS. WHILE THESE ROUTINES WILL NOT BUGCHECK IF
|
|
SUCH A THING IS DONE, THE CALLER WILL PROBABLY FIND IT DIFFICULT
|
|
TO CODE A CLOSE ROUTINE!
|
|
|
|
NOTE: THIS ROUTINE ASSUMES THAT IT IS CALLED WITH THE LOCK HELD.
|
|
|
|
Arguments:
|
|
|
|
Filter - A pointer to the filter database.
|
|
|
|
NdisFilterHandle - Pointer to the open.
|
|
|
|
NdisRequest - If it is necessary to call the action routines,
|
|
this will be passed to it.
|
|
|
|
Return Value:
|
|
|
|
If action routines are called by the various address and filtering
|
|
routines the this routine will likely return the status returned
|
|
by those routines. The exception to this rule is noted below.
|
|
|
|
Given that the filter and address deletion routines return a status
|
|
NDIS_STATUS_PENDING or NDIS_STATUS_SUCCESS this routine will then
|
|
try to return the filter index to the freelist. If the routine
|
|
detects that this binding is currently being indicated to via
|
|
NdisIndicateReceive, this routine will return a status of
|
|
NDIS_STATUS_CLOSING_INDICATING.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Holds the status returned from the packet filter and address
|
|
// deletion routines. Will be used to return the status to
|
|
// the caller of this routine.
|
|
//
|
|
NDIS_STATUS StatusToReturn;
|
|
|
|
//
|
|
// Local variable.
|
|
//
|
|
PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
|
|
|
|
StatusToReturn = ArcFilterAdjust(Filter,
|
|
NdisFilterHandle,
|
|
NdisRequest,
|
|
(UINT)0,
|
|
FALSE);
|
|
|
|
if ((StatusToReturn == NDIS_STATUS_SUCCESS) ||
|
|
(StatusToReturn == NDIS_STATUS_PENDING) ||
|
|
(StatusToReturn == NDIS_STATUS_RESOURCES))
|
|
{
|
|
//
|
|
// Remove the reference from the original open.
|
|
//
|
|
|
|
if (--(LocalOpen->References) == 0)
|
|
{
|
|
PARC_BINDING_INFO *ppBI;
|
|
|
|
//
|
|
// Remove it from the list.
|
|
//
|
|
|
|
for (ppBI = &Filter->OpenList;
|
|
*ppBI != NULL;
|
|
ppBI = &(*ppBI)->NextOpen)
|
|
{
|
|
if (*ppBI == LocalOpen)
|
|
{
|
|
*ppBI = LocalOpen->NextOpen;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(*ppBI == LocalOpen->NextOpen);
|
|
|
|
//
|
|
// First we finish any NdisIndicateReceiveComplete that
|
|
// may be needed for this binding.
|
|
//
|
|
|
|
if (LocalOpen->ReceivedAPacket)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
FilterIndicateReceiveComplete(LocalOpen->NdisBindingHandle);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
}
|
|
|
|
FREE_POOL(LocalOpen);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Let the caller know that there is a reference to the open
|
|
// by the receive indication. The close action routine will be
|
|
// called upon return from NdisIndicateReceive.
|
|
//
|
|
|
|
StatusToReturn = NDIS_STATUS_CLOSING_INDICATING;
|
|
}
|
|
}
|
|
|
|
return StatusToReturn;
|
|
}
|
|
|
|
|
|
VOID
|
|
arcUndoFilterAdjust(
|
|
IN PARC_FILTER Filter,
|
|
IN PARC_BINDING_INFO Binding
|
|
)
|
|
{
|
|
Binding->PacketFilters = Binding->OldPacketFilters;
|
|
Filter->CombinedPacketFilter = Filter->OldCombinedPacketFilter;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
ArcFilterAdjust(
|
|
IN PARC_FILTER Filter,
|
|
IN NDIS_HANDLE NdisFilterHandle,
|
|
IN PNDIS_REQUEST NdisRequest,
|
|
IN UINT FilterClasses,
|
|
IN BOOLEAN Set
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The FilterAdjust routine will call an action routine when a
|
|
particular filter class is changes from not being used by any
|
|
binding to being used by at least one binding or vice versa.
|
|
|
|
If the action routine returns a value other than pending or
|
|
success then this routine has no effect on the packet filters
|
|
for the open or for the adapter as a whole.
|
|
|
|
NOTE: THIS ROUTINE ASSUMES THAT THE LOCK IS HELD.
|
|
|
|
Arguments:
|
|
|
|
Filter - A pointer to the filter database.
|
|
|
|
NdisFilterHandle - A pointer to the open.
|
|
|
|
NdisRequest - If it is necessary to call the action routine,
|
|
this will be passed to it.
|
|
|
|
FilterClasses - The filter classes that are to be added or
|
|
deleted.
|
|
|
|
Set - A boolean that determines whether the filter classes
|
|
are being adjusted due to a set or because of a close. (The filtering
|
|
routines don't care, the MAC might.)
|
|
|
|
Return Value:
|
|
|
|
If it calls the action routine then it will return the
|
|
status returned by the action routine. If the status
|
|
returned by the action routine is anything other than
|
|
NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING the filter database
|
|
will be returned to the state it was in upon entrance to this
|
|
routine.
|
|
|
|
If the action routine is not called this routine will return
|
|
the following statum:
|
|
|
|
NDIS_STATUS_SUCCESS - If the new packet filters doesn't change
|
|
the combined mask of all bindings packet filters.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Contains the value of the combined filter classes before
|
|
// it is adjusted.
|
|
//
|
|
UINT OldCombined = Filter->CombinedPacketFilter;
|
|
|
|
PARC_BINDING_INFO LocalOpen = (PARC_BINDING_INFO)NdisFilterHandle;
|
|
PARC_BINDING_INFO OpenList;
|
|
|
|
UNREFERENCED_PARAMETER(NdisRequest);
|
|
UNREFERENCED_PARAMETER(Set);
|
|
|
|
//
|
|
// Set the new filter information for the open.
|
|
//
|
|
LocalOpen->OldPacketFilters = LocalOpen->PacketFilters;
|
|
LocalOpen->PacketFilters = FilterClasses;
|
|
|
|
//
|
|
// We always have to reform the compbined filter since
|
|
// this filter index may have been the only filter index
|
|
// to use a particular bit.
|
|
//
|
|
Filter->OldCombinedPacketFilter = Filter->CombinedPacketFilter;
|
|
|
|
|
|
for (OpenList = Filter->OpenList, Filter->CombinedPacketFilter = 0;
|
|
OpenList != NULL;
|
|
OpenList = OpenList->NextOpen)
|
|
{
|
|
Filter->CombinedPacketFilter |= OpenList->PacketFilters;
|
|
}
|
|
|
|
return ((OldCombined != Filter->CombinedPacketFilter) ?
|
|
NDIS_STATUS_PENDING : NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ArcFilterDoIndication(
|
|
IN PARC_FILTER Filter,
|
|
IN PARC_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the filter package only to indicate
|
|
that a packet is ready to be indicated to procotols.
|
|
|
|
Arguments:
|
|
|
|
Filter - Pointer to the filter database.
|
|
|
|
Packet - Packet to indicate.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Will hold the type of address that we know we've got.
|
|
//
|
|
UINT AddressType;
|
|
|
|
NDIS_STATUS StatusOfReceive;
|
|
|
|
//
|
|
// Current Open to indicate to.
|
|
//
|
|
PARC_BINDING_INFO LocalOpen, NextOpen;
|
|
|
|
if (Packet->Header.ProtHeader.DestId[0] != 0x00)
|
|
{
|
|
AddressType = NDIS_PACKET_TYPE_DIRECTED;
|
|
}
|
|
else
|
|
{
|
|
AddressType = NDIS_PACKET_TYPE_BROADCAST;
|
|
}
|
|
|
|
//
|
|
// We need to acquire the filter exclusively while we're finding
|
|
// bindings to indicate to.
|
|
//
|
|
|
|
if (!ArcConvertToNdisPacket(Filter, Packet, TRUE))
|
|
{
|
|
//
|
|
// Out of resources, abort.
|
|
//
|
|
return;
|
|
}
|
|
|
|
for (LocalOpen = Filter->OpenList;
|
|
LocalOpen != NULL;
|
|
LocalOpen = NextOpen)
|
|
{
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
//
|
|
// Reference the open during indication.
|
|
//
|
|
if (LocalOpen->PacketFilters & AddressType)
|
|
{
|
|
LocalOpen->References++;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
//
|
|
// Indicate the packet to the binding.
|
|
//
|
|
FilterIndicateReceive(&StatusOfReceive,
|
|
LocalOpen->NdisBindingHandle,
|
|
&Packet->TmpNdisPacket,
|
|
&(Packet->Header.ProtHeader),
|
|
3,
|
|
Packet->FirstBuffer->Buffer,
|
|
Packet->FirstBuffer->Size - Packet->FirstBuffer->BytesLeft,
|
|
Packet->TotalLength);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
LocalOpen->ReceivedAPacket = TRUE;
|
|
|
|
if ((--(LocalOpen->References)) == 0)
|
|
{
|
|
PARC_BINDING_INFO *ppBI;
|
|
|
|
//
|
|
// This binding is shutting down. We have to kill it.
|
|
//
|
|
|
|
//
|
|
// Remove it from the list.
|
|
//
|
|
|
|
for (ppBI = &Filter->OpenList;
|
|
*ppBI != NULL;
|
|
ppBI = &(*ppBI)->NextOpen)
|
|
{
|
|
if (*ppBI == LocalOpen)
|
|
{
|
|
*ppBI = LocalOpen->NextOpen;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(*ppBI == LocalOpen->NextOpen);
|
|
|
|
//
|
|
// Call the IndicateComplete routine.
|
|
//
|
|
|
|
|
|
if (LocalOpen->ReceivedAPacket)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
FilterIndicateReceiveComplete(LocalOpen->NdisBindingHandle);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
}
|
|
|
|
//
|
|
// Call the macs action routine so that they know we
|
|
// are no longer referencing this open binding.
|
|
//
|
|
ndisMDereferenceOpen((PNDIS_OPEN_BLOCK)LocalOpen->NdisBindingHandle);
|
|
|
|
FREE_POOL(LocalOpen);
|
|
} // end of if binding is shutting down
|
|
|
|
} // end of if any binding wants the packet
|
|
} // end of there are more open bindings
|
|
}
|
|
|
|
|
|
VOID
|
|
ArcFilterDprIndicateReceiveComplete(
|
|
IN PARC_FILTER Filter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by to indicate that the receive
|
|
process is complete to all bindings. Only those bindings which
|
|
have received packets will be notified.
|
|
|
|
Arguments:
|
|
|
|
Filter - Pointer to the filter database.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
PARC_BINDING_INFO LocalOpen, NextOpen;
|
|
|
|
//
|
|
// We need to acquire the filter exclusively while we're finding
|
|
// bindings to indicate to.
|
|
//
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
for (LocalOpen = Filter->OpenList; LocalOpen != NULL; LocalOpen = NextOpen)
|
|
{
|
|
NextOpen = LocalOpen->NextOpen;
|
|
|
|
if (LocalOpen->ReceivedAPacket)
|
|
{
|
|
//
|
|
// Indicate the binding.
|
|
//
|
|
|
|
LocalOpen->ReceivedAPacket = FALSE;
|
|
|
|
LocalOpen->References++;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
FilterIndicateReceiveComplete(LocalOpen->NdisBindingHandle);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
|
|
if ((--(LocalOpen->References)) == 0)
|
|
{
|
|
PARC_BINDING_INFO *ppBI;
|
|
|
|
//
|
|
// This binding is shutting down. We have to kill it.
|
|
//
|
|
|
|
//
|
|
// Remove it from the list.
|
|
//
|
|
|
|
for (ppBI = &Filter->OpenList;
|
|
*ppBI != NULL;
|
|
ppBI = &(*ppBI)->NextOpen)
|
|
{
|
|
if (*ppBI == LocalOpen)
|
|
{
|
|
*ppBI = LocalOpen->NextOpen;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(*ppBI == LocalOpen->NextOpen);
|
|
|
|
//
|
|
// Call the macs action routine so that they know we
|
|
// are no longer referencing this open binding.
|
|
//
|
|
ndisMDereferenceOpen((PNDIS_OPEN_BLOCK)LocalOpen->NdisBindingHandle);
|
|
|
|
FREE_POOL(LocalOpen);
|
|
}
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Filter->Miniport);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArcConvertOidListToEthernet(
|
|
IN PNDIS_OID OidList,
|
|
IN PULONG NumberOfOids
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts an arcnet supported OID list into
|
|
an ethernet OID list by replacing or removing arcnet
|
|
OID's.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG c;
|
|
ULONG cArcOids;
|
|
NDIS_OID EthernetOidList[ARC_NUMBER_OF_EXTRA_OIDS] = {
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE
|
|
};
|
|
|
|
//
|
|
// Now we need to copy the returned results into the callers buffer,
|
|
// removing arcnet OID's and adding in ethernet OID's. At this point
|
|
// we do not know if the callers buffer is big enough since we may
|
|
// remove some entries, checking it up front may not yield correct
|
|
// results (i.e. it may actually be big enough).
|
|
//
|
|
for (c = 0, cArcOids = 0; c < *NumberOfOids; c++)
|
|
{
|
|
switch (OidList[c])
|
|
{
|
|
case OID_ARCNET_PERMANENT_ADDRESS:
|
|
OidList[cArcOids++] = OID_802_3_PERMANENT_ADDRESS;
|
|
break;
|
|
|
|
case OID_ARCNET_CURRENT_ADDRESS:
|
|
OidList[cArcOids++] = OID_802_3_CURRENT_ADDRESS;
|
|
break;
|
|
|
|
case OID_ARCNET_RECONFIGURATIONS:
|
|
break;
|
|
|
|
default:
|
|
if ((OidList[c] & 0xFFF00000) != 0x06000000)
|
|
OidList[cArcOids++] = OidList[c];
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the ethernet OIDs.
|
|
//
|
|
CopyMemory((PUCHAR)OidList + (cArcOids * sizeof(NDIS_OID)),
|
|
EthernetOidList,
|
|
ARC_NUMBER_OF_EXTRA_OIDS * sizeof(NDIS_OID));
|
|
|
|
//
|
|
// Update the size of the buffer to send back to the caller.
|
|
//
|
|
*NumberOfOids = cArcOids + ARC_NUMBER_OF_EXTRA_OIDS;
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
ndisMArcIndicateEthEncapsulatedReceive(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PVOID HeaderBuffer,
|
|
IN PVOID DataBuffer,
|
|
IN UINT Length
|
|
)
|
|
/*++
|
|
|
|
HeaderBuffer - This is the 878.2 header.
|
|
DataBuffer - This is the 802.3 header.
|
|
Length - This is the length of the ethernet frame.
|
|
|
|
--*/
|
|
{
|
|
ULONG_PTR MacReceiveContext[2];
|
|
|
|
UNREFERENCED_PARAMETER(HeaderBuffer);
|
|
|
|
//
|
|
// Indicate the packet.
|
|
//
|
|
|
|
MacReceiveContext[0] = (ULONG_PTR) DataBuffer;
|
|
MacReceiveContext[1] = Length;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
if (Length > 14)
|
|
{
|
|
ULONG PacketLength = 0;
|
|
PUCHAR Header = DataBuffer;
|
|
|
|
PacketLength = (ULONG)(((USHORT)Header[12] << 8) | (USHORT)Header[13]);
|
|
|
|
NdisMEthIndicateReceive((NDIS_HANDLE)Miniport, // miniport handle.
|
|
(NDIS_HANDLE)MacReceiveContext, // receive context.
|
|
DataBuffer, // ethernet header.
|
|
14, // ethernet header length.
|
|
(PUCHAR)DataBuffer + 14, // ethernet data.
|
|
PacketLength, // ethernet data length.
|
|
PacketLength); // ethernet data length.
|
|
}
|
|
else
|
|
{
|
|
NdisMEthIndicateReceive((NDIS_HANDLE)Miniport, // miniport handle.
|
|
(NDIS_HANDLE)MacReceiveContext, // receive context.
|
|
DataBuffer, // ethernet header.
|
|
Length, // ethernet header length.
|
|
NULL, // ethernet data.
|
|
0, // ethernet data length.
|
|
0); // ethernet data length.
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMArcTransferData(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer,
|
|
IN OUT PNDIS_PACKET DstPacket,
|
|
OUT PUINT BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the transfer data calls to arcnet mini-port.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Pointer to open block.
|
|
|
|
MacReceiveContext - Context given for the indication
|
|
|
|
ByteOffset - Offset to start transfer at.
|
|
|
|
BytesToTransfer - Number of bytes to transfer
|
|
|
|
Packet - Packet to transfer into
|
|
|
|
BytesTransferred - the number of actual bytes copied
|
|
|
|
Return values:
|
|
|
|
NDIS_STATUS_SUCCESS, if successful, else NDIS_STATUS_FAILURE.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_OPEN_BLOCK MiniportOpen;
|
|
PNDIS_PACKET SrcPacket;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
NDIS_PACKET TempPacket;
|
|
KIRQL OldIrql;
|
|
|
|
MiniportOpen = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
|
|
Miniport = MiniportOpen->MiniportHandle;
|
|
NdisBuffer = NULL;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
//
|
|
// If this is encapsulated ethernet then we don't currently
|
|
// have the source packet from which to copy from.
|
|
//
|
|
|
|
if (MINIPORT_TEST_FLAG(MiniportOpen, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
|
|
{
|
|
//
|
|
// If this is not loopback then we need to create a
|
|
// temp NDIS_PACKET for the packet-to-packet copy.
|
|
//
|
|
if (INDICATED_PACKET(Miniport) == NULL)
|
|
{
|
|
PUCHAR DataBuffer = (PUCHAR)((PULONG_PTR) MacReceiveContext)[0];
|
|
UINT DataLength = (UINT)((PULONG_PTR) MacReceiveContext)[1];
|
|
|
|
//
|
|
// We'll always be in the scope of this function so we
|
|
// can use local stack space rather than allocating dynamic
|
|
// memory.
|
|
//
|
|
SrcPacket = &TempPacket; // Use the local stack for packet store.
|
|
|
|
ZeroMemory(SrcPacket, sizeof(NDIS_PACKET));
|
|
|
|
NdisAllocateBuffer(&Status, // Status code.
|
|
&NdisBuffer, // NDIS buffer to chain onto the packet.
|
|
NULL, // On NT, this parameter is ignored.
|
|
DataBuffer, // The ethernet frame.
|
|
DataLength); // The ethernet frame length.
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisChainBufferAtFront(SrcPacket, NdisBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SrcPacket = INDICATED_PACKET(Miniport);
|
|
|
|
ByteOffset += 3; // Skip fake arcnet header.
|
|
}
|
|
|
|
//
|
|
// Skip the ethernet header.
|
|
//
|
|
|
|
ByteOffset += 14;
|
|
}
|
|
else
|
|
{
|
|
SrcPacket = (PNDIS_PACKET) MacReceiveContext;
|
|
}
|
|
|
|
//
|
|
// Now we can simply copy from the source packet to the
|
|
// destination packet.
|
|
//
|
|
NdisCopyFromPacketToPacket(DstPacket, // destination packet.
|
|
0, // destination offset.
|
|
BytesToTransfer, // bytes to copy.
|
|
SrcPacket, // source packet.
|
|
ByteOffset, // source offset.
|
|
BytesTransferred);// bytes copied.
|
|
|
|
//
|
|
// If we allocated an NDIS_BUFFER then we need to free it. We don't
|
|
// need to unchain the buffer from the packet since the packet is
|
|
// a local stack variable the will just get trashed anyway.
|
|
//
|
|
|
|
if (NdisBuffer != NULL)
|
|
{
|
|
NdisFreeBuffer(NdisBuffer);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMBuildArcnetHeader(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_OPEN_BLOCK Open,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER TmpBuffer;
|
|
UINT i, Flags;
|
|
PUCHAR Address;
|
|
PARC_BUFFER_LIST Buffer;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Only ethernet encapsulation needs this.
|
|
//
|
|
if (!OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
|
|
{
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
if (Miniport->ArcBuf->NumFree == 0)
|
|
{
|
|
//
|
|
// Set flag
|
|
//
|
|
CLEAR_RESOURCE(Miniport, 'S');
|
|
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
NdisQueryPacket(Packet, NULL, NULL, &TmpBuffer, NULL);
|
|
NdisQueryBuffer(TmpBuffer, &Address, &Flags);
|
|
|
|
for (i = 0, Buffer = &Miniport->ArcBuf->ArcnetBuffers[0];
|
|
i < ARC_SEND_BUFFERS;
|
|
Buffer++, i++)
|
|
{
|
|
if (Buffer->Next == NULL)
|
|
{
|
|
Buffer->Next = (PARC_BUFFER_LIST)-1;
|
|
Miniport->ArcBuf->NumFree --;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(i < ARC_SEND_BUFFERS);
|
|
|
|
NdisAllocateBuffer(&Status,
|
|
&NdisBuffer,
|
|
Miniport->ArcBuf->ArcnetBufferPool,
|
|
Buffer->Buffer,
|
|
3);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
CLEAR_RESOURCE(Miniport, 'S');
|
|
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
NdisChainBufferAtFront(Packet, NdisBuffer);
|
|
|
|
((PUCHAR)Buffer->Buffer)[0] = Miniport->ArcnetAddress;
|
|
|
|
if (Address[0] & 0x01)
|
|
{
|
|
//
|
|
// Broadcast
|
|
//
|
|
((PUCHAR)Buffer->Buffer)[1] = 0x00;
|
|
}
|
|
else
|
|
{
|
|
((PUCHAR)Buffer->Buffer)[1] = Address[5];
|
|
}
|
|
|
|
((PUCHAR) Buffer->Buffer)[2] = 0xE8;
|
|
|
|
Packet->Private.Flags = NdisGetPacketFlags(Packet) | NDIS_FLAGS_CONTAINS_ARCNET_HEADER;
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
ndisMFreeArcnetHeader(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_PACKET Packet,
|
|
IN PNDIS_OPEN_BLOCK Open
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function strips off the arcnet header appended to
|
|
ethernet encapsulated packets
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Packet - Ndis packet.
|
|
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PARC_BUFFER_LIST Buffer;
|
|
PNDIS_BUFFER NdisBuffer = NULL;
|
|
PVOID BufferVa;
|
|
UINT i, Length;
|
|
|
|
if (OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_USING_ETH_ENCAPSULATION) &&
|
|
(NdisGetPacketFlags(Packet) & NDIS_FLAGS_CONTAINS_ARCNET_HEADER))
|
|
{
|
|
NdisUnchainBufferAtFront(Packet, &NdisBuffer);
|
|
|
|
if (NdisBuffer != NULL)
|
|
{
|
|
NdisQueryBuffer(NdisBuffer, (PVOID *)&BufferVa, &Length);
|
|
|
|
NdisFreeBuffer(NdisBuffer);
|
|
|
|
for (i = 0, Buffer = &Miniport->ArcBuf->ArcnetBuffers[0];
|
|
i < ARC_SEND_BUFFERS;
|
|
Buffer++, i++)
|
|
{
|
|
if (Buffer->Buffer == BufferVa)
|
|
{
|
|
Buffer->Next = NULL;
|
|
Miniport->ArcBuf->NumFree ++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_CONTAINS_ARCNET_HEADER);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMArcnetSendLoopback(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if a packet needs to be loopbacked and does so if necessary.
|
|
|
|
NOTE: Must be called at DPC_LEVEL with lock HELD!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
Packet - Packet to loopback.
|
|
|
|
Return Value:
|
|
|
|
FALSE if the packet should be sent on the net, TRUE if it is
|
|
a self-directed packet.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Loopback;
|
|
BOOLEAN SelfDirected;
|
|
PNDIS_STACK_RESERVED NSR;
|
|
PNDIS_BUFFER FirstBuffer, NewBuffer;
|
|
PNDIS_PACKET pNewPacket = NULL;
|
|
UINT BufferLength = 0;
|
|
PUCHAR BufferAddress;
|
|
UINT Length;
|
|
UINT BytesToCopy;
|
|
UINT Offset;
|
|
PVOID PacketMemToFree = NULL;
|
|
|
|
|
|
// We should not be here if the driver handles loopback
|
|
ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(NdisMediumArcnet878_2 == Miniport->MediaType);
|
|
|
|
FirstBuffer = Packet->Private.Head;
|
|
BufferAddress = MDL_ADDRESS_SAFE(FirstBuffer, HighPagePriority);
|
|
if (BufferAddress == NULL)
|
|
{
|
|
return(FALSE); // Can't determine if it is a loopback packet
|
|
}
|
|
|
|
//
|
|
// Is this an ethernet encapsulated packet?
|
|
//
|
|
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
|
|
if (ARC_PACKET_IS_ENCAPSULATED(NSR))
|
|
{
|
|
//
|
|
// The second buffer in the packet is the ethernet
|
|
// header so we need to get that one before we can
|
|
// proceed.
|
|
//
|
|
NdisGetNextBuffer(FirstBuffer, &FirstBuffer);
|
|
|
|
BufferAddress = MDL_ADDRESS_SAFE(FirstBuffer, HighPagePriority);
|
|
|
|
if (BufferAddress == NULL)
|
|
{
|
|
return(FALSE); // Can't determine if it is a loopback packet
|
|
}
|
|
|
|
//
|
|
// Now we can continue as though this were ethernet.
|
|
//
|
|
EthShouldAddressLoopBackMacro(Miniport->EthDB,
|
|
BufferAddress,
|
|
&Loopback,
|
|
&SelfDirected);
|
|
}
|
|
else
|
|
{
|
|
Loopback = ((BufferAddress[0] == BufferAddress[1]) ||
|
|
((BufferAddress[1] == 0x00) &&
|
|
(ARC_QUERY_FILTER_CLASSES(Miniport->ArcDB) |
|
|
NDIS_PACKET_TYPE_BROADCAST)));
|
|
|
|
if (BufferAddress[0] == BufferAddress[1])
|
|
{
|
|
SelfDirected = TRUE;
|
|
Loopback = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SelfDirected = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it's not a loopback packet then get out of here!
|
|
//
|
|
if (!Loopback)
|
|
{
|
|
ASSERT(!SelfDirected);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Get the buffer length
|
|
//
|
|
NdisQueryPacket(Packet, NULL, NULL, NULL, &Length);
|
|
|
|
//
|
|
// See if we need to copy the data from the packet
|
|
// into the loopback buffer.
|
|
//
|
|
// We need to copy to the local loopback buffer if
|
|
// the first buffer of the packet is less than the
|
|
// minimum loopback size AND the first buffer isn't
|
|
// the total packet. We always need to copy in case of encapsulation
|
|
//
|
|
if (ARC_PACKET_IS_ENCAPSULATED(NSR))
|
|
{
|
|
PNDIS_STACK_RESERVED NewPacketNSR;
|
|
NDIS_STATUS Status;
|
|
UINT PktSize;
|
|
ULONG j;
|
|
|
|
|
|
//
|
|
// If the packet is encapsulated ethernet then don't count the
|
|
// arcnet header in with the length.
|
|
//
|
|
Length -= ARC_PROTOCOL_HEADER_SIZE;
|
|
|
|
//
|
|
// Skip the fake arcnet header.
|
|
//
|
|
Offset = ARC_PROTOCOL_HEADER_SIZE;
|
|
|
|
PktSize = NdisPacketSize(PROTOCOL_RESERVED_SIZE_IN_PACKET);
|
|
|
|
|
|
//
|
|
// Allocate a buffer for the packet.
|
|
//
|
|
pNewPacket = (PNDIS_PACKET)ALLOC_FROM_POOL(Length + PktSize, NDIS_TAG_LOOP_PKT);
|
|
PacketMemToFree = (PVOID)pNewPacket;
|
|
|
|
if (NULL == pNewPacket)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
ZeroMemory(pNewPacket, PktSize);
|
|
BufferAddress = (PUCHAR)pNewPacket + PktSize;
|
|
pNewPacket = (PNDIS_PACKET)((PUCHAR)pNewPacket + SIZE_PACKET_STACKS);
|
|
|
|
for (j = 0; j < ndisPacketStackSize; j++)
|
|
{
|
|
CURR_STACK_LOCATION(pNewPacket) = j;
|
|
NDIS_STACK_RESERVED_FROM_PACKET(pNewPacket, &NewPacketNSR);
|
|
INITIALIZE_SPIN_LOCK(&NewPacketNSR->Lock);
|
|
}
|
|
|
|
CURR_STACK_LOCATION(pNewPacket) = (UINT)-1;
|
|
|
|
//
|
|
// Allocate an MDL for the packet.
|
|
//
|
|
NdisAllocateBuffer(&Status, &NewBuffer, NULL, BufferAddress, Length);
|
|
if (NDIS_STATUS_SUCCESS != Status)
|
|
{
|
|
FREE_POOL(PacketMemToFree);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// NdisChainBufferAtFront()
|
|
//
|
|
pNewPacket->Private.Head = NewBuffer;
|
|
pNewPacket->Private.Tail = NewBuffer;
|
|
pNewPacket->Private.Pool = (PVOID)'pooL';
|
|
pNewPacket->Private.NdisPacketOobOffset = (USHORT)(PktSize - (SIZE_PACKET_STACKS +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_EXTENSION)));
|
|
|
|
NDIS_SET_ORIGINAL_PACKET(pNewPacket, pNewPacket);
|
|
|
|
ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
|
|
Offset, // Offset from beginning of packet.
|
|
Length, // Number of bytes to copy.
|
|
BufferAddress,// The destination buffer.
|
|
&BufferLength);
|
|
|
|
MINIPORT_SET_PACKET_FLAG(pNewPacket, fPACKET_IS_LOOPBACK);
|
|
pNewPacket->Private.Flags = NdisGetPacketFlags(Packet) & NDIS_FLAGS_DONT_LOOPBACK;
|
|
pNewPacket->Private.Flags |= NDIS_FLAGS_IS_LOOPBACK_PACKET;
|
|
}
|
|
else if ((BufferLength < NDIS_M_MAX_LOOKAHEAD) && (BufferLength != Length))
|
|
{
|
|
//
|
|
// Copy the arcnet header.
|
|
//
|
|
BufferLength = MDL_SIZE(FirstBuffer);
|
|
BytesToCopy = ARC_PROTOCOL_HEADER_SIZE;
|
|
|
|
//
|
|
// Don't skip anything.
|
|
//
|
|
Offset = 0;
|
|
|
|
BufferAddress = Miniport->ArcBuf->ArcnetLookaheadBuffer;
|
|
BytesToCopy += Miniport->CurrentLookahead;
|
|
|
|
ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
|
|
Offset, // Offset from beginning of packet.
|
|
BytesToCopy, // Number of bytes to copy.
|
|
BufferAddress, // The destination buffer.
|
|
&BufferLength); // The number of bytes copied.
|
|
}
|
|
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
//
|
|
// Indicate the packet to every open binding
|
|
// that could want it.
|
|
//
|
|
if (ARC_PACKET_IS_ENCAPSULATED(NSR) && pNewPacket)
|
|
{
|
|
NDIS_SET_PACKET_HEADER_SIZE(pNewPacket, 14);
|
|
ethFilterDprIndicateReceivePacket(Miniport,
|
|
&pNewPacket,
|
|
1);
|
|
NdisFreeBuffer(pNewPacket->Private.Head);
|
|
FREE_POOL(PacketMemToFree);
|
|
}
|
|
else
|
|
{
|
|
PUCHAR PlaceInBuffer;
|
|
PUCHAR ArcDataBuffer;
|
|
UINT ArcDataLength;
|
|
UINT PacketDataOffset;
|
|
UCHAR FrameCount;
|
|
UCHAR i;
|
|
UINT IndicateDataLength;
|
|
|
|
//
|
|
// Calculate how many frames we will need.
|
|
//
|
|
ArcDataLength = Length - ARC_PROTOCOL_HEADER_SIZE;
|
|
PacketDataOffset = ARC_PROTOCOL_HEADER_SIZE;
|
|
|
|
FrameCount = (UCHAR)(ArcDataLength / ARC_MAX_FRAME_SIZE);
|
|
|
|
if ((ArcDataLength % ARC_MAX_FRAME_SIZE) != 0)
|
|
{
|
|
FrameCount++;
|
|
}
|
|
|
|
for (i = 0; i < FrameCount; ++i)
|
|
{
|
|
PlaceInBuffer = Miniport->ArcBuf->ArcnetLookaheadBuffer;
|
|
|
|
//
|
|
// Point data buffer to start of 'data'
|
|
// Don't include system code as part of data
|
|
//
|
|
ArcDataBuffer = Miniport->ArcBuf->ArcnetLookaheadBuffer + ARC_PROTOCOL_HEADER_SIZE;
|
|
|
|
//
|
|
// Copy Header (SrcId/DestId/ProtId)
|
|
//
|
|
ndisMCopyFromPacketToBuffer(Packet,
|
|
0,
|
|
ARC_PROTOCOL_HEADER_SIZE,
|
|
PlaceInBuffer,
|
|
&BufferLength);
|
|
|
|
PlaceInBuffer += ARC_PROTOCOL_HEADER_SIZE;
|
|
|
|
//
|
|
// Put in split flag
|
|
//
|
|
if (FrameCount > 1)
|
|
{
|
|
//
|
|
// Multi-frame indication...
|
|
//
|
|
if ( i == 0 )
|
|
{
|
|
//
|
|
// first frame
|
|
//
|
|
|
|
// *PlaceInBuffer = ( (FrameCount - 2) * 2 ) + 1;
|
|
|
|
*PlaceInBuffer = 2 * FrameCount - 3;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Subsequent frame
|
|
//
|
|
*PlaceInBuffer = ( i * 2 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Only frame in the indication
|
|
//
|
|
*PlaceInBuffer = 0;
|
|
}
|
|
|
|
//
|
|
// Skip split flag
|
|
//
|
|
PlaceInBuffer++;
|
|
|
|
//
|
|
// Put in packet number.
|
|
//
|
|
*PlaceInBuffer++ = 0;
|
|
*PlaceInBuffer++ = 0;
|
|
|
|
//
|
|
// Copy data
|
|
//
|
|
if (ArcDataLength > ARC_MAX_FRAME_SIZE)
|
|
{
|
|
IndicateDataLength = ARC_MAX_FRAME_SIZE;
|
|
}
|
|
else
|
|
{
|
|
IndicateDataLength = ArcDataLength;
|
|
}
|
|
|
|
ndisMCopyFromPacketToBuffer(Packet,
|
|
PacketDataOffset,
|
|
IndicateDataLength,
|
|
PlaceInBuffer,
|
|
&BufferLength);
|
|
|
|
//
|
|
// Indicate the actual data length which should not
|
|
// include the system code.
|
|
//
|
|
ArcFilterDprIndicateReceive(Miniport->ArcDB,
|
|
Miniport->ArcBuf->ArcnetLookaheadBuffer,
|
|
ArcDataBuffer,
|
|
IndicateDataLength + ARC_PROTOCOL_HEADER_SIZE);
|
|
|
|
ArcDataLength -= ARC_MAX_FRAME_SIZE;
|
|
PacketDataOffset += ARC_MAX_FRAME_SIZE;
|
|
}
|
|
|
|
ArcFilterDprIndicateReceiveComplete(Miniport->ArcDB);
|
|
}
|
|
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
|
|
{
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
return(SelfDirected);
|
|
}
|
|
|
|
#endif
|