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.
465 lines
13 KiB
465 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntos\tdi\isn\fwd\packets.h
|
|
|
|
Abstract:
|
|
IPX Forwarder Driver packet allocator
|
|
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef _IPXFWD_PACKETS_
|
|
#define _IPXFWD_PACKETS_
|
|
|
|
// Forward structure prototypes
|
|
struct _SEGMENT_LIST;
|
|
typedef struct _SEGMENT_LIST SEGMENT_LIST, *PSEGMENT_LIST;
|
|
struct _PACKET_SEGMENT;
|
|
typedef struct _PACKET_SEGMENT PACKET_SEGMENT, *PPACKET_SEGMENT;
|
|
struct _PACKET_TAG;
|
|
typedef struct _PACKET_TAG PACKET_TAG, *PPACKET_TAG;
|
|
|
|
// Forwarder data associated with each packet it allocates
|
|
struct _PACKET_TAG {
|
|
union {
|
|
UCHAR PT_Identifier; // this should be IDENTIFIER_RIP
|
|
PPACKET_TAG PT_Next; // link in packet segment
|
|
};
|
|
union {
|
|
PVOID SEND_RESERVED[SEND_RESERVED_COMMON_SIZE]; // needed by ipx
|
|
// for padding on ethernet
|
|
PINTERFACE_CB PT_SourceIf; // Source interface reference needed
|
|
// for spoofing keep-alives and
|
|
// queuing connection requests
|
|
};
|
|
PPACKET_SEGMENT PT_Segment; // segment where it belongs
|
|
LONGLONG PT_PerfCounter;
|
|
ULONG PT_Flags;
|
|
#define PT_NB_DESTROY 0x1 // NB packet to be not requeued
|
|
#define PT_SOURCE_IF 0x2 // Spoofing packet with src if reference
|
|
PUCHAR PT_Data; // Data buffer
|
|
PNDIS_BUFFER PT_MacHdrBufDscr; // buffer descriptor for
|
|
// mac header buffer required
|
|
// by IPX
|
|
PINTERFACE_CB PT_InterfaceReference; // points to the interface CB where
|
|
// it is queued
|
|
LIST_ENTRY PT_QueueLink; // links this packet in send queue
|
|
IPX_LOCAL_TARGET PT_Target; // destination target for ipx
|
|
// stack
|
|
UCHAR PT_MacHeader[1];// Mac header buffer reserved for IPX
|
|
};
|
|
|
|
// Segment of preallocated packets complete with buffers
|
|
struct _PACKET_SEGMENT {
|
|
LIST_ENTRY PS_Link; // Link in segment list
|
|
PSEGMENT_LIST PS_SegmentList; // Segment list we belong to
|
|
PPACKET_TAG PS_FreeHead; // List of free packets in
|
|
// this segment
|
|
ULONG PS_BusyCount; // Count of packets allocated
|
|
// from this segment
|
|
NDIS_HANDLE PS_PacketPool; // Pool of NDIS packet
|
|
// descriptors used by the
|
|
// packets in this segment
|
|
NDIS_HANDLE PS_BufferPool; // Pool of NDIS buffer
|
|
// descriptors used by the
|
|
// packets in this segment
|
|
LONGLONG PS_FreeStamp; // Time when last packet was freed
|
|
union {
|
|
UCHAR PS_Buffers[1]; // Memory used by buffers
|
|
LONGLONG PS_BuffersAlign;
|
|
};
|
|
};
|
|
|
|
|
|
// List of segment with preallocated packets
|
|
struct _SEGMENT_LIST {
|
|
const ULONG SL_BlockSize; // Size of packet's buffer
|
|
LIST_ENTRY SL_Head; // Head of the segment list
|
|
ULONG SL_FreeCount; // Total number of free packets
|
|
// in all segment in the list
|
|
ULONG SL_BlockCount; // Number of packets per segment
|
|
ULONG SL_LowCount; // Free count at which we
|
|
// will preallocate new segment
|
|
LONG SL_RefCount; // Number of consumers that are
|
|
// using packets in this list
|
|
BOOLEAN SL_TimerDpcPending;
|
|
BOOLEAN SL_AllocatorPending;
|
|
WORK_QUEUE_ITEM SL_Allocator; // Allocation work item
|
|
KTIMER SL_Timer; // Timer to free unused segments
|
|
KDPC SL_TimerDpc; // DPC of the timer of unused segments
|
|
KSPIN_LOCK SL_Lock; // Access control
|
|
};
|
|
|
|
|
|
// The number of rcv packets per segment (config parameter)
|
|
#define MIN_RCV_PKTS_PER_SEGMENT 8
|
|
#define DEF_RCV_PKTS_PER_SEGMENT 64
|
|
#define MAX_RCV_PKTS_PER_SEGMENT 256
|
|
extern ULONG RcvPktsPerSegment;
|
|
|
|
// Maximum size of memory that can be used to allocate packets (config
|
|
// param). 0 means no limit
|
|
extern ULONG MaxRcvPktsPoolSize;
|
|
|
|
// There are currently three known frame sizes: ethernet-1500,
|
|
// token ring 4k - 4500, token ring 16k - 17986
|
|
#define FRAME_SIZE_VARIATIONS 3
|
|
|
|
// List of packet segments for Ethernet packets
|
|
extern SEGMENT_LIST ListEther;
|
|
// List of packet segments for Token Ring 4K packets
|
|
extern SEGMENT_LIST ListTR4;
|
|
// List of packet segments for Token Ring 16K packets
|
|
extern SEGMENT_LIST ListTR16;
|
|
// Mapping from src and destination packet size requirments
|
|
// to the appropriate segment list
|
|
extern PSEGMENT_LIST SegmentMap[FRAME_SIZE_VARIATIONS][FRAME_SIZE_VARIATIONS];
|
|
// Timeout for unused segment
|
|
extern const LONGLONG SegmentTimeout;
|
|
extern KSPIN_LOCK AllocatorLock;
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t i a l i z e P a c k e t A l l o c a t o r
|
|
|
|
Routine Description:
|
|
Initializes packet allocator
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
// VOID
|
|
// InitializePacketAllocator (
|
|
// void
|
|
// );
|
|
#define InitializePacketAllocator() { \
|
|
KeInitializeSpinLock(&AllocatorLock); \
|
|
InitializeSegmentList(&ListEther); \
|
|
InitializeSegmentList(&ListTR4); \
|
|
InitializeSegmentList(&ListTR16); \
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e l e t e P a c k e t A l l o c a t o r
|
|
|
|
Routine Description:
|
|
Disposes of all resources in packet allocator
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
// VOID
|
|
// DeletePacketAllocator (
|
|
// void
|
|
// );
|
|
#define DeletePacketAllocator() { \
|
|
DeleteSegmentList(&ListEther); \
|
|
DeleteSegmentList(&ListTR4); \
|
|
DeleteSegmentList(&ListTR16); \
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
A l l o c a t e P a c k e t
|
|
|
|
Routine Description:
|
|
Allocate packet for source - destination combination
|
|
Arguments:
|
|
srcListId - identifies max frame size for source interface
|
|
dstListId - identifies max frame size for destination
|
|
packet - receives pointer to allocated packet or NULL if allocation
|
|
fails
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
// VOID
|
|
// AllocatePacket (
|
|
// IN INT srcListId,
|
|
// IN INT dstListId,
|
|
// OUT PPACKET_TAG packet
|
|
// );
|
|
#define AllocatePacket(srcListId,dstListId,packet) { \
|
|
PSEGMENT_LIST list; \
|
|
ASSERT ((srcListId>=0) && (srcListId<FRAME_SIZE_VARIATIONS)); \
|
|
ASSERT ((dstListId>=0) && (dstListId<FRAME_SIZE_VARIATIONS)); \
|
|
list = SegmentMap[srcListId][dstListId]; \
|
|
AllocatePacketFromList(list,packet); \
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D u p l i c a t e P a c k e t
|
|
|
|
Routine Description:
|
|
Duplicates packet
|
|
Arguments:
|
|
src - source packet
|
|
dst - receives pointer to duplicated packet or NUUL if operation
|
|
failed
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
// VOID
|
|
// DuplicatePacket (
|
|
// IN PPACKET_TAG src
|
|
// OUT PPACKET_TAG dst
|
|
// );
|
|
#define DuplicatePacket(src,dst) { \
|
|
PSEGMENT_LIST list; \
|
|
list = src->PT_Segment->PS_SegmentList; \
|
|
AllocatePacketFromList(list,dst); \
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
A l l o c a t e P a c k e t F r o m L i s t
|
|
|
|
Routine Description:
|
|
Allocate packet from specified packet segment list
|
|
Arguments:
|
|
list - list from which to allocate
|
|
packet - receives pointer to allocated packet or NULL if allocation
|
|
fails
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
// VOID
|
|
// AllocatePacketFromList (
|
|
// IN PSEGMENT_LIST list
|
|
// OUT PPACKET_TAG packet
|
|
// );
|
|
#define AllocatePacketFromList(list,packet) { \
|
|
PPACKET_SEGMENT segment; \
|
|
KIRQL oldIRQL; \
|
|
KeAcquireSpinLock (&list->SL_Lock, &oldIRQL); \
|
|
do { \
|
|
if (list->SL_FreeCount>0) { \
|
|
segment = CONTAINING_RECORD (list->SL_Head.Flink, \
|
|
PACKET_SEGMENT, PS_Link); \
|
|
while (segment->PS_FreeHead==NULL) { \
|
|
segment = CONTAINING_RECORD (segment->PS_Link.Flink, \
|
|
PACKET_SEGMENT, PS_Link); \
|
|
ASSERT (&segment->PS_Link!=&list->SL_Head); \
|
|
} \
|
|
list->SL_FreeCount -= 1; \
|
|
if ((list->SL_FreeCount<list->SL_LowCount) \
|
|
&& !list->SL_AllocatorPending \
|
|
&& EnterForwarder ()) { \
|
|
list->SL_AllocatorPending = TRUE; \
|
|
ExQueueWorkItem (&list->SL_Allocator, DelayedWorkQueue);\
|
|
} \
|
|
} \
|
|
else { \
|
|
segment = CreateSegment (list); \
|
|
if (segment!=NULL) { \
|
|
InsertTailList (&list->SL_Head, &segment->PS_Link); \
|
|
segment->PS_SegmentList = list; \
|
|
list->SL_FreeCount = list->SL_BlockCount-1; \
|
|
} \
|
|
else { \
|
|
packet = NULL; \
|
|
break; \
|
|
} \
|
|
} \
|
|
packet = segment->PS_FreeHead; \
|
|
segment->PS_FreeHead = packet->PT_Next; \
|
|
segment->PS_BusyCount += 1; \
|
|
packet->PT_Identifier = IDENTIFIER_RIP; \
|
|
packet->PT_Flags = 0; \
|
|
} \
|
|
while (FALSE); \
|
|
KeReleaseSpinLock (&list->SL_Lock, oldIRQL); \
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
F r e e P a c k e t
|
|
|
|
Routine Description:
|
|
Free allocated packet
|
|
Arguments:
|
|
packet - packet to free
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
// VOID
|
|
// FreePacket (
|
|
// IN PPACKET_TAG packet
|
|
// );
|
|
#define FreePacket(packet) { \
|
|
PPACKET_SEGMENT segment=packet->PT_Segment; \
|
|
PSEGMENT_LIST list; \
|
|
KIRQL oldIRQL; \
|
|
list = segment->PS_SegmentList; \
|
|
KeAcquireSpinLock (&list->SL_Lock, &oldIRQL); \
|
|
packet->PT_Next = segment->PS_FreeHead; \
|
|
segment->PS_FreeHead = packet; \
|
|
list->SL_FreeCount += 1; \
|
|
segment->PS_BusyCount -= 1; \
|
|
if (segment->PS_BusyCount==0) { \
|
|
if (list->SL_TimerDpcPending) { \
|
|
KeQuerySystemTime ((PLARGE_INTEGER)&segment->PS_FreeStamp); \
|
|
KeReleaseSpinLock (&list->SL_Lock, oldIRQL);\
|
|
} \
|
|
else if (EnterForwarder ()) { \
|
|
list->SL_TimerDpcPending = TRUE; \
|
|
KeReleaseSpinLock (&list->SL_Lock, oldIRQL);\
|
|
KeSetTimer (&list->SL_Timer, \
|
|
*((PLARGE_INTEGER)&SegmentTimeout), \
|
|
&list->SL_TimerDpc); \
|
|
} \
|
|
else { \
|
|
KeReleaseSpinLock (&list->SL_Lock, oldIRQL);\
|
|
} \
|
|
} \
|
|
else { \
|
|
KeReleaseSpinLock (&list->SL_Lock, oldIRQL); \
|
|
} \
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
C r e a t e S e g m e n t
|
|
|
|
Routine Description:
|
|
Allocates and initializes packet segment
|
|
Arguments:
|
|
list - segment list to which new segment will be added
|
|
Return Value:
|
|
Pointer to allocated segment, NULL if fails
|
|
|
|
*******************************************************************
|
|
--*/
|
|
PPACKET_SEGMENT
|
|
CreateSegment (
|
|
PSEGMENT_LIST list
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e l e t e S e g m e n t
|
|
|
|
Routine Description:
|
|
Frees packet segment
|
|
Arguments:
|
|
segment - segment to free
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
DeleteSegment (
|
|
PPACKET_SEGMENT segment
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
R e g i s t e r P a c k e t C o n s u m e r
|
|
|
|
Routine Description:
|
|
Registers a consumer (bound interface) of packets of the
|
|
given size
|
|
Arguments:
|
|
pktsize - maximum size of packets needed
|
|
listId - buffer to return packet list id where packets
|
|
of required size are located
|
|
Return Value:
|
|
STATUS_SUCCESS - registration succeded
|
|
STATUS_INSUFFICIENT_RESOURCES - not enogh resources to register
|
|
|
|
*******************************************************************
|
|
--*/
|
|
NTSTATUS
|
|
RegisterPacketConsumer (
|
|
IN ULONG pktsize,
|
|
OUT INT *listID
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e r e g i s t e r P a c k e t C o n s u m e r
|
|
|
|
Routine Description:
|
|
Deregisters a consumer (bound interface) of packets of the
|
|
given size
|
|
Arguments:
|
|
listId - packet list id used by the consumer
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
DeregisterPacketConsumer (
|
|
IN INT listID
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t i a l i z e S e g m e n t L i s t
|
|
|
|
Routine Description:
|
|
Initializes list of packet segments
|
|
Arguments:
|
|
list - list to initalize
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
InitializeSegmentList(
|
|
PSEGMENT_LIST list
|
|
);
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e l e t e S e g m e n t L i s t
|
|
|
|
Routine Description:
|
|
Deletes list of packet segments
|
|
Arguments:
|
|
list - list to delete
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
DeleteSegmentList (
|
|
PSEGMENT_LIST list
|
|
);
|
|
|
|
#endif
|
|
|
|
|