/*++ Copyright (c) 1990-1995 Microsoft Corporation Module Name: Util.c Abstract: This file contains utility functions used by NdisWan. Author: Tony Bell (TonyBe) June 06, 1995 Environment: Kernel Mode Revision History: TonyBe 06/06/95 Created --*/ #include "wan.h" #define __FILE_SIG__ UTIL_FILESIG VOID NdisWanCopyFromPacketToBuffer( IN PNDIS_PACKET pNdisPacket, IN ULONG Offset, IN ULONG BytesToCopy, OUT PUCHAR Buffer, OUT PULONG BytesCopied ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { ULONG NdisBufferCount; PNDIS_BUFFER CurrentBuffer; PVOID VirtualAddress; ULONG CurrentLength, AmountToMove; ULONG LocalBytesCopied = 0, PacketLength; *BytesCopied = 0; // // Take care of zero byte copy // if (!BytesToCopy) { return; } // // Get the buffer count // NdisQueryPacket(pNdisPacket, NULL, &NdisBufferCount, &CurrentBuffer, &PacketLength); // // Could be a null packet // if (!NdisBufferCount || Offset == PacketLength) { return; } NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength); while (LocalBytesCopied < BytesToCopy && LocalBytesCopied < PacketLength) { // // No more bytes left in this buffer // if (!CurrentLength) { // // Get the next buffer // NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer); // // End of the packet, copy what we can // if (CurrentBuffer == NULL) { break; } // // // NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength); if (!CurrentLength) { continue; } } // // Get to the point where we can start copying // if (Offset) { if (Offset > CurrentLength) { // // Not in this buffer, go to the next one // Offset -= CurrentLength; CurrentLength = 0; continue; } else { // // At least some in this buffer // VirtualAddress = (PUCHAR)VirtualAddress + Offset; CurrentLength -= Offset; Offset = 0; } } if (!CurrentLength) { continue; } // // We can copy some data. If we need more data than is available // in this buffer we can copy what we need and go back for more. // AmountToMove = (CurrentLength > (BytesToCopy - LocalBytesCopied)) ? (BytesToCopy - LocalBytesCopied) : CurrentLength; NdisMoveMemory(Buffer, VirtualAddress, AmountToMove); Buffer = (PUCHAR)Buffer + AmountToMove; VirtualAddress = (PUCHAR)VirtualAddress + AmountToMove; LocalBytesCopied += AmountToMove; CurrentLength -= AmountToMove; } *BytesCopied = LocalBytesCopied; } VOID NdisWanCopyFromBufferToPacket( PUCHAR Buffer, ULONG BytesToCopy, PNDIS_PACKET NdisPacket, ULONG PacketOffset, PULONG BytesCopied ) { PNDIS_BUFFER NdisBuffer; ULONG NdisBufferCount, NdisBufferLength; PVOID VirtualAddress; ULONG LocalBytesCopied = 0; *BytesCopied = 0; // // Make sure we actually want to do something // if (BytesToCopy == 0) { return; } // // Get the buffercount of the packet // NdisQueryPacket(NdisPacket, NULL, &NdisBufferCount, &NdisBuffer, NULL); // // Make sure this is not a null packet // if (NdisBufferCount == 0) { return; } // // Get first buffer and buffer length // NdisQueryBuffer(NdisBuffer, &VirtualAddress, &NdisBufferLength); while (LocalBytesCopied < BytesToCopy) { if (NdisBufferLength == 0) { NdisGetNextBuffer(NdisBuffer, &NdisBuffer); if (NdisBuffer == NULL) { break; } NdisQueryBuffer(NdisBuffer, &VirtualAddress, &NdisBufferLength); continue; } if (PacketOffset != 0) { if (PacketOffset > NdisBufferLength) { PacketOffset -= NdisBufferLength; NdisBufferLength = 0; continue; } else { VirtualAddress = (PUCHAR)VirtualAddress + PacketOffset; NdisBufferLength -= PacketOffset; PacketOffset = 0; } } // // Copy the data // { ULONG AmountToMove; ULONG AmountRemaining; AmountRemaining = BytesToCopy - LocalBytesCopied; AmountToMove = (NdisBufferLength < AmountRemaining) ? NdisBufferLength : AmountRemaining; NdisMoveMemory((PUCHAR)VirtualAddress, Buffer, AmountToMove); Buffer += AmountToMove; LocalBytesCopied += AmountToMove; NdisBufferLength -= AmountToMove; } } *BytesCopied = LocalBytesCopied; } BOOLEAN IsLinkValid( NDIS_HANDLE LinkHandle, BOOLEAN CheckState, PLINKCB *LinkCB ) { PLINKCB plcb; LOCK_STATE LockState; BOOLEAN Valid; *LinkCB = NULL; Valid = FALSE; NdisAcquireReadWriteLock(&ConnTableLock, FALSE, &LockState); do { if (PtrToUlong(LinkHandle) > ConnectionTable->ulArraySize) { break; } plcb = *(ConnectionTable->LinkArray + PtrToUlong(LinkHandle)); if (plcb == NULL) { break; } NdisDprAcquireSpinLock(&plcb->Lock); if (CheckState && (plcb->State != LINK_UP)) { NdisDprReleaseSpinLock(&plcb->Lock); break; } REF_LINKCB(plcb); NdisDprReleaseSpinLock(&plcb->Lock); *LinkCB = plcb; Valid = TRUE; } while (FALSE); NdisReleaseReadWriteLock(&ConnTableLock, &LockState); return (Valid); } BOOLEAN IsBundleValid( NDIS_HANDLE BundleHandle, BOOLEAN CheckState, PBUNDLECB *BundleCB ) { PBUNDLECB pbcb; LOCK_STATE LockState; BOOLEAN Valid; *BundleCB = NULL; Valid = FALSE; NdisAcquireReadWriteLock(&ConnTableLock, FALSE, &LockState); do { if (PtrToUlong(BundleHandle) > ConnectionTable->ulArraySize) { break; } pbcb = *(ConnectionTable->BundleArray + PtrToUlong(BundleHandle)); if (pbcb == NULL) { break; } NdisDprAcquireSpinLock(&pbcb->Lock); if (CheckState && (pbcb->State != BUNDLE_UP)) { NdisDprReleaseSpinLock(&pbcb->Lock); break; } REF_BUNDLECB(pbcb); NdisDprReleaseSpinLock(&pbcb->Lock); *BundleCB = pbcb; Valid = TRUE; } while (FALSE); NdisReleaseReadWriteLock(&ConnTableLock, &LockState); return (Valid); } BOOLEAN AreLinkAndBundleValid( NDIS_HANDLE LinkHandle, BOOLEAN CheckState, PLINKCB *LinkCB, PBUNDLECB *BundleCB ) { PLINKCB plcb; PBUNDLECB pbcb; LOCK_STATE LockState; BOOLEAN Valid; *LinkCB = NULL; *BundleCB = NULL; Valid = FALSE; NdisAcquireReadWriteLock(&ConnTableLock, FALSE, &LockState); do { if (PtrToUlong(LinkHandle) > ConnectionTable->ulArraySize) { break; } plcb = *(ConnectionTable->LinkArray + PtrToUlong(LinkHandle)); if (plcb == NULL) { break; } NdisDprAcquireSpinLock(&plcb->Lock); if (CheckState && (plcb->State != LINK_UP)) { NdisDprReleaseSpinLock(&plcb->Lock); break; } pbcb = plcb->BundleCB; if (pbcb == NULL) { NdisDprReleaseSpinLock(&plcb->Lock); break; } REF_LINKCB(plcb); NdisDprReleaseSpinLock(&plcb->Lock); NdisDprAcquireSpinLock(&pbcb->Lock); REF_BUNDLECB(pbcb); NdisDprReleaseSpinLock(&pbcb->Lock); *LinkCB = plcb; *BundleCB = pbcb; Valid = TRUE; } while (FALSE); NdisReleaseReadWriteLock(&ConnTableLock, &LockState); return (Valid); } // // Called with BundleCB->Lock held // VOID DoDerefBundleCBWork( PBUNDLECB BundleCB ) { ASSERT(BundleCB->State == BUNDLE_GOING_DOWN); ASSERT(BundleCB->OutstandingFrames == 0); ASSERT(BundleCB->ulNumberOfRoutes == 0); ASSERT(BundleCB->ulLinkCBCount == 0); ReleaseBundleLock(BundleCB); RemoveBundleFromConnectionTable(BundleCB); NdisWanFreeBundleCB(BundleCB); } // // Called with LinkCB->Lock held // VOID DoDerefLinkCBWork( PLINKCB LinkCB ) { PBUNDLECB _pbcb = LinkCB->BundleCB; ASSERT(LinkCB->State == LINK_GOING_DOWN); ASSERT(LinkCB->OutstandingFrames == 0); NdisReleaseSpinLock(&LinkCB->Lock); RemoveLinkFromBundle(_pbcb, LinkCB, FALSE); RemoveLinkFromConnectionTable(LinkCB); NdisWanFreeLinkCB(LinkCB); } // // // VOID DoDerefCmVcCBWork( PCM_VCCB VcCB ) { InterlockedExchange((PLONG)&(VcCB)->State, CMVC_DEACTIVE); NdisMCmDeactivateVc(VcCB->NdisVcHandle); NdisMCmCloseCallComplete(NDIS_STATUS_SUCCESS, VcCB->NdisVcHandle, NULL); } // // Called with ClAfSap->Lock held // VOID DoDerefClAfSapCBWork( PCL_AFSAPCB AfSapCB ) { NDIS_STATUS Status; ASSERT(AfSapCB->Flags & SAP_REGISTERED); if (AfSapCB->Flags & SAP_REGISTERED) { AfSapCB->Flags &= ~(SAP_REGISTERED); AfSapCB->Flags |= (SAP_DEREGISTERING); NdisReleaseSpinLock(&AfSapCB->Lock); Status = NdisClDeregisterSap(AfSapCB->SapHandle); if (Status != NDIS_STATUS_PENDING) { ClDeregisterSapComplete(Status, AfSapCB); } } else { NdisReleaseSpinLock(&AfSapCB->Lock); } } VOID DerefVc( PLINKCB LinkCB ) { // // Ref applied when we sent the packet to the underlying // miniport // LinkCB->VcRefCount--; if ((LinkCB->ClCallState == CL_CALL_CLOSE_PENDING) && (LinkCB->VcRefCount == 0) ) { NDIS_STATUS CloseStatus; LinkCB->ClCallState = CL_CALL_CLOSED; NdisReleaseSpinLock(&LinkCB->Lock); CloseStatus = NdisClCloseCall(LinkCB->NdisLinkHandle, NULL, NULL, 0); if (CloseStatus != NDIS_STATUS_PENDING) { ClCloseCallComplete(CloseStatus, LinkCB, NULL); } NdisAcquireSpinLock(&LinkCB->Lock); } } VOID DeferredWorker( PKDPC Dpc, PVOID Context, PVOID Arg1, PVOID Arg2 ) { NdisAcquireSpinLock(&DeferredWorkList.Lock); while (!(IsListEmpty(&DeferredWorkList.List))) { PLIST_ENTRY Entry; PBUNDLECB BundleCB; Entry = RemoveHeadList(&DeferredWorkList.List); DeferredWorkList.ulCount--; NdisReleaseSpinLock(&DeferredWorkList.Lock); BundleCB = CONTAINING_RECORD(Entry, BUNDLECB, DeferredLinkage); AcquireBundleLock(BundleCB); BundleCB->Flags &= ~DEFERRED_WORK_QUEUED; // // Do all of the deferred work items for this Bundle // SendPacketOnBundle(BundleCB); // // Deref for the ref applied when we inserted this item on // the worker queue. // DEREF_BUNDLECB(BundleCB); NdisAcquireSpinLock(&DeferredWorkList.Lock); } DeferredWorkList.TimerScheduled = FALSE; NdisReleaseSpinLock(&DeferredWorkList.Lock); } #ifdef NT VOID NdisWanStringToNdisString( PNDIS_STRING pDestString, PWSTR pSrcBuffer ) { PWSTR Dest, Src = pSrcBuffer; NDIS_STRING SrcString; NdisInitUnicodeString(&SrcString, pSrcBuffer); NdisWanAllocateMemory(&pDestString->Buffer, SrcString.MaximumLength, NDISSTRING_TAG); if (pDestString->Buffer == NULL) { return; } pDestString->MaximumLength = SrcString.MaximumLength; pDestString->Length = SrcString.Length; RtlCopyUnicodeString(pDestString, &SrcString); } VOID NdisWanFreeNdisString( PNDIS_STRING NdisString ) { if (NdisString->Buffer != NULL) { NdisWanFreeMemory(NdisString->Buffer); } } VOID NdisWanAllocateAdapterName( PNDIS_STRING Dest, PNDIS_STRING Src ) { NdisWanAllocateMemory(&Dest->Buffer, Src->MaximumLength, NDISSTRING_TAG); if (Dest->Buffer != NULL) { Dest->MaximumLength = Src->MaximumLength; Dest->Length = Src->Length; RtlUpcaseUnicodeString(Dest, Src, FALSE); } } //VOID //NdisWanFreeNdisString( // PNDIS_STRING NdisString // ) //{ // NdisFreeMemory(NdisString->Buffer, // NdisString->MaximumLength * sizeof(WCHAR), // 0); //} VOID NdisWanNdisStringToInteger( PNDIS_STRING Source, PULONG Value ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { PWSTR s = Source->Buffer; ULONG Digit; *Value = 0; while (*s != UNICODE_NULL) { if (*s >= L'0' && *s < L'9') { Digit = *s - L'0'; } else if (*s >= L'A' && *s <= L'F') { Digit = *s - L'A' + 10; } else if (*s >= L'a' && *s <= L'f') { Digit = *s - L'a' + 10; } else { break; } *Value = (*Value << 4) | Digit; s++; } } VOID NdisWanCopyNdisString( PNDIS_STRING Dest, PNDIS_STRING Src ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { PWSTR SrcBuffer = Src->Buffer; PWSTR DestBuffer = Dest->Buffer; while (*SrcBuffer != UNICODE_NULL) { *DestBuffer = *SrcBuffer; SrcBuffer++; DestBuffer++; } *DestBuffer = UNICODE_NULL; Dest->Length = Src->Length; } VOID BonDWorker( PKDPC Dpc, PVOID Context, PVOID Arg1, PVOID Arg2 ) { PLIST_ENTRY Entry; NdisAcquireSpinLock(&BonDWorkList.Lock); for (Entry = BonDWorkList.List.Flink; Entry != &BonDWorkList.List; Entry = Entry->Flink) { PBUNDLECB BundleCB; BundleCB = CONTAINING_RECORD(Entry, BUNDLECB, BonDLinkage); NdisReleaseSpinLock(&BonDWorkList.Lock); AcquireBundleLock(BundleCB); if (BundleCB->State != BUNDLE_UP || !(BundleCB->Flags & BOND_ENABLED)) { ReleaseBundleLock(BundleCB); NdisAcquireSpinLock(&BonDWorkList.Lock); continue; } AgeSampleTable(&BundleCB->SUpperBonDInfo->SampleTable); CheckUpperThreshold(BundleCB); AgeSampleTable(&BundleCB->SLowerBonDInfo->SampleTable); CheckLowerThreshold(BundleCB); AgeSampleTable(&BundleCB->RUpperBonDInfo->SampleTable); CheckUpperThreshold(BundleCB); AgeSampleTable(&BundleCB->RLowerBonDInfo->SampleTable); CheckUpperThreshold(BundleCB); ReleaseBundleLock(BundleCB); NdisAcquireSpinLock(&BonDWorkList.Lock); } NdisReleaseSpinLock(&BonDWorkList.Lock); } #if 0 VOID CheckBonDInfo( PKDPC Dpc, PBUNDLECB BundleCB, PVOID SysArg1, PVOID SysArg2 ) { if (!(BundleCB->Flags & BOND_ENABLED)) { return; } AgeSampleTable(&BundleCB->SUpperBonDInfo.SampleTable); CheckUpperThreshold(BundleCB); AgeSampleTable(&BundleCB->SLowerBonDInfo.SampleTable); CheckLowerThreshold(BundleCB); AgeSampleTable(&BundleCB->RUpperBonDInfo.SampleTable); CheckUpperThreshold(BundleCB); AgeSampleTable(&BundleCB->RLowerBonDInfo.SampleTable); CheckUpperThreshold(BundleCB); } #endif VOID AgeSampleTable( PSAMPLE_TABLE SampleTable ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { WAN_TIME CurrentTime, TimeDiff; ULONG HeadIndex = SampleTable->ulHead; // // Should return CurrentTime in 100ns units // NdisWanGetSystemTime(&CurrentTime); // // We will search through the sample indexing over samples that are more than // one second older than the current time. // while (!IsSampleTableEmpty(SampleTable) ) { PBOND_SAMPLE FirstSample; FirstSample = &SampleTable->SampleArray[SampleTable->ulHead]; NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &FirstSample->TimeStamp); if (NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) break; SampleTable->ulCurrentSampleByteCount -= FirstSample->ulBytes; ASSERT((LONG)SampleTable->ulCurrentSampleByteCount >= 0); FirstSample->ulReferenceCount = 0; if (++SampleTable->ulHead == SampleTable->ulSampleArraySize) { SampleTable->ulHead = 0; } SampleTable->ulSampleCount--; } if (IsSampleTableEmpty(SampleTable)) { ASSERT((LONG)SampleTable->ulCurrentSampleByteCount == 0); SampleTable->ulHead = SampleTable->ulCurrent; } } VOID UpdateSampleTable( PSAMPLE_TABLE SampleTable, ULONG Bytes ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { WAN_TIME CurrentTime, TimeDiff; ULONG CurrentIndex = SampleTable->ulCurrent; PBOND_SAMPLE CurrentSample = &SampleTable->SampleArray[CurrentIndex]; NdisWanGetSystemTime(&CurrentTime); NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &CurrentSample->TimeStamp); if (NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SampleRate) || IsSampleTableFull(SampleTable)) { // // Add this send on the previous sample // CurrentSample->ulBytes += Bytes; CurrentSample->ulReferenceCount++; } else { ULONG NextIndex; // // We need a new sample // if (IsSampleTableEmpty(SampleTable)) { NextIndex = SampleTable->ulHead; ASSERT(NextIndex == SampleTable->ulCurrent); } else { NextIndex = SampleTable->ulCurrent + 1; } if (NextIndex == SampleTable->ulSampleArraySize) { NextIndex = 0; } SampleTable->ulCurrent = NextIndex; CurrentSample = &SampleTable->SampleArray[NextIndex]; CurrentSample->TimeStamp = CurrentTime; CurrentSample->ulBytes = Bytes; CurrentSample->ulReferenceCount = 1; SampleTable->ulSampleCount++; ASSERT(SampleTable->ulSampleCount <= SampleTable->ulSampleArraySize); } SampleTable->ulCurrentSampleByteCount += Bytes; } VOID UpdateBandwidthOnDemand( PBOND_INFO BonDInfo, ULONG Bytes ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { PSAMPLE_TABLE SampleTable = &BonDInfo->SampleTable; // // Age and update the sample table // AgeSampleTable(SampleTable); UpdateSampleTable(SampleTable, Bytes); } VOID CheckUpperThreshold( PBUNDLECB BundleCB ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { WAN_TIME CurrentTime, TimeDiff; PBOND_INFO BonDInfo; PSAMPLE_TABLE SampleTable; ULONGLONG Bps; BOOLEAN SSignal, RSignal; // // First check send side // BonDInfo = BundleCB->SUpperBonDInfo; SSignal = FALSE; SampleTable = &BonDInfo->SampleTable; Bps = SampleTable->ulCurrentSampleByteCount; // // Switch on the current state // switch (BonDInfo->State) { case BonDSignaled: break; case BonDIdle: // // We are currently below the upper threshold. If we // go over the upperthreshold we will set the time and // transition to the monitor state. // if (Bps >= BonDInfo->ulBytesThreshold) { NdisWanGetSystemTime(&BonDInfo->StartTime); BonDInfo->State = BonDMonitor; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("U-S: i -> m, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); } break; case BonDMonitor: // // We are currently in the monitor state which means that // we have gone above the upper threshold. If we fall below // the upper threshold we will go back to the idle state. // if (Bps < BonDInfo->ulBytesThreshold) { NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("U-S: m -> i, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); BonDInfo->State = BonDIdle; } else { NdisWanGetSystemTime(&CurrentTime); NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime); if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) { SSignal = TRUE; } } break; } // // Now check the receive side // BonDInfo = BundleCB->RUpperBonDInfo; RSignal = FALSE; SampleTable = &BonDInfo->SampleTable; Bps = SampleTable->ulCurrentSampleByteCount; switch (BonDInfo->State) { case BonDSignaled: break; case BonDIdle: // // We are currently below the upper threshold. If we // go over the upperthreshold we will set the time and // transition to the monitor state. // if (Bps >= BonDInfo->ulBytesThreshold) { NdisWanGetSystemTime(&BonDInfo->StartTime); BonDInfo->State = BonDMonitor; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("U-R: i -> m, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); } break; case BonDMonitor: // // We are currently in the monitor state which means that // we have gone above the upper threshold. If we fall below // the upper threshold we will go back to the idle state. // if (Bps < BonDInfo->ulBytesThreshold) { NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("U-R: m -> i, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); BonDInfo->State = BonDIdle; } else { NdisWanGetSystemTime(&CurrentTime); NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime); if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) { RSignal = TRUE; } } break; } if (SSignal || RSignal) { // // We have been above the threshold for time greater than the // threshold sample period so we need to notify someone of this // historic event! // CompleteThresholdEvent(BundleCB, BonDInfo->DataType, UPPER_THRESHOLD); BundleCB->SUpperBonDInfo->State = BonDSignaled; BundleCB->RUpperBonDInfo->State = BonDSignaled; #if DBG { ULONGLONG util; util = BundleCB->SUpperBonDInfo->SampleTable.ulCurrentSampleByteCount; util *= 100; util /= BundleCB->SUpperBonDInfo->ulBytesInSamplePeriod; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("U-S: Bps %I64d Threshold %I64d Util %I64d", Bps, BundleCB->SUpperBonDInfo->ulBytesThreshold, util)); util = BundleCB->RUpperBonDInfo->SampleTable.ulCurrentSampleByteCount; util *= 100; util /= BundleCB->RUpperBonDInfo->ulBytesInSamplePeriod; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("U-R: Bps %I64d Threshold %I64d Util %I64d", Bps, BundleCB->RUpperBonDInfo->ulBytesThreshold, util)); } #endif } } VOID CheckLowerThreshold( PBUNDLECB BundleCB ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { WAN_TIME CurrentTime, TimeDiff; PBOND_INFO BonDInfo; PSAMPLE_TABLE SampleTable; ULONGLONG Bps; BOOLEAN SSignal, RSignal; if (!(BundleCB->Flags & BOND_ENABLED)) { return; } // // First check send side // BonDInfo = BundleCB->SLowerBonDInfo; SampleTable = &BonDInfo->SampleTable; Bps = SampleTable->ulCurrentSampleByteCount; SSignal = FALSE; // // Switch on the current state // switch (BonDInfo->State) { case BonDIdle: // // We are currently above the lower threshold. If we // go under the lowerthreshold we will set the time and // transition to the monitor state. // if (Bps <= BonDInfo->ulBytesThreshold) { NdisWanGetSystemTime(&BonDInfo->StartTime); BonDInfo->State = BonDMonitor; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("L-S: i -> m, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); } break; case BonDMonitor: // // We are currently in the monitor state which means that // we have gone below the lower threshold. If we climb above // the lower threshold we will go back to the idle state. // if (Bps > BonDInfo->ulBytesThreshold) { NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("L-S: m -> i, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); BonDInfo->State = BonDIdle; } else { NdisWanGetSystemTime(&CurrentTime); NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime); if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) { SSignal = TRUE; } } break; case BonDSignaled: break; } // // Now check the receive side // BonDInfo = BundleCB->RLowerBonDInfo; RSignal = FALSE; SampleTable = &BonDInfo->SampleTable; Bps = SampleTable->ulCurrentSampleByteCount; switch (BonDInfo->State) { case BonDIdle: // // We are currently above the lower threshold. If we // go below the lowerthreshold we will set the time and // transition to the monitor state. // if (Bps <= BonDInfo->ulBytesThreshold) { NdisWanGetSystemTime(&BonDInfo->StartTime); BonDInfo->State = BonDMonitor; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("L-R: i -> m, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); } break; case BonDMonitor: // // We are currently in the monitor state which means that // we have gone below the lower threshold. If we climb above // the lower threshold we will go back to the idle state. // if (Bps > BonDInfo->ulBytesThreshold) { NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("L-R: m -> i, %I64d-%I64d", Bps, BonDInfo->ulBytesThreshold)); BonDInfo->State = BonDIdle; } else { NdisWanGetSystemTime(&CurrentTime); NdisWanCalcTimeDiff(&TimeDiff, &CurrentTime, &BonDInfo->StartTime); if (!NdisWanIsTimeDiffLess(&TimeDiff, &SampleTable->SamplePeriod)) { RSignal = TRUE; } } break; case BonDSignaled: break; } if (SSignal && RSignal) { // // We have been above the threshold for time greater than the // threshold sample period so we need to notify someone of this // historic event! // CompleteThresholdEvent(BundleCB, BonDInfo->DataType, LOWER_THRESHOLD); BundleCB->SLowerBonDInfo->State = BonDSignaled; BundleCB->RLowerBonDInfo->State = BonDSignaled; #if DBG { ULONGLONG util; util = BundleCB->SLowerBonDInfo->SampleTable.ulCurrentSampleByteCount; util *= 100; util /= BundleCB->SLowerBonDInfo->ulBytesInSamplePeriod; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("L-S: Bps %I64d Threshold %I64d Util %I64d", Bps, BundleCB->SLowerBonDInfo->ulBytesThreshold, util)); util = BundleCB->RLowerBonDInfo->SampleTable.ulCurrentSampleByteCount; util *= 100; util /= BundleCB->RLowerBonDInfo->ulBytesInSamplePeriod; NdisWanDbgOut(DBG_TRACE, DBG_BACP, ("L-R: Bps %I64d Threshold %I64d Util %I64d", Bps, BundleCB->RLowerBonDInfo->ulBytesThreshold, util)); } #endif } } #endif // end of ifdef NT #if DBG VOID InsertSendTrc( PSEND_TRC_INFO SendTrcInfo, ULONG DataLength, PUCHAR Data ) { PWAN_TRC_EVENT NewTrcEvent; PSEND_TRC_INFO TrcInfo; if (WanTrcCount == 4096) { NewTrcEvent = (PWAN_TRC_EVENT) RemoveTailList(&WanTrcList); NdisWanFreeMemory(NewTrcEvent->TrcInfo); NdisZeroMemory(NewTrcEvent, sizeof(WAN_TRC_EVENT)); } else { NdisWanAllocateMemory(&NewTrcEvent, sizeof(WAN_TRC_EVENT), WANTRCEVENT_TAG); if (NewTrcEvent == NULL) { return; } } WanTrcCount += 1; } #endif