Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1596 lines
36 KiB

/*++
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);
}
NTSTATUS
TransformRegister(
PVOID ClientOpenContext,
ULONG CharsSize,
PTRANSFORM_CHARACTERISTICS Chars,
ULONG CapsSize,
PTRANSFORM_INFO Caps
)
{
PTRANSDRVCB TransDrvCB = (PTRANSDRVCB)ClientOpenContext;
PTRANSDRVCB tTransDrvCB;
PTRANSFORM_IE Ie = (PTRANSFORM_IE)(Caps->InfoElements);
PTRANSFORM_IE tIe;
UINT i, FoundCount = 0, MemoryNeeded = 0;
#if 0
InterlockedExchange((PLONG)&TransDrvCB->State, TRANSDRV_REGISTERING);
for (i = 0; i < Caps->InfoElementCount; i++) {
if (Ie->IEType == TRANS_PPP_COMPRESSION ||
Ie->IEType == TRANS_PPP_ENCRYPTION) {
//
// This is an IEType that we are interested in
// but we have some requirements...
// 1. It must support the framed interface unless it is
// MPPC/MPPE.
// 2. If we already have a driver registered that supports
// this scheme we will not add this in again.
// 3. We will give priority to drivers that have hardware
// assisted data transformation.
//
//
// Walk the transform driver list and see if
// this scheme is already registered by another
// driver. If it is, see if either has hardware
// support. If they have the same level of support
// just use the one currently registered. If the new
// ie has a higher level of support mark the old ie
// as not being used
//
NdisAcquireSpinLock(&TransformDrvList.Lock);
for (tTransDrvCB = (PTRANSDRVCB)TransformDrvList.List.Flink;
(PVOID)tTransDrvCB != (PVOID)&TransformDrvList.List;
tTransDrvCB = (PTRANSDRVCB)tTransDrvCB->Linkage.Flink) {
tIe = (PTRANSFORM_IE)tTransDrvCB->Caps->InfoElements;
for (i = 0; i < tTransDrvCB->Caps->InfoElementCount; i++) {
if (tIe->Flags & IE_IN_USE) {
}
}
}
NdisReleaseSpinLock(&TransformDrvList.Lock);
MemoryNeeded += Ie->IESize;
}
Ie = (PTRANSFORM_IE)((PUCHAR)Ie + Ie->IESize);
}
if (FoundCount == 0) {
return (STATUS_UNSUCCESSFUL);
}
NdisWanAllocateMemory(&TransDrvCB->Caps,
MemoryNeeded,
TRANSDRV_TAG);
if (TransDrvCB->Caps == NULL) {
return (STATUS_UNSUCCESSFUL);
}
TransDrvCB->Caps->InfoElementCount = FoundCount;
tIe = (PTRANSFORM_IE)(TransDrvCB->Caps->InfoElements);
for (i = 0; i < Caps->InfoElementCount; i++) {
if (Ie->IEType == TRANS_PPP_COMPRESSION ||
Ie->IEType == TRANS_PPP_ENCRYPTION) {
NdisMoveMemory(tIe, Ie, Ie->IESize);
}
Ie = (PTRANSFORM_IE)((PUCHAR)Ie + Ie->IESize);
tIe = (PTRANSFORM_IE)((PUCHAR)tIe + tIe->IESize);
}
NdisMoveMemory(&TransDrvCB->Chars, Chars, CharsSize);
#endif
return (STATUS_SUCCESS);
}
VOID
TransformTxComplete(
NTSTATUS Status,
PVOID TxCtx,
PMDL InData,
PMDL OutData,
ULONG OutDataOffset,
ULONG OutDataLength
)
{
}
VOID
TransformRxComplete(
NTSTATUS Status,
PVOID RxCtx,
PMDL InData,
PMDL OutData,
ULONG OutDataOffset,
ULONG OutDataLength
)
{
}
NTSTATUS
TransformSendCtrlPacket(
PVOID TxCtx,
ULONG DataLength,
PUCHAR Data
)
{
return (STATUS_SUCCESS);
}
#ifdef NT
VOID
NdisWanStringToNdisString(
PNDIS_STRING pDestString,
PWSTR pSrcBuffer
)
{
PWSTR Dest, Src = pSrcBuffer;
NDIS_STRING SrcString;
NdisWanInitUnicodeString(&SrcString, pSrcBuffer);
NdisWanAllocateMemory(&pDestString->Buffer, SrcString.MaximumLength, NDISSTRING_TAG);
if (pDestString->Buffer == NULL) {
return;
}
pDestString->MaximumLength = SrcString.MaximumLength;
pDestString->Length = SrcString.Length;
NdisWanCopyUnicodeString(pDestString, &SrcString);
}
VOID
NdisWanInitUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString OPTIONAL
)
/*++
Routine Description:
The NdisWanInitUnicodeString function initializes an NT counted
unicode string. The DestinationString is initialized to point to
the SourceString and the Length and MaximumLength fields of
DestinationString are initialized to the length of the SourceString,
which is zero if SourceString is not specified.
Arguments:
DestinationString - Pointer to the counted string to initialize
SourceString - Optional pointer to a null terminated unicode string that
the counted string is to point to.
Return Value:
None.
--*/
{
ULONG Length;
DestinationString->Buffer = (PWSTR)SourceString;
if (ARGUMENT_PRESENT( SourceString )) {
Length = wcslen( SourceString ) * sizeof( WCHAR );
DestinationString->Length = (USHORT)Length;
DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
}
else {
DestinationString->MaximumLength = 0;
DestinationString->Length = 0;
}
}
VOID
NdisWanCopyUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PUNICODE_STRING SourceString OPTIONAL
)
/*++
Routine Description:
The NdisWanCopyUnicodeString function copies the SourceString
to the DestinationString. If SourceString is not specified,
then the Length field of DestinationString is set to zero. The
MaximumLength and Buffer fields of DestinationString are not
modified by this function.
The number of bytes copied from the SourceString is either the
Length of SourceString or the MaximumLength of DestinationString,
whichever is smaller.
Arguments:
DestinationString - Pointer to the destination string.
SourceString - Optional pointer to the source string.
Return Value:
None.
--*/
{
UNALIGNED WCHAR *src, *dst;
ULONG n;
if (ARGUMENT_PRESENT(SourceString)) {
dst = DestinationString->Buffer;
src = SourceString->Buffer;
n = SourceString->Length;
if ((USHORT)n > DestinationString->MaximumLength) {
n = DestinationString->MaximumLength;
}
DestinationString->Length = (USHORT)n;
RtlCopyMemory(dst, src, n);
if (DestinationString->Length < DestinationString->MaximumLength) {
dst[n / sizeof(WCHAR)] = UNICODE_NULL;
}
} else {
DestinationString->Length = 0;
}
return;
}
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);
}
}
BOOLEAN
NdisWanCompareNdisString(
PNDIS_STRING NdisString1,
PNDIS_STRING NdisString2
)
{
USHORT l1 = NdisString1->Length;
USHORT l2 = NdisString2->Length;
PWSTR s1 = NdisString1->Buffer;
PWSTR s2 = NdisString2->Buffer;
PWSTR EndCompare;
ASSERT(l1 != 0);
ASSERT(l2 != 0);
if (l1 == l2) {
EndCompare = (PWSTR)((PUCHAR)s1 + l1);
while (s1 < EndCompare) {
if (*s1++ != *s2++) {
return (FALSE);
}
}
return (TRUE);
}
return(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