/*++
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"
VOID
NdisWanLineUpIndication(
PWAN_ADAPTERCB WanAdapterCB,
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;
PBUNDLECB BundleCB;
PPROTOCOLCB ProtocolCB;
NDIS_STATUS Status;
PNDIS_MAC_LINE_UP LineUpInfo = (PNDIS_MAC_LINE_UP)Buffer;
PNDIS_MAC_LINE_UP LinkLineUpInfo;
BOOLEAN EmptyList;
if (BufferSize >= sizeof(NDIS_MAC_LINE_UP)) {
//
// Is this for a new connetion?
//
if (LineUpInfo->NdisLinkContext == NULL) {
//
// This is a new connection!
//
//
// Get a linkcb
//
NdisWanGetLinkCB(&LinkCB,
WanAdapterCB,
LineUpInfo->SendWindow);
if (LinkCB == NULL) {
//
// Error getting LinkCB!
//
return;
}
LinkCB->NdisLinkHandle = LineUpInfo->NdisLinkHandle;
//
// Get a bundlecb
//
NdisWanGetBundleCB(&BundleCB);
if (BundleCB == NULL) {
//
// Error getting BundleCB!
//
NdisWanReturnLinkCB(LinkCB);
return;
}
//
// Copy LineUpInfo to Link LineUpInfo
//
NdisMoveMemory((PUCHAR)&LinkCB->LineUpInfo,
(PUCHAR)LineUpInfo,
sizeof(NDIS_MAC_LINE_UP));
//
// Add LinkCB to BundleCB
//
AddLinkToBundle(BundleCB, LinkCB);
//
// Place BundleCB in active connection table
//
InsertBundleInConnectionTable(BundleCB);
//
// Place LinkCB in active connection table
//
InsertLinkInConnectionTable(LinkCB);
LineUpInfo->NdisLinkContext = (NDIS_HANDLE)LinkCB->hLinkHandle;
} else {
//
// This is an already existing connetion
//
LINKCB_FROM_LINKH(LinkCB, LineUpInfo->NdisLinkContext);
if (LinkCB == NULL) {
#if DBG
DbgPrint("NDISWAN.SYS: Invalid LinkContext (0x%8.8x) in LineUp!",
LineUpInfo->NdisLinkContext);
#endif
return;
}
BundleCB = BUNDLECB_FROM_LINKCB(LinkCB);
if (BundleCB == NULL) {
#if DBG
DbgPrint("NDISWAN.SYS: Invalid BundleCB in LineUp, BundleCB: 0x%8.8x, LinkCB: 0x%8.8x\n",
LinkCB, BundleCB);
#endif
return;
}
NdisAcquireSpinLock(&BundleCB->Lock);
LinkLineUpInfo = &LinkCB->LineUpInfo;
LinkLineUpInfo->LinkSpeed = LineUpInfo->LinkSpeed;
LinkLineUpInfo->Quality = LineUpInfo->Quality;
LinkLineUpInfo->SendWindow = LineUpInfo->SendWindow;
//
// Update BundleCB info
//
UpdateBundleInfo(BundleCB);
NdisReleaseSpinLock(&BundleCB->Lock);
}
}
}
VOID
NdisWanLineDownIndication(
PWAN_ADAPTERCB WanAdapterCB,
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;
PPROTOCOLCB ProtocolCB;
BOOLEAN FreeBundle = FALSE;
BOOLEAN FreeLink = FALSE;
LINKCB_FROM_LINKH(LinkCB, (ULONG)LineDownInfo->NdisLinkContext);
if (LinkCB == NULL) {
return;
}
BundleCB = LinkCB->BundleCB;
NdisAcquireSpinLock(&BundleCB->Lock);
//
// Link is now going down
//
LinkCB->State = LINK_GOING_DOWN;
//
// If there are not any frames pending on this
// link we will go ahead and free it's resources.
// If there are frames pending the resources will
// be freed in the sendcomplete routine.
//
if (LinkCB->OutstandingFrames == 0) {
//
// Mark this link as being down
//
LinkCB->State = LINK_DOWN;
FreeLink = TRUE;
//
// Remove the link from the bundle
//
RemoveLinkFromBundle(BundleCB, LinkCB);
}
//
// If this bundle's link count has gone to
// zero and it is not been routed yet no
// user-mode component will be freeing the
// resources so we may need to free the
// resources.
//
if (BundleCB->ulLinkCBCount == 0) {
BundleCB->State = BUNDLE_GOING_DOWN;
//
// If there are not any frames pending on this
// bundle so we need to free it's resources now.
// If there are frames pending the resources will
// be freed in the sendcomplete routine.
//
if ((BundleCB->OutstandingFrames == 0) &&
!(BundleCB->Flags & BUNDLE_ROUTED)) {
BundleCB->State = BUNDLE_DOWN;
FreeBundle = TRUE;
}
}
NdisReleaseSpinLock(&BundleCB->Lock);
if (FreeLink) {
//
// Remove this link from the connection table
//
RemoveLinkFromConnectionTable(LinkCB);
NdisWanReturnLinkCB(LinkCB);
}
if (FreeBundle) {
//
// Remove this bundle from the connection table
//
RemoveBundleFromConnectionTable(BundleCB);
NdisWanReturnBundleCB(BundleCB);
}
}
VOID
NdisWanFragmentIndication(
PWAN_ADAPTERCB WanAdapterCB,
PUCHAR Buffer,
ULONG BufferSize
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PNDIS_MAC_FRAGMENT FragmentInfo = (PNDIS_MAC_FRAGMENT)Buffer;
PLINKCB LinkCB;
PBUNDLECB BundleCB;
LINKCB_FROM_LINKH(LinkCB, (ULONG)FragmentInfo->NdisLinkContext);
if (LinkCB == NULL) {
return;
}
BundleCB = LinkCB->BundleCB;
if (BundleCB == NULL) {
return;
}
NdisAcquireSpinLock(&BundleCB->Lock);
if (FragmentInfo->Errors & WAN_ERROR_CRC) {
LinkCB->LinkStats.CRCErrors++;
BundleCB->BundleStats.CRCErrors++;
}
if (FragmentInfo->Errors & WAN_ERROR_FRAMING) {
LinkCB->LinkStats.FramingErrors++;
BundleCB->BundleStats.FramingErrors++;
}
if (FragmentInfo->Errors & WAN_ERROR_HARDWAREOVERRUN) {
LinkCB->LinkStats.SerialOverrunErrors++;
BundleCB->BundleStats.SerialOverrunErrors++;
}
if (FragmentInfo->Errors & WAN_ERROR_BUFFEROVERRUN) {
LinkCB->LinkStats.BufferOverrunErrors++;
BundleCB->BundleStats.BufferOverrunErrors++;
}
if (FragmentInfo->Errors & WAN_ERROR_TIMEOUT) {
LinkCB->LinkStats.TimeoutErrors++;
BundleCB->BundleStats.TimeoutErrors++;
}
if (FragmentInfo->Errors & WAN_ERROR_ALIGNMENT) {
LinkCB->LinkStats.AlignmentErrors++;
BundleCB->BundleStats.AlignmentErrors++;
}
NdisReleaseSpinLock(&BundleCB->Lock);
}
VOID
UpdateBundleInfo(
PBUNDLECB BundleCB
)
/*++
Routine Name:
Routine Description:
Expects the BundleCB->Lock to be held!
Arguments:
Return Values:
--*/
{
PLINKCB LinkCB;
ULONG SlowestLink;
PPROTOCOLCB ProtocolCB, IoProtocolCB;
#ifdef BANDWIDTH_ON_DEMAND
ULONG SecondsInSamplePeriod;
ULONG BytesPerSecond;
ULONG BytesInSamplePeriod;
#endif // end of BANDWIDTH_ON_DEMAND
//
// If there are any links attached to this bundlecb we will
// update the bundlecb's info
//
if (BundleCB->ulLinkCBCount != 0) {
PBUNDLE_LINE_UP BundleLineUpInfo = &BundleCB->LineUpInfo;
SlowestLink =
BundleLineUpInfo->BundleSpeed = 0;
BundleLineUpInfo->usSendWindow = 0;
BundleLineUpInfo->Quality = NdisWanReliable;
//
// Walk the LinkCBList and update the bundle's info
//
for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
(PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
PWAN_ADAPTERCB WanAdapterCB = LinkCB->WanAdapterCB;
PNDIS_MAC_LINE_UP LinkLineUpInfo = &LinkCB->LineUpInfo;
//
// Bundle link speed is total of all links. Keep track
// of slowest link for multilink recv desc's time to live.
//
BundleLineUpInfo->BundleSpeed += LinkLineUpInfo->LinkSpeed;
if ((LinkLineUpInfo->LinkSpeed < SlowestLink) || (SlowestLink == 0)) {
SlowestLink = LinkLineUpInfo->LinkSpeed;
}
//
// Bundle send windows is the total of all links
//
BundleLineUpInfo->usSendWindow += LinkLineUpInfo->SendWindow;
//
// Bundle line quality is the worst of all links
//
if (BundleLineUpInfo->Quality < LinkLineUpInfo->Quality) {
BundleLineUpInfo->Quality = LinkLineUpInfo->Quality;
}
}
#if 0
//
// Update the time to live for multilink recv desc's. This is in ms and
// is the time it would take to receive a complete frame of size MRRU
// across the slowest link in the bundle. Value must be a multiple of
// 100ms with a minimum value of 1sec. If the slowest link in the bundle is
// slower than a 28.8K modem we will increase the timeout value by 2
//
if (SlowestLink == 0) {
SlowestLink = 288;
}
BundleCB->TimeToLive =
(BundleCB->FramingInfo.MaxRRecvFrameSize * 1000) /
((SlowestLink * 100) / 8);
if (SlowestLink < 64) {
BundleCB->TimeToLive *= 2;
}
BundleCB->TimeToLive |= 0x3E8;
BundleCB->TimeToLive /= 0x64;
BundleCB->TimeToLive *= 0x64;
#endif
//
// Now calculate the % bandwidth that each links contributes to the
// bundle.
//
BundleCB->NextLinkToXmit = (PLINKCB)BundleCB->LinkCBList.Flink;
for (LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
(PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
if (LinkCB->LineUpInfo.LinkSpeed != 0) {
ULONG n, d, temp;
d = BundleCB->LineUpInfo.BundleSpeed;
n = LinkCB->LineUpInfo.LinkSpeed * 100;
LinkCB->ulBandwidth = (temp = (n / d)) ? temp : 1;
} else {
LinkCB->ulBandwidth = 1;
}
if (LinkCB->ulBandwidth > ((PLINKCB)(BundleCB->NextLinkToXmit))->ulBandwidth) {
BundleCB->NextLinkToXmit = LinkCB;
}
}
#ifdef BANDWIDTH_ON_DEMAND
//
// Update the BandwidthOnDemand information
//
SecondsInSamplePeriod = BundleCB->UpperBonDInfo.ulSecondsInSamplePeriod;
BytesPerSecond = BundleCB->LineUpInfo.BundleSpeed * 100 / 8;
BytesInSamplePeriod = BytesPerSecond * SecondsInSamplePeriod;
BundleCB->UpperBonDInfo.ulBytesThreshold = BytesInSamplePeriod *
BundleCB->UpperBonDInfo.usPercentBandwidth / 100;
SecondsInSamplePeriod = BundleCB->LowerBonDInfo.ulSecondsInSamplePeriod;
BytesPerSecond = BundleCB->LineUpInfo.BundleSpeed * 100 / 8;
BytesInSamplePeriod = BytesPerSecond * SecondsInSamplePeriod;
BundleCB->LowerBonDInfo.ulBytesThreshold = BytesInSamplePeriod *
BundleCB->LowerBonDInfo.usPercentBandwidth / 100;
#endif // end of BANDWIDTH_ON_DEMAND
//
// We need to do a new lineup to all routed protocols skipping
// the IoProtocolCB!
//
IoProtocolCB = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
for (ProtocolCB = (PPROTOCOLCB)IoProtocolCB->Linkage.Flink;
(PVOID)ProtocolCB != (PVOID)&BundleCB->ProtocolCBList;
ProtocolCB = (PPROTOCOLCB)ProtocolCB->Linkage.Flink) {
#ifdef BANDWIDTH_ON_DEMAND
ProtocolCB->ulByteQuota =
(BytesPerSecond * ProtocolCB->usPriority) / 100;
#endif // end of BANDWIDTH_ON_DEMAND
NdisReleaseSpinLock(&BundleCB->Lock);
DoLineUpToProtocol(ProtocolCB);
NdisAcquireSpinLock(&BundleCB->Lock);
}
}
}
VOID
AddLinkToBundle(
IN PBUNDLECB BundleCB,
IN PLINKCB LinkCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NdisAcquireSpinLock(&(BundleCB->Lock));
InsertTailList(&(BundleCB->LinkCBList), &(LinkCB->Linkage));
BundleCB->ulLinkCBCount++;
BundleCB->SendingLinks++;
LinkCB->BundleCB = BundleCB;
LinkCB->LastRecvSeqNumber = BundleCB->MinReceivedSeqNumber;
//
// Update BundleCB Info
//
UpdateBundleInfo(BundleCB);
NdisReleaseSpinLock(&(BundleCB->Lock));
}
VOID
RemoveLinkFromBundle(
IN PBUNDLECB BundleCB,
IN PLINKCB LinkCB
)
/*++
Routine Name:
Routine Description:
Expects the BundleCB->Lock to be held!
Arguments:
Return Values:
--*/
{
//
// Remove link from the bundle
//
RemoveEntryList(&LinkCB->Linkage);
LinkCB->BundleCB = NULL;
BundleCB->ulLinkCBCount--;
BundleCB->SendingLinks--;
//
// Update BundleCB LineUp Info
//
UpdateBundleInfo(BundleCB);
}