windows-nt/Source/XPSP1/NT/net/tcpip/driver/ipv4/mcasttmr.c
2020-09-26 16:20:57 +08:00

293 lines
7 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
tcpip\ip\mcasttmr.c
Abstract:
Timer routine for cleanup of MFEs
Author:
Amritansh Raghav
Revision History:
AmritanR Created
Notes:
--*/
#include "precomp.h"
#if IPMCAST
#define __FILE_SIG__ TMR_SIG
#include "ipmcast.h"
#include "ipmcstxt.h"
#include "mcastmfe.h"
VOID
CompleteNotificationIrp(
IN PNOTIFICATION_MSG pMsg
);
VOID
McastTimerRoutine(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2
);
//
// MUST BE PAGED IN
//
#pragma alloc_text(PAGEIPMc, McastTimerRoutine)
VOID
McastTimerRoutine(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2
)
/*++
Routine Description:
The DPC routine associated with the timer.
The global variable g_ulNextHashIndex keeps track of the bucket
that needs to be walked and checked for activity. The routine
walks all the groups in BUCKETS_PER_QUANTUM number of buckets.
N.B.: We should probably use a JOB object for this.
Locks:
Takes the lock for each hash bucket walked as writer
Arguments:
Dpc
DeferredContext
SystemArgument1
SystemArgument2
Return Value:
NONE
--*/
{
LONGLONG llCurrentTime, llTime;
ULONG ulIndex, ulNumBuckets, ulMsgIndex;
PLIST_ENTRY pleGrpNode, pleSrcNode;
PGROUP pGroup;
PSOURCE pSource;
LARGE_INTEGER liDueTime;
PNOTIFICATION_MSG pCopy;
PIPMCAST_MFE_MSG pMsg;
TraceEnter(TMR, "McastTimerRoutine");
KeQueryTickCount((PLARGE_INTEGER)&llCurrentTime);
ulIndex = g_ulNextHashIndex;
ulMsgIndex = 0;
pCopy = NULL;
pMsg = NULL;
Trace(TMR, TRACE,
("McastTimerRoutine: Starting at index %d\n",
ulIndex));
for(ulNumBuckets = 0;
ulNumBuckets < BUCKETS_PER_QUANTUM;
ulNumBuckets++)
{
//
// Acquire the bucket lock as writer. Since we are off a TIMER
// we are at DPC
//
EnterWriterAtDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
pleGrpNode = g_rgGroupTable[ulIndex].leHashHead.Flink;
while(pleGrpNode isnot &(g_rgGroupTable[ulIndex].leHashHead))
{
pGroup = CONTAINING_RECORD(pleGrpNode, GROUP, leHashLink);
pleGrpNode = pleGrpNode->Flink;
pleSrcNode = pGroup->leSrcHead.Flink;
while(pleSrcNode isnot &pGroup->leSrcHead)
{
//
// We look at the SOURCE without taking the lock, because
// the source can not be deleted without removing it from the
// group list, which can not happen since we have the group
// bucket locked as writer
//
pSource = CONTAINING_RECORD(pleSrcNode, SOURCE, leGroupLink);
pleSrcNode = pleSrcNode->Flink;
//
// The TimeOut and CreateTime can be looked at without
// a lock, but the LastActivity should be read only with
// the lock held. However, we shall take the chance and
// not use a lock
//
if(pSource->llTimeOut isnot 0)
{
//
// Timeout value has been supplied, lets use that
//
llTime = llCurrentTime - pSource->llCreateTime;
if((llCurrentTime > pSource->llCreateTime) and
(llTime < pSource->llTimeOut))
{
continue;
}
Trace(TMR, TRACE,
("McastTimerRoutine: %d.%d.%d.%d %d.%d.%d.%d entry being removed due to user supplied timeout\n",
PRINT_IPADDR(pGroup->dwGroup),
PRINT_IPADDR(pSource->dwSource)));
}
else
{
//
// Otherwise, just do this based on activity
//
llTime = llCurrentTime - pSource->llLastActivity;
if((llCurrentTime > pSource->llLastActivity) and
(llTime < SECS_TO_TICKS(INACTIVITY_PERIOD)))
{
continue;
}
Trace(TMR, TRACE,
("McastTimerRoutine: %d.%d.%d.%d %d.%d.%d.%d entry being removed due to inactiviy\n",
PRINT_IPADDR(pGroup->dwGroup),
PRINT_IPADDR(pSource->dwSource)));
}
//
// Otherwise we need to delete the source, and complete an
// IRP back to the router manager
//
if(ulMsgIndex is 0)
{
RtAssert(!pCopy);
pCopy = ExAllocateFromNPagedLookasideList(&g_llMsgBlocks);
if(pCopy is NULL)
{
continue;
}
pCopy->inMessage.dwEvent = IPMCAST_DELETE_MFE_MSG;
pMsg = &(pCopy->inMessage.immMfe);
pMsg->ulNumMfes = 0;
}
pMsg->ulNumMfes++;
pMsg->idmMfe[ulMsgIndex].dwGroup = pGroup->dwGroup;
pMsg->idmMfe[ulMsgIndex].dwSource = pSource->dwSource;
pMsg->idmMfe[ulMsgIndex].dwSrcMask = pSource->dwSrcMask;
ulMsgIndex++;
ulMsgIndex %= NUM_DEL_MFES;
if(ulMsgIndex is 0)
{
//
// Complete the Irp
//
CompleteNotificationIrp(pCopy);
pCopy = NULL;
pMsg = NULL;
}
//
// The function needs the SOURCE ref'ed and locked
//
ReferenceSource(pSource);
RtAcquireSpinLockAtDpcLevel(&(pSource->mlLock));
RemoveSource(pGroup->dwGroup,
pSource->dwSource,
pSource->dwSrcMask,
pGroup,
pSource);
}
}
ExitWriterFromDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
//
// Done walking this bucket
//
ulIndex++;
ulIndex %= GROUP_TABLE_SIZE;
}
//
// The last message may not have been indicated up. See if it needs
// to be completed
//
if(pCopy)
{
CompleteNotificationIrp(pCopy);
}
g_ulNextHashIndex = ulIndex;
liDueTime = RtlEnlargedUnsignedMultiply(TIMER_IN_MILLISECS,
SYS_UNITS_IN_ONE_MILLISEC);
liDueTime = RtlLargeIntegerNegate(liDueTime);
KeSetTimerEx(&g_ktTimer,
liDueTime,
0,
&g_kdTimerDpc);
TraceLeave(TMR, "McastTimerRoutine");
}
#endif