⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 neighbor.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 2 页
字号:
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
//
// (c) Microsoft Corporation. All rights reserved. 
//
// This file is part of the Microsoft Virtual Ring Routing distribution.
// You should have received a copy of the Microsoft Research Shared Source
// license agreement (MSR-SSLA) for this software; see the file "license.txt".
// If not, please see http://research.microsoft.com/vrr/license.htm,
// or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
//
// This file is derived from the Microsoft Research Mesh Connectivity Layer,
// available under the MSR-SSLA license, and downloadable from
// http://research.microsoft.com/mesh/.
//

#include "headers.h"
#define VRR_MIN_NCE_REFCNT    2     // RefCnt of NCE in Neigbor Cache but otherwise unreferenced. 

//* NeighborCacheInit
//
//  Initializes a neighbor cache.
//
void
NeighborCacheInit(NeighborCache *NC)
{
    KeInitializeSpinLock(&NC->Lock);
    NC->FirstNCE = NC->LastNCE = SentinelNCE(NC);
}

//* AddRefNCE
void
AddRefNCE(NeighborCacheEntry *NCE)
{
    InterlockedIncrement(&NCE->RefCnt);
}

//* ReleaseNCE
void
ReleaseNCE(NeighborCacheEntry *NCE)
{
    if (InterlockedDecrement(&NCE->RefCnt) == 0) {
        VRRASSERT(VRR_NCE_STATE_ORPHAN == NCE->State);
        ExFreePool(NCE);
    }
}

//* RemoveNCE
//
//  Remove an NCE from a miniport's neighbor cache.
//  Caller must hold the NC lock for the virtual adapter.
//
void
RemoveNCE(
    NeighborCache *NC,
    NeighborCacheEntry *NCE)
{
    VRRASSERT(NCE != (NeighborCacheEntry *)NC);
    VRRASSERT(NCE->RefCnt >= VRR_MIN_NCE_REFCNT);
    VRRASSERT(VRR_NCE_STATE_ORPHAN != NCE->State);
    
    NCE->State = VRR_NCE_STATE_ORPHAN;
    NCE->Next->Prev = NCE->Prev;
    ReleaseNCE(NCE);
    NCE->Prev->Next = NCE->Next;
    ReleaseNCE(NCE);

    InterlockedDecrement(&NC->Count);
}

//* NeighborCacheCleanup
//
//  Uninitializes a neighbor cache.
//
void
NeighborCacheCleanup(NeighborCache *NC)
{
    NeighborCacheEntry *NCE;

    while ((NCE = NC->FirstNCE) != SentinelNCE(NC)) {
        //
        // Remove the NCE.
        //
        RemoveNCE(NC,NCE);
    }
}

//* NeighborCacheFlushAddress
//
//  Removes entries from the neighbor cache.
//  If VAddr is NULL, removes all entries.
//  Otherwise it only removes entries for that virtual address.
//
void
NeighborCacheFlushAddress(
    NeighborCache *NC,
    const VirtualAddress VAddr,
    VRRIf RemIF)
{
    NeighborCacheEntry *NCE;
    NeighborCacheEntry *NextNCE;
    KIRQL OldIrql;

    KeAcquireSpinLock(&NC->Lock, &OldIrql);
    for (NCE = NC->FirstNCE;
         NCE != SentinelNCE(NC);
         NCE = NextNCE) {
        NextNCE = NCE->Next;

        //
        // Should we remove this NCE?
        //
        if ((VAddr == NULL) ||
            (VirtualAddressEqual(NCE->VAddress, VAddr) &&
             (NCE->RemIF == RemIF))) {
             
            RemoveNCE(NC,NCE);
        }
    }
    KeReleaseSpinLock(&NC->Lock, OldIrql);
}

//* FindNCE
//
// Find an NCE in the Neighbor cache.
//
// Caller must hold NC->Lock.
//
NeighborCacheEntry *
FindNCE(
    NeighborCache *NC,
    const VirtualAddress VAddr,
    VRRIf LocIF,
    VRRIf RemIF,
    uchar States)
{
    NeighborCacheEntry *NCE = NULL;

    for (NCE = NC->FirstNCE; NCE != SentinelNCE(NC); NCE = NCE->Next)
        if (VirtualAddressEqual(NCE->VAddress, VAddr) || IsUnspecified(VAddr))
        if (NCE->RemIF == RemIF || VRR_IFID_UNSPECIFIED == RemIF) 
        if (NCE->LocIF == LocIF || VRR_IFID_UNSPECIFIED == LocIF)
        if (NCE->State & States)
            return NCE;
    
    return NULL;
}

//* InsertNCE
//
//  Insert NCE into the (ordered) list for given NC.
//
//  Caller must hold the NC->Lock.
//
void
InsertNCE(
    NeighborCache *NC,
    NeighborCacheEntry *NCE)
{
    NeighborCacheEntry *NCENext;

    VRRASSERT(NC != NULL);
    VRRASSERT(NCE != NULL);
#if DBG
    VRRASSERT(NULL == FindNCE(NC, NCE->VAddress, NCE->LocIF, NCE->RemIF, VRR_NCE_STATE_ANY));
#endif 

    //
    // Find insertion point for new NCE in the Neighbor cache.
    //
    NCENext = NC->FirstNCE;
    for (NCENext = NC->FirstNCE; 
         NCENext != SentinelNCE(NC);
         NCENext = NCENext->Next) {
        if (VirtualAddressLessThan(NCENext->VAddress, NCE->VAddress))
            continue;
        if (VirtualAddressEqual(NCE->VAddress, NCENext->VAddress) && 
            NCENext->LocIF < NCE->LocIF)
            continue;
        if (VirtualAddressEqual(NCE->VAddress, NCENext->VAddress) &&
            NCENext->LocIF == NCE->LocIF && 
            NCENext->RemIF < NCE->RemIF)
            continue;
        //
        // We need to insert the new NCE immediately prior to NextNCE.
        //
        break;
    }

    //
    // Insert the new NCE into the cache.
    //
    NCE->Prev = NCENext->Prev;
    NCE->Prev->Next = NCE;
    AddRefNCE(NCE);
    NCE->Next = NCENext;
    NCE->Next->Prev = NCE;
    AddRefNCE(NCE);
    
    InterlockedIncrement(&NC->Count);
}

//* CreateNCE
//
//  Creates a new NCE and inserts it in neighbor cache.
//  Called with the neighbor cache locked.
//
NeighborCacheEntry *
CreateNCE(
    NeighborCache *NC,
    const VirtualAddress VAddr,
    VRRIf LocIF,
    VRRIf RemIF)
{
    NeighborCacheEntry *NCE;
    MiniportAdapter *VA;
    Time Now = KeQueryInterruptTime();

    //
    // Allocate memory for new NCE.
    //
    NCE = ExAllocatePool(NonPagedPool, sizeof *NCE);
    if (NCE == NULL)
        return NULL;

    //
    // Initialize the NCE. Our caller must initialize PAddress.
    //
    RtlZeroMemory(NCE, sizeof *NCE);  // Init NCE to zeros throughout.
    NCE->State = VRR_NCE_STATE_FAILED;
    RtlCopyMemory(NCE->VAddress, VAddr, sizeof(VirtualAddress));
    NCE->RemIF = RemIF;
    NCE->LocIF = LocIF;
    
    //
    // Init WCETT state of Link members.
    //
    VA = CONTAINING_RECORD(NC,MiniportAdapter,NC);
    NCE->AdjIn.outif = RemIF;
    NCE->AdjIn.inif = LocIF;
    NCE->AdjIn.TimeStamp = Now;
    NCE->AdjOut.TimeStamp = Now;
    WcettInitLinkMetric(VA,0,&NCE->AdjIn,Now);
    NCE->AdjOut.outif = LocIF;
    NCE->AdjOut.inif = RemIF;
    NCE->AdjOut.TimeStamp = Now;
    WcettInitLinkMetric(VA,0,&NCE->AdjOut,Now);

    //
    // Insert the NCE into the cache.
    //
    InsertNCE(NC,NCE);

    return NCE;

}

//* FindOrCreateNCE
//
//  Finds or creates a neighbor cache entry.
//  Called with the neighbor cache locked.
//
NeighborCacheEntry *
FindOrCreateNCE(
    NeighborCache *NC,
    const VirtualAddress VAddr,
    VRRIf RemIF,
    VRRIf LocIF)
{
    NeighborCacheEntry *NCE;

    NCE = FindNCE(NC, VAddr, LocIF, RemIF, VRR_NCE_STATE_ANY);
    if (NCE != NULL)
        return NCE;

    return CreateNCE(NC, VAddr, LocIF, RemIF);
    
}


//* NeighborFindPhysical
//
//  Given a virtual address and physical adapter,
//  finds a corresponding physical address.
//  Returns FALSE on failure.
//
boolint
NeighborFindPhysical(
    NeighborCache *NC,
    const VirtualAddress VAddr,
    VRRIf RemIF,
    PhysicalAddress PAddr)
{
    NeighborCacheEntry *NCE;
    KIRQL OldIrql;

    KeAcquireSpinLock(&NC->Lock, &OldIrql);
    for (NCE = NC->FirstNCE; ; NCE = NCE->Next) {
        if (NCE == SentinelNCE(NC)) {
            NCE = NULL;
            break;
        }

        //
        // Do we have an NCE for this virtual address?
        //
        if (VirtualAddressEqual(NCE->VAddress, VAddr) &&
            (NCE->RemIF == RemIF)) {
            //
            // Return the physical address.
            //
            RtlCopyMemory(PAddr, NCE->PAddress, sizeof(PhysicalAddress));
            break;
        }
    }
    KeReleaseSpinLock(&NC->Lock, OldIrql);
    return NCE != NULL;
}

//* UpdateQoSForNCE
//
//  Encapsulates our QoS calculations for physical neighbors.
//
void
UpdateQoSForNCE(
    NeighborCacheEntry *NCE)
{
    uint PktPairBandwidth = WcettDecodeBandwidth(NCE->AdjOut.wcett.Bandwidth);

    if (PktPairBandwidth > NCE->BitsPerSec) {
        //
        // Adopt PktPair estimate if it is greater than our running estimate.
        //
        NCE->BitsPerSec = PktPairBandwidth;
    }
    else {
        //
        // Exponential Weighted Moving Average for decreasing our running estimate.
        //
        uint Average;
        uint Sample;

        Average = NCE->BitsPerSec / PKT2_SCALING;
        Sample = PktPairBandwidth / PKT2_SCALING;
        Average = (Sample * PKT2_ALPHA) + ((PKT2_SCALING - PKT2_ALPHA) * Average );
        NCE->BitsPerSec = (uint)Average;
    }
    
    NCE->LastWcettBandwidth = NCE->AdjOut.wcett.Bandwidth;

}

//* SibTableEntryToRSSI
//
//  Returns freshest RSSI measurement from a SibTableEntry.
//
uint
SibTableEntryToRSSI(
    MSRCSibTableEntry *STE)
{
    uint MostRecentTimestamp = -1;
    uint MostRecentRssi = 0;

    //
    // Find the most recent of the valid RSSI indicators.
    //
    if (STE->rssiTime > 0) {
        MostRecentTimestamp = STE->rssiTime;
        MostRecentRssi = STE->rssiLast;
    }
    if (STE->rxUCastMSecs > 0 && STE->rxUCastMSecs < MostRecentTimestamp) {
        MostRecentTimestamp = STE->rxUCastMSecs;
        MostRecentRssi = STE->rxUCastRSSI;
    }
    if (STE->rxBeaconMSecs > 0 && STE->rxBeaconMSecs < MostRecentTimestamp) {
        MostRecentTimestamp = STE->rxBeaconMSecs;
        MostRecentRssi = STE->rxBeaconRSSI;
    }
    if (STE->rxBCastMSecs > 0 && STE->rxBCastMSecs < MostRecentTimestamp) {
        MostRecentTimestamp = STE->rxBCastMSecs;
        MostRecentRssi = STE->rxBCastRSSI;
    }

    //
    // Decay link quality if the most recent RSSI is stale.
    //
    // We start to decay link quality if we have heard
    // nothing during an interval that ought at least to
    // have included a hello.
    //
    if (MostRecentTimestamp > HelloMinFrequency)
        MostRecentRssi = 0;
    
    return MostRecentRssi;
}

//* ExpWeightedMovingAverage
//
//  Calculate exponentially weighted moving average of
//  two 32-bit unsigned ints according to a specified
//  alpha weight. We use 64-bit integer arithmetic. Note
//  that the intended alpha lies in the interval [0,0.99]
//  but is supplied as alpha*100, i.e. in interval [0,99].
//
uint
ExpWeightedMovingAverage(
    uint Average,
    uint Sample,
    uint Alpha)
{
    unsigned __int64 i64 = Average;
    i64 = (100 - Alpha)*i64;
    i64 += Alpha * Sample;
    i64 = i64 / 100;  // account for scaling of alpha.

    return (uint)i64;
}

//* TranslateNdisRequestStatus
//
//  Helper for NeighborCacheTimeout trace in debug builds.
//
void
TranslateNdisRequestStatus(
    NDIS_STATUS NdisStatus,
    uint PAIndex)
{
#if DBG
    if (NdisStatus == NDIS_STATUS_SUCCESS)
        KdPrint(("NCETimeoutOID PA(%u):  NdisStatus=NDIS_STATUS_SUCCESS\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_INVALID_OID)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_INVALID_OID\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_INVALID_LENGTH)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_INVALID_LENGTH\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_BUFFER_TOO_SHORT)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_BUFFER_TOO_SHORT\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_INVALID_DATA)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_INVALID_DATA\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_NOT_SUPPORTED)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_NOT_SUPPORTED\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_NOT_RECOGNIZED)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_NOT_RECOGNIZED\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_RESOURCES)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_RESOURCES\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_NOT_ACCEPTED)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_NOT_ACCEPTED\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_CLOSING)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_CLOSING\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_CLOSING_INDICATING)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_CLOSING_INDICATING\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_RESET_IN_PROGRESS)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_RESET_IN_PROGRESS\n",PAIndex));
    else if (NdisStatus == NDIS_STATUS_FAILURE)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=NDIS_STATUS_FAILURE\n",PAIndex));
    else if (NdisStatus == STATUS_INVALID_DEVICE_REQUEST)
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=STATUS_INVALID_DEVICE_REQUEST\n",PAIndex));
    else if (NdisStatus != NDIS_STATUS_SUCCESS) {
        KdPrint(("NCETimeoutOID PA(%u): silent mask NdisStatus=0x%8x\n",PAIndex,NdisStatus));
        VRRASSERT(FALSE);
    }
#else
    return;
#endif
}

//* NeighborCacheTimeout
//
//  Housekeeping of Neighbor cache.
//
Time
NeighborCacheTimeout(
    MiniportAdapter *VA,
    Time Now)
{
    NDIS_STATUS Status;
    LARGE_INTEGER Timestamp;
    LARGE_INTEGER Frequency;
    KIRQL OldIrql;
    Time NextTimeout = Now + MIN_NCE_TIMOUT_INTERVAL;
    NeighborCacheEntry *NCE;
    NeighborCacheEntry *NextNCE;
    uint OldNCCount;
    uint CheckCount = 0;
    uint CountPA = InterlockedCompareExchange((PLONG)&VA->NextPhysicalAdapterIndex,0,0);
    uint *SupportsOID = NULL;
    uint i;
    NDIS_PACKET *Probe, *ProbeList = NULL;
    uint CountLinkedNow = 0;
    uint CountLinkedLast = 0;

    //
    // Refresh 802.11 Sib stats for any PA that supports OID_MSRC_QUERY_SIB_TABLE.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -