windows-nt/Source/XPSP1/NT/net/rras/ndis/ndiswan/indicate.c
2020-09-26 16:20:57 +08:00

1027 lines
25 KiB
C

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
Indicate.c
Abstract:
This file contains procedures to handle indications from the
WAN Miniport drivers.
Author:
Tony Bell (TonyBe) June 06, 1995
Environment:
Kernel Mode
Revision History:
TonyBe 06/06/95 Created
--*/
#include "wan.h"
#define __FILE_SIG__ INDICATE_FILESIG
VOID
NdisWanLineUpIndication(
POPENCB OpenCB,
PUCHAR Buffer,
ULONG BufferSize
)
/*++
Routine Name:
NdisWanLineupIndication
Routine Description:
This routine is called when a WAN Miniport driver has a new connetion
become active or when the status of an active connection changes. If
this is a new connection the routine creates a LinkCB, and a BundleCB
for the new connection. If this is for an already active connetion the
connection info is updated.
Arguments:
Return Values:
None
--*/
{
PLINKCB LinkCB = NULL;
PBUNDLECB BundleCB = NULL;
NDIS_STATUS Status;
PNDIS_MAC_LINE_UP LineUpInfo = (PNDIS_MAC_LINE_UP)Buffer;
BOOLEAN EmptyList;
if (BufferSize < sizeof(NDIS_MAC_LINE_UP)) {
return;
}
//
// Is this for a new connetion?
//
if (LineUpInfo->NdisLinkContext == NULL) {
//
// This is a new connection!
//
//
// Get a linkcb
//
LinkCB = NdisWanAllocateLinkCB(OpenCB, LineUpInfo->SendWindow);
if (LinkCB == NULL) {
//
// Error getting LinkCB!
//
return;
}
LinkCB->NdisLinkHandle = LineUpInfo->NdisLinkHandle;
LinkCB->ConnectionWrapperID = LineUpInfo->ConnectionWrapperID;
//
// Get a bundlecb
//
BundleCB = NdisWanAllocateBundleCB();
if (BundleCB == NULL) {
//
// Error getting BundleCB!
//
NdisWanFreeLinkCB(LinkCB);
return;
}
AcquireBundleLock(BundleCB);
//
// Copy LineUpInfo to Link LineUpInfo
//
/* NdisMoveMemory((PUCHAR)&LinkCB->LineUpInfo,
(PUCHAR)LineUpInfo,
sizeof(NDIS_MAC_LINE_UP));
*/
//
// If a linkspeed is not reported we are
// assuming 28.8K as the slowest...
//
if (LineUpInfo->LinkSpeed == 0) {
LineUpInfo->LinkSpeed = 288;
}
//
// Take 1/100bps to Bps without rolling over
//
{
ULONGLONG temp;
ULONG value;
temp = LineUpInfo->LinkSpeed;
temp *= 100;
temp /= 8;
//
// Check for rollover
//
value = (ULONG)temp;
if (value == 0) {
value = 0xFFFFFFFF/8;
}
LinkCB->SFlowSpec.TokenRate =
LinkCB->SFlowSpec.PeakBandwidth =
LinkCB->RFlowSpec.TokenRate =
LinkCB->RFlowSpec.PeakBandwidth = (ULONG)value;
}
LinkCB->SFlowSpec.MaxSduSize =
(OpenCB->WanInfo.MaxFrameSize > glMaxMTU) ?
glMaxMTU : OpenCB->WanInfo.MaxFrameSize;
LinkCB->RFlowSpec.MaxSduSize = glMRRU;
//
// Add LinkCB to BundleCB
//
AddLinkToBundle(BundleCB, LinkCB);
ReleaseBundleLock(BundleCB);
//
// Place BundleCB in active connection table
//
if (NULL == InsertBundleInConnectionTable(BundleCB)) {
//
// Error inserting link in ConnectionTable
//
RemoveLinkFromBundle(BundleCB, LinkCB, FALSE);
NdisWanFreeLinkCB(LinkCB);
NdisWanFreeBundleCB(BundleCB);
return;
}
//
// Place LinkCB in active connection table
//
if (NULL == InsertLinkInConnectionTable(LinkCB)) {
//
// Error inserting bundle in connectiontable
//
RemoveLinkFromBundle(BundleCB, LinkCB, FALSE);
NdisWanFreeLinkCB(LinkCB);
NdisWanFreeBundleCB(BundleCB);
return;
}
LineUpInfo->NdisLinkContext = LinkCB->hLinkHandle;
} else {
do {
//
// This is an already existing connetion
//
if (!AreLinkAndBundleValid(LineUpInfo->NdisLinkContext,
TRUE,
&LinkCB,
&BundleCB)) {
#if DBG
DbgPrint("NDISWAN: LineUp on unknown LinkContext %x\n",
LineUpInfo->NdisLinkContext);
DbgBreakPoint();
#endif
break;
}
AcquireBundleLock(BundleCB);
if (LineUpInfo->LinkSpeed == 0) {
LineUpInfo->LinkSpeed = 288;
}
//
// Take 1/100bps to Bps
//
{
ULONGLONG temp;
temp = LineUpInfo->LinkSpeed;
temp *= 100;
temp /= 8;
LinkCB->SFlowSpec.TokenRate =
LinkCB->SFlowSpec.PeakBandwidth =
LinkCB->RFlowSpec.TokenRate =
LinkCB->RFlowSpec.PeakBandwidth = (ULONG)temp;
}
LinkCB->SendWindow = (LineUpInfo->SendWindow > OpenCB->WanInfo.MaxTransmit ||
LineUpInfo->SendWindow == 0) ?
OpenCB->WanInfo.MaxTransmit : LineUpInfo->SendWindow;
//
// If the new sendwindow is set smaller then the
// current # of outstanding frames then we have to
// close the sendwindow for the link and reduce the
// number of sending links that the bundle sees.
//
// If the new sendwindow is set larger then the
// current # of outstanding frames and the sendwindow
// is currently closed, we need to open the sendwindow
// and increase the number of sending links that the
// bundle sees.
//
if (LinkCB->LinkActive) {
if (LinkCB->SendWindow <= LinkCB->OutstandingFrames) {
if (LinkCB->SendWindowOpen) {
LinkCB->SendWindowOpen = FALSE;
BundleCB->SendingLinks -= 1;
}
} else if (!LinkCB->SendWindowOpen) {
LinkCB->SendWindowOpen = TRUE;
BundleCB->SendingLinks += 1;
}
}
//
// Update BundleCB info
//
UpdateBundleInfo(BundleCB);
//
// Deref's for the ref's applied when we mapped the
// context into the control blocks
//
DEREF_BUNDLECB_LOCKED(BundleCB);
DEREF_LINKCB(LinkCB);
} while ( 0 );
}
}
VOID
NdisWanLineDownIndication(
POPENCB OpenCB,
PUCHAR Buffer,
ULONG BufferSize
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PNDIS_MAC_LINE_DOWN LineDownInfo = (PNDIS_MAC_LINE_DOWN)Buffer;
PLINKCB LinkCB;
PBUNDLECB BundleCB;
PRECV_DESC RecvDesc;
ULONG i;
if (!AreLinkAndBundleValid(LineDownInfo->NdisLinkContext,
TRUE,
&LinkCB,
&BundleCB)) {
#if DBG
DbgPrint("NDISWAN: LineDown on unknown LinkContext %x\n",
LineDownInfo->NdisLinkContext);
DbgBreakPoint();
#endif
return;
}
//
// Link is now going down
//
NdisAcquireSpinLock(&LinkCB->Lock);
LinkCB->State = LINK_GOING_DOWN;
//
// Deref for the ref applied in AreLinkAndBundleValid. We don't
// have to go through the full deref code as we know that the
// ref applied at lineup will hold the block around.
//
LinkCB->RefCount--;
NdisReleaseSpinLock(&LinkCB->Lock);
NdisAcquireSpinLock(&IoRecvList.Lock);
RecvDesc = (PRECV_DESC)IoRecvList.DescList.Flink;
while ((PVOID)RecvDesc != (PVOID)&IoRecvList.DescList) {
PRECV_DESC Next;
Next = (PRECV_DESC)RecvDesc->Linkage.Flink;
if (RecvDesc->LinkCB == LinkCB) {
RemoveEntryList(&RecvDesc->Linkage);
LinkCB->RecvDescCount--;
IoRecvList.ulDescCount--;
NdisWanFreeRecvDesc(RecvDesc);
}
RecvDesc = Next;
}
NdisReleaseSpinLock(&IoRecvList.Lock);
//
// Flush the Bundle's fragment send queues that
// have sends pending on this link
//
AcquireBundleLock(BundleCB);
for (i = 0; i < MAX_MCML; i++) {
PSEND_DESC SendDesc;
PSEND_FRAG_INFO FragInfo;
FragInfo = &BundleCB->SendFragInfo[i];
SendDesc = (PSEND_DESC)FragInfo->FragQueue.Flink;
while ((PVOID)SendDesc != (PVOID)&FragInfo->FragQueue) {
if (SendDesc->LinkCB == LinkCB) {
PSEND_DESC NextSendDesc;
NextSendDesc = (PSEND_DESC)SendDesc->Linkage.Flink;
RemoveEntryList(&SendDesc->Linkage);
FragInfo->FragQueueDepth--;
(*LinkCB->SendHandler)(SendDesc);
SendDesc = NextSendDesc;
} else {
SendDesc = (PSEND_DESC)SendDesc->Linkage.Flink;
}
}
}
UpdateBundleInfo(BundleCB);
ReleaseBundleLock(BundleCB);
//
// For the ref from the lineup
//
DEREF_LINKCB(LinkCB);
//
// Deref for the ref applied in AreLinkAndBundleValid
//
DEREF_BUNDLECB(BundleCB);
}
VOID
NdisWanFragmentIndication(
POPENCB OpenCB,
PUCHAR Buffer,
ULONG BufferSize
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
ULONG Errors;
PLINKCB LinkCB;
PBUNDLECB BundleCB;
PNDIS_MAC_FRAGMENT FragmentInfo =
(PNDIS_MAC_FRAGMENT)Buffer;
if (!AreLinkAndBundleValid(FragmentInfo->NdisLinkContext,
TRUE,
&LinkCB,
&BundleCB)) {
#if DBG
DbgPrint("NDISWAN: Status indication after link has gone down LinkContext %x\n",
FragmentInfo->NdisLinkContext);
DbgBreakPoint();
#endif
return;
}
Errors = FragmentInfo->Errors;
AcquireBundleLock(BundleCB);
if (Errors & WAN_ERROR_CRC) {
LinkCB->Stats.CRCErrors++;
BundleCB->Stats.CRCErrors++;
}
if (Errors & WAN_ERROR_FRAMING) {
LinkCB->Stats.FramingErrors++;
BundleCB->Stats.FramingErrors++;
}
if (Errors & WAN_ERROR_HARDWAREOVERRUN) {
LinkCB->Stats.SerialOverrunErrors++;
BundleCB->Stats.SerialOverrunErrors++;
}
if (Errors & WAN_ERROR_BUFFEROVERRUN) {
LinkCB->Stats.BufferOverrunErrors++;
BundleCB->Stats.BufferOverrunErrors++;
}
if (Errors & WAN_ERROR_TIMEOUT) {
LinkCB->Stats.TimeoutErrors++;
BundleCB->Stats.TimeoutErrors++;
}
if (Errors & WAN_ERROR_ALIGNMENT) {
LinkCB->Stats.AlignmentErrors++;
BundleCB->Stats.AlignmentErrors++;
}
//
// Deref's for the ref's applied in AreLinkAndBundleValid
//
DEREF_BUNDLECB_LOCKED(BundleCB);
DEREF_LINKCB(LinkCB);
}
VOID
NdisCoWanFragmentIndication(
PLINKCB LinkCB,
PBUNDLECB BundleCB,
PUCHAR Buffer,
ULONG BufferSize
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
ULONG Errors;
PNDIS_WAN_CO_FRAGMENT FragmentInfo =
(PNDIS_WAN_CO_FRAGMENT)Buffer;
Errors = FragmentInfo->Errors;
AcquireBundleLock(BundleCB);
if (Errors & WAN_ERROR_CRC) {
LinkCB->Stats.CRCErrors++;
BundleCB->Stats.CRCErrors++;
}
if (Errors & WAN_ERROR_FRAMING) {
LinkCB->Stats.FramingErrors++;
BundleCB->Stats.FramingErrors++;
}
if (Errors & WAN_ERROR_HARDWAREOVERRUN) {
LinkCB->Stats.SerialOverrunErrors++;
BundleCB->Stats.SerialOverrunErrors++;
}
if (Errors & WAN_ERROR_BUFFEROVERRUN) {
LinkCB->Stats.BufferOverrunErrors++;
BundleCB->Stats.BufferOverrunErrors++;
}
if (Errors & WAN_ERROR_TIMEOUT) {
LinkCB->Stats.TimeoutErrors++;
BundleCB->Stats.TimeoutErrors++;
}
if (Errors & WAN_ERROR_ALIGNMENT) {
LinkCB->Stats.AlignmentErrors++;
BundleCB->Stats.AlignmentErrors++;
}
ReleaseBundleLock(BundleCB);
}
VOID
NdisCoWanLinkParamChange(
PLINKCB LinkCB,
PBUNDLECB BundleCB,
PUCHAR Buffer,
ULONG BufferSize
)
{
PWAN_CO_LINKPARAMS LinkParams =
(PWAN_CO_LINKPARAMS)Buffer;
if (BufferSize < sizeof(WAN_CO_LINKPARAMS)) {
return;
}
AcquireBundleLock(BundleCB);
NdisWanDbgOut(DBG_TRACE, DBG_INDICATE,
("LinkParamChange: SendWindow %d XmitSpeed %d RecvSpeed %d",
LinkParams->SendWindow, LinkParams->TransmitSpeed, LinkParams->ReceiveSpeed));
LinkCB->SendWindow = LinkParams->SendWindow;
//
// If the new sendwindow is set smaller then the
// current # of outstanding frames then we have to
// close the sendwindow for the link and reduce the
// number of sending links that the bundle sees.
//
// If the new sendwindow is set larger then the
// current # of outstanding frames and the sendwindow
// is currently closed, we need to open the sendwindow
// and increase the number of sending links that the
// bundle sees.
//
if (LinkCB->LinkActive) {
if (LinkCB->SendWindow <= LinkCB->OutstandingFrames) {
if (LinkCB->SendWindowOpen) {
LinkCB->SendWindowOpen = FALSE;
BundleCB->SendingLinks -= 1;
}
} else if (!LinkCB->SendWindowOpen) {
LinkCB->SendWindowOpen = TRUE;
BundleCB->SendingLinks += 1;
}
}
LinkCB->SFlowSpec.PeakBandwidth =
LinkParams->TransmitSpeed;
LinkCB->RFlowSpec.PeakBandwidth =
LinkParams->ReceiveSpeed;
if (LinkCB->SFlowSpec.PeakBandwidth == 0) {
LinkCB->SFlowSpec.PeakBandwidth = 28800 / 8;
}
if (LinkCB->RFlowSpec.PeakBandwidth == 0) {
LinkCB->RFlowSpec.PeakBandwidth = LinkCB->SFlowSpec.PeakBandwidth;
}
UpdateBundleInfo(BundleCB);
ReleaseBundleLock(BundleCB);
}
VOID
UpdateBundleInfo(
PBUNDLECB BundleCB
)
/*++
Routine Name:
Routine Description:
Expects the BundleCB->Lock to be held!
Arguments:
Return Values:
--*/
{
PLINKCB LinkCB;
ULONG SlowestSSpeed, FastestSSpeed;
ULONG SlowestRSpeed, FastestRSpeed;
PPROTOCOLCB ProtocolCB;
PFLOWSPEC BSFlowSpec, BRFlowSpec;
ULONG i;
ULONG SmallestSDU;
LIST_ENTRY TempList;
BSFlowSpec = &BundleCB->SFlowSpec;
BRFlowSpec = &BundleCB->RFlowSpec;
SlowestSSpeed = FastestSSpeed = 0;
SlowestRSpeed = FastestRSpeed = 0;
SmallestSDU = 0;
BSFlowSpec->TokenRate = 0;
BSFlowSpec->PeakBandwidth = 0;
BRFlowSpec->TokenRate = 0;
BRFlowSpec->PeakBandwidth = 0;
BundleCB->SendWindow = 0;
BundleCB->State = BUNDLE_GOING_DOWN;
if (BundleCB->ulLinkCBCount != 0) {
//
// Currently only using the SendSide FastestSpeed so
// just get it from the head of the list.
//
FastestSSpeed =
((PLINKCB)(BundleCB->LinkCBList.Flink))->SFlowSpec.PeakBandwidth;
SmallestSDU =
((PLINKCB)(BundleCB->LinkCBList.Flink))->SFlowSpec.MaxSduSize;
//
// If a link has a speed that is less than the minimum
// link bandwidth (% of the fastests link speed) it is flaged
// as not sending and does not count as a sending link.
//
BundleCB->SendingLinks = 0;
BundleCB->SendResources = 0;
for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
(PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
ULONGLONG n, d, temp;
PFLOWSPEC LSFlowSpec = &LinkCB->SFlowSpec;
PFLOWSPEC LRFlowSpec = &LinkCB->RFlowSpec;
if (LinkCB->State == LINK_UP) {
BundleCB->State = BUNDLE_UP;
}
n = LSFlowSpec->PeakBandwidth;
n *= 100;
d = FastestSSpeed;
temp = n/d;
LinkCB->LinkActive = ((ULONG)temp > glMinLinkBandwidth) ?
TRUE : FALSE;
if (LinkCB->LinkActive) {
BundleCB->SendResources += LinkCB->SendResources;
BundleCB->SendWindow += LinkCB->SendWindow;
if (LinkCB->SendWindowOpen) {
BundleCB->SendingLinks += 1;
}
BSFlowSpec->PeakBandwidth += LSFlowSpec->PeakBandwidth;
BRFlowSpec->PeakBandwidth += LRFlowSpec->PeakBandwidth;
}
if (LinkCB->SFlowSpec.MaxSduSize < SmallestSDU) {
SmallestSDU = LinkCB->SFlowSpec.MaxSduSize;
}
}
BundleCB->SFlowSpec.MaxSduSize = SmallestSDU;
//
// Now calculate the % bandwidth that each links contributes to the
// bundle. If a link has a speed that is less than the minimum
// link bandwidth (% of the fastests link speed) it is flaged
// as not sending and does not count as a sending link.
//
for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
(PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
ULONGLONG n, d, temp;
PFLOWSPEC LSFlowSpec = &LinkCB->SFlowSpec;
PFLOWSPEC LRFlowSpec = &LinkCB->RFlowSpec;
//
// Do sending side
//
n = LSFlowSpec->PeakBandwidth;
n *= 100;
d = BSFlowSpec->PeakBandwidth;
temp = n/d;
LinkCB->SBandwidth = (temp > 0) ? (ULONG)temp : 1;
//
// Do receiving side
//
n = LRFlowSpec->PeakBandwidth;
n *= 100;
d = BRFlowSpec->PeakBandwidth;
temp = n/d;
LinkCB->RBandwidth = (temp > 0) ? (ULONG)temp : 1;
}
BundleCB->NextLinkToXmit =
(PLINKCB)BundleCB->LinkCBList.Flink;
//
// Update the BandwidthOnDemand information
//
if (BundleCB->Flags & BOND_ENABLED) {
PBOND_INFO BonDInfo;
ULONGLONG SecondsInSamplePeriod;
ULONGLONG BytesPerSecond;
ULONGLONG BytesInSamplePeriod;
ULONGLONG temp;
BonDInfo = BundleCB->SUpperBonDInfo;
SecondsInSamplePeriod =
BonDInfo->ulSecondsInSamplePeriod;
BytesPerSecond =
BundleCB->SFlowSpec.PeakBandwidth;
BytesInSamplePeriod =
BytesPerSecond * SecondsInSamplePeriod;
temp = BonDInfo->usPercentBandwidth;
temp *= BytesInSamplePeriod;
temp /= 100;
BonDInfo->ulBytesThreshold = (ULONG)temp;
BonDInfo = BundleCB->SLowerBonDInfo;
SecondsInSamplePeriod =
BonDInfo->ulSecondsInSamplePeriod;
BytesPerSecond =
BundleCB->SFlowSpec.PeakBandwidth;
BytesInSamplePeriod =
BytesPerSecond * SecondsInSamplePeriod;
temp = BonDInfo->usPercentBandwidth;
temp *= BytesInSamplePeriod;
temp /= 100;
BonDInfo->ulBytesThreshold = (ULONG)temp;
BonDInfo = BundleCB->RUpperBonDInfo;
SecondsInSamplePeriod =
BonDInfo->ulSecondsInSamplePeriod;
BytesPerSecond =
BundleCB->RFlowSpec.PeakBandwidth;
BytesInSamplePeriod =
BytesPerSecond * SecondsInSamplePeriod;
temp = BonDInfo->usPercentBandwidth;
temp *= BytesInSamplePeriod;
temp /= 100;
BonDInfo->ulBytesThreshold = (ULONG)temp;
BonDInfo = BundleCB->RLowerBonDInfo;
SecondsInSamplePeriod =
BonDInfo->ulSecondsInSamplePeriod;
BytesPerSecond =
BundleCB->RFlowSpec.PeakBandwidth;
BytesInSamplePeriod =
BytesPerSecond * SecondsInSamplePeriod;
temp = BonDInfo->usPercentBandwidth;
temp *= BytesInSamplePeriod;
temp /= 100;
BonDInfo->ulBytesThreshold = (ULONG)temp;
}
}
//
// We need to do a new lineup to all routed protocols
//
ProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
InitializeListHead(&TempList);
while ((PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList) {
REF_PROTOCOLCB(ProtocolCB);
InsertHeadList(&TempList, &ProtocolCB->RefLinkage);
ProtocolCB =
(PPROTOCOLCB)ProtocolCB->Linkage.Flink;
}
while (!IsListEmpty(&TempList)) {
PLIST_ENTRY Entry;
Entry =
RemoveHeadList(&TempList);
ProtocolCB = CONTAINING_RECORD(Entry, PROTOCOLCB, RefLinkage);
if (BundleCB->State == BUNDLE_UP) {
ReleaseBundleLock(BundleCB);
DoLineUpToProtocol(ProtocolCB);
AcquireBundleLock(BundleCB);
} else {
//
// Our link count has gone to 0. This means
// that we can not send any packets. Flush the
// queues and don't accept any more sends from
// the transports.
//
FlushProtocolPacketQueue(ProtocolCB);
}
DEREF_PROTOCOLCB(ProtocolCB);
}
}
VOID
AddLinkToBundle(
IN PBUNDLECB BundleCB,
IN PLINKCB LinkCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
UINT Class;
//
// Insert the links so that they are ordered with the fastest
// sending link at the head of the list
//
if (IsListEmpty(&BundleCB->LinkCBList) ||
(LinkCB->SFlowSpec.PeakBandwidth >=
((PLINKCB)(BundleCB->LinkCBList.Flink))->SFlowSpec.PeakBandwidth)) {
//
// The list was either empty or this link is a bigger pipe
// than anything else on the bundle
//
InsertHeadList(&BundleCB->LinkCBList, &LinkCB->Linkage);
} else if ((LinkCB->SFlowSpec.PeakBandwidth <=
((PLINKCB)(BundleCB->LinkCBList.Blink))->SFlowSpec.PeakBandwidth)) {
//
// This link is a smaller pipe than anything else
// on the bundle.
//
InsertTailList(&(BundleCB->LinkCBList), &(LinkCB->Linkage));
} else {
PLINKCB Current, Next;
BOOLEAN Inserted = FALSE;
//
// We need to find where this link belongs in the list!
//
Current = (PLINKCB)BundleCB->LinkCBList.Flink;
Next = (PLINKCB)Current->Linkage.Flink;
while ((PVOID)Next != (PVOID)&BundleCB->LinkCBList) {
if (LinkCB->SFlowSpec.PeakBandwidth <= Current->SFlowSpec.PeakBandwidth &&
LinkCB->SFlowSpec.PeakBandwidth >= Next->SFlowSpec.PeakBandwidth) {
LinkCB->Linkage.Flink = (PLIST_ENTRY)Next;
LinkCB->Linkage.Blink = (PLIST_ENTRY)Current;
Current->Linkage.Flink =
Next->Linkage.Blink =
(PLIST_ENTRY)LinkCB;
Inserted = TRUE;
break;
}
Current = Next;
Next = (PLINKCB)Next->Linkage.Flink;
}
if (!Inserted) {
InsertTailList(&(BundleCB->LinkCBList), &(LinkCB->Linkage));
}
}
BundleCB->ulLinkCBCount++;
LinkCB->BundleCB = BundleCB;
for (Class = 0; Class < MAX_MCML; Class++) {
PLINK_RECV_INFO LinkRecvInfo;
PBUNDLE_RECV_INFO BundleRecvInfo;
LinkRecvInfo = &LinkCB->RecvInfo[Class];
BundleRecvInfo = &BundleCB->RecvInfo[Class];
LinkRecvInfo->LastSeqNumber =
BundleRecvInfo->MinSeqNumber;
}
//
// Update BundleCB info
//
UpdateBundleInfo(BundleCB);
REF_BUNDLECB(BundleCB);
}
VOID
RemoveLinkFromBundle(
IN PBUNDLECB BundleCB,
IN PLINKCB LinkCB,
IN BOOLEAN Locked
)
/*++
Routine Name:
Routine Description:
Expects the BundleCB->Lock to be held! Returns with the
lock released!
Arguments:
Return Values:
--*/
{
if (!Locked) {
AcquireBundleLock(BundleCB);
}
//
// Remove link from the bundle
//
RemoveEntryList(&LinkCB->Linkage);
LinkCB->BundleCB = NULL;
BundleCB->ulLinkCBCount--;
BundleCB->SendingLinks--;
//
// Update BundleCB info
//
UpdateBundleInfo(BundleCB);
//
// Deref for ref applied when we added this linkcb to
// the bundle
//
DEREF_BUNDLECB_LOCKED(BundleCB);
}