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