612 lines
12 KiB
C
612 lines
12 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"
|
|
|
|
|
|
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);
|
|
|
|
}
|