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

📄 pback.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 2 页
字号:
            PO->Token.LocIF == SRP->Token.LocIF && 
            PO->Token.RemIF == SRP->Token.RemIF) {
        
            //
            // The opt can go in this SRP because they share the same NextHop.
            //
            uint OptionSize = sizeof(VRROption) + PO->Opt->Opt.optDataLen;

            //
            // Would it make the packet too big?
            // NB: Currently we check against PROTOCOL_MIN_FRAME_SIZE,
            // but sometimes we know which physical link will be used
            // and perhaps that physical link has a larger MTU.
            // Furthermore some options will not be forwarded.
            // So in some cases we could safely make the packet larger
            // than PROTOCOL_MIN_FRAME_SIZE.
            // gregos: allow space for MaintBufSendPacket() to insert an AR.
            // if (*Size + OptionSize > PROTOCOL_MIN_FRAME_SIZE) {
            if (*Size + OptionSize > PROTOCOL_MIN_FRAME_SIZE - sizeof(AcknowledgementRequest)) {
                goto KeepLooking;
            }

            //
            // Remove the option and add it to the packet.
            //
            *PrevPO = PO->Next;
            MsgMoveMessageToSRP(VA, PCache, SRP, PO->Opt);
            Count++;
            *Size += OptionSize;

            ExFreePool(PO);
        }
        else {
        KeepLooking:
            PrevPO = &PO->Next;
        }
    }

    return Count;
}

//* PbackPacketSize
//
//  Calculates the packet's current size, for the purposes of piggy-backing.
//  This makes worst-case assumptions about the possible growth in size
//  of some options.
//
uint
PbackPacketSize(SRPacket *SRP)
{
    uint Size;

    //
    // Start with the fixed-size VRR header.
    //
    Size = sizeof(VRRHeader);

    //
    // Add the size of the options.
    // This is exactly SROptionLength except
    // we assume worst-case size of Source Route
    // (because of Route Salvaging) and Route Request options.
    //
    Size += SROptionListLength((InternalOption *)SRP->ackreq);
    Size += SROptionListLength((InternalOption *)SRP->ack);
    Size += SROptionListLength((InternalOption *)SRP->Probe);
    Size += SROptionListLength((InternalOption *)SRP->ProbeReply);
    Size += SROptionListLength((InternalOption *)SRP->VrrHello);
    Size += SROptionListLength((InternalOption *)SRP->VrrSetup);
    Size += SROptionListLength((InternalOption *)SRP->VrrTearDown);
    Size += SROptionListLength((InternalOption *)SRP->VrrSetupReq);

    //
    // Add the size of the encrypted payload.
    //
    if (SRP->Packet != NULL) {
        uint Length;

        NdisQueryPacketLength(SRP->Packet, &Length);
        Size += Length;
    }

    return Size;
}

//* MsgLoadSRPfromList
//
//  Find messages from list than can be added to batch of
//  messages in a given SRP.
//
//  Should be called with the piggy-back cache locked,
//  if PrevPO is &PCache->List.
//
static uint
MsgLoadSRPfromList(
    PbackCache *PCache,
    PbackOption **PrevPO,       // Pointer to list of options.
    SRPacket *SRP)
{
    uint Size;
    uint Count;

    Size = PbackPacketSize(SRP);

    //
    // Add options destined for the packet's destination.
    //
    Count = MsgMoveMultiToSRP(PCache, PrevPO, SRP, &Size, SRP->Dest);

    return Count;
}

//* MsgLoadSRPfromPCache
//
//  Called when sending a packet. Checks if there are any
//  waiting options which should be added to the packet.
//
void
MsgLoadSRPfromPCache(
    MiniportAdapter *VA,
    SRPacket *SRP)
{
    PbackCache *PCache = &VA->PCache;
    uint Count;
    KIRQL OldIrql;

    KeAcquireSpinLock(&PCache->Lock, &OldIrql);
    Count = MsgLoadSRPfromList(PCache, &PCache->List, SRP);
    PCache->Number -= Count;
    KeReleaseSpinLock(&PCache->Lock, OldIrql);
}

//* PbackSendComplete
//
//  Completes the transmission of a control packet,
//  which is carrying options that could not be piggy-backed.
//
static void
PbackSendComplete(
    MiniportAdapter *VA,
    SRPacket *SRP,
    NDIS_STATUS Status)
{
    UNREFERENCED_PARAMETER(VA);
    UNREFERENCED_PARAMETER(Status);

    SRPacketFree(SRP);
}

//* MsgFailLink
//
//  Purge message queue of all messages for a given destination.
//
void
MsgFailLink(
    MiniportAdapter *VA,
    VirtualAddress Address,
    VRRIf LocIF,
    VRRIf RemIF)
{
    PbackCache *PCache = &VA->PCache;
    PbackOption *PO, **PrevPO = &PCache->List;
    KIRQL OldIrql;

    VrrTrace(VA,2,"MQ:**=FailLink", VA->Address,Address,Address,"LocIF",LocIF,"RemIF",RemIF);

    KeAcquireSpinLock(&PCache->Lock, &OldIrql);

    while ((PO = *PrevPO) != NULL) {
        if (VirtualAddressEqual(PO->Token.NextVAddress, Address) &&
            PO->Token.LocIF == LocIF && PO->Token.RemIF == RemIF) {

            if (PO->Opt->Opt.optionType == VRR_OPTION_TYPE_ACK) {
                Acknowledgement *Ack = (Acknowledgement *)&PO->Opt->Opt;
                VrrTrace(VA,3,"MQ:AK=Purj", Ack->from,Address,Ack->to,"id",Ack->identification, NULL, 0);
            }
            else if (PO->Opt->Opt.optionType == VRR_OPTION_TYPE_SETUP) {
                VrrSetup *Setup = (VrrSetup *)&PO->Opt->Opt;
                VrrTrace(VA,3,"MQ:SU=Purj" ,Setup->Source,Address,Setup->A,"Pid",RtlUlongByteSwap(Setup->PathId), NULL, 0);
            }
            else if (PO->Opt->Opt.optionType == VRR_OPTION_TYPE_TEARDOWN) {
                VrrTearDown *TD = (VrrTearDown *)&PO->Opt->Opt;
                int i, NumPId = RtlUlongByteSwap(TD->NumGlobalPathId);
                for (i = 0; i < NumPId; i++)
                    VrrTrace(VA,3,"MQ:TD=Purj", TD->Source,Address,TD->PId[i].Address,"Pid",RtlUlongByteSwap(TD->PId[i].PathId), NULL, 0);
            }
            else if (PO->Opt->Opt.optionType == VRR_OPTION_TYPE_SETUPREQ) {
                VrrSetupReq *SR = (VrrSetupReq *)&PO->Opt->Opt;
                VrrTrace(VA,3,"MQ:SR=Purj" ,SR->Source,Address,SR->Dest,"SeqNo",RtlUlongByteSwap(SR->FrameSeqNo), NULL, 0);
            }

            *PrevPO = PO->Next;
            ExFreePool(PO->Opt);
            ExFreePool(PO);
        }
        else {
            PrevPO = &PO->Next;
        }
    }

    KeReleaseSpinLock(&PCache->Lock, OldIrql);

}

//* MsgTimeoutPrint
//
//  Helper for MessageTimeout
//
void MsgTimeoutPrint(
    MiniportAdapter  *VA,
    InternalOption   *Opt,
    Time             Timeout,
    VirtualAddress   NextHop,
    uint             Wait)
{
    uint MicroSecs = TIME_TO_MS(Timeout) - TIMESTAMP;

    if (Opt->Opt.optionType == VRR_OPTION_TYPE_ACK) {
        Acknowledgement *Ack = (Acknowledgement *)&Opt->Opt;
        VrrTrace(VA, 3, Wait ? "MQ:AK=Wait" : "MQ:AK=Now_", Ack->from, NextHop, Ack->to,
               "SeqNo",Ack->identification, "Due", MicroSecs);
    }
    else if (Opt->Opt.optionType == VRR_OPTION_TYPE_SETUP) {
        VrrSetup *Setup = (VrrSetup *)&Opt->Opt;
        VrrTrace(VA, 3,Wait ? "MQ:SU=Wait" : "MQ:SU=Now_" ,Setup->Source, NextHop, Setup->A,
               "Pid",RtlUlongByteSwap(Setup->PathId), "Due", MicroSecs);
    }
    else if (Opt->Opt.optionType == VRR_OPTION_TYPE_TEARDOWN) {
        VrrTearDown *TD = (VrrTearDown *)&Opt->Opt;
        int i, NumPId = RtlUlongByteSwap(TD->NumGlobalPathId);
        for (i = 0; i < NumPId; i++)
            VrrTrace(VA, 3,Wait ? "MQ:TD=Wait" : "MQ:TD=Now_",TD->Source,NextHop,TD->PId[i].Address,
                   "Pid",RtlUlongByteSwap(TD->PId[i].PathId), "Due", MicroSecs);
    }
    else if (Opt->Opt.optionType == VRR_OPTION_TYPE_SETUPREQ) {
        VrrSetupReq *SR = (VrrSetupReq *)&Opt->Opt;
        VrrTrace(VA, 3,Wait ? "MQ:SR=Wait" : "MQ:SR=Now_",SR->Source,NextHop,SR->Dest,
               "FrameSeqNo",RtlUlongByteSwap(SR->FrameSeqNo), "Due", MicroSecs);
    }

}

//* MessageTimeout
//
//  Ensures that waiting options are sent by their timeout.
//
//  Called from MiniportTimeout at DPC level.
//
Time
MessageTimeout(
    MiniportAdapter *VA,
    Time Now)
{
    PbackCache *PCache = &VA->PCache;
    MaintBuf *MB = VA->MaintBuf;
    PbackOption *PO;
    PbackOption *PrevPO = NULL;
    Time Timeout = 0;
    uint NumMessages;
    Time MaxMsgDelay = 0;
    uint CountMsgDelayed = 0;

    //
    // Search the message queue for messages which are past their
    // transmission deadline and for which the maintenance buffer
    // is not blocked awaiting ack of an earlier packet.
    //
    // Note that the message queue is disturbed whenever a batch
    // of messages is taken from it.
    //
    KeAcquireSpinLockAtDpcLevel(&PCache->Lock);

    NumMessages = PCache->Number;
    
    for (PO = PCache->List; 
         PO != NULL; 
         PO = (PrevPO == NULL ? PCache->List : PrevPO->Next)) {

        MaintBufNode *MBN;
        SRPacket *SRP;
        uint BatchSize;
        Time Overdue;

        VRRASSERT(NumMessages > 0);
        if (NumMessages == 0)
            break;

        if (PO->Timeout > Now) {
            if (Timeout == 0)
                Timeout = PO->Timeout;
            MsgTimeoutPrint(VA, PO->Opt, PO->Timeout, PO->Token.NextVAddress,TRUE);
            PrevPO = PO;
            NumMessages--;
            continue;
        }

        KeAcquireSpinLockAtDpcLevel(&MB->Lock);
        MBN = MaintBufFindNode(MB, PO->Token.NextVAddress, 
                               PO->Token.LocIF, PO->Token.RemIF);
        KeReleaseSpinLockFromDpcLevel(&MB->Lock);
        
        if (MBN == NULL) {
            // Should never happen.
            MsgTimeoutPrint(VA, PO->Opt, PO->Timeout, PO->Token.NextVAddress, TRUE);
            PrevPO = PO;
            NumMessages--;
            continue;
        }

        //
        // If MBN is already has a (packet,ack) pair queued then wait
        // for it to complete; otherwise construct a batch of messages
        // in an SRP for the MBN to send.
        //
        if (MBN->MBP != NULL) {
            MsgTimeoutPrint(VA, PO->Opt, PO->Timeout, PO->Token.NextVAddress, TRUE);
            Timeout = Now + MAX_MSG_TIMOUT_INTERVAL;
            CountMsgDelayed++;
            if (MaxMsgDelay < Now - PO->Timeout)
                MaxMsgDelay = Now - PO->Timeout;
            PrevPO = PO;
            NumMessages--;
            continue;
        }

        //
        // Allocate an SRP for a batch of messages to this next hop.
        //
        SRP = ExAllocatePool(NonPagedPool, sizeof *SRP);
        if (SRP == NULL) {
            ExFreePool(SRP);
            VrrTrace(VA,2,"MQ:**=AllocErr",VA->Address,PO->Token.NextVAddress,PO->Dest,NULL,0,NULL,0);
            PrevPO = PO;
            NumMessages--;
            continue;
        }
        RtlZeroMemory(SRP, sizeof *SRP);

        //
        // Initialize SRP.
        //
        RtlCopyMemory(SRP->Dest, PO->Dest, SR_ADDR_LEN);
        RtlCopyMemory(SRP->Source, VA->Address, SR_ADDR_LEN);
        RtlCopyMemory(&SRP->Token, &PO->Token, sizeof(TxToken));
        RtlCopyMemory(SRP->Origin, VA->Address, SR_ADDR_LEN);
        SRP->FrameSeqNo = InterlockedIncrement((unsigned long *)&VrrGlobal.NextFrameSeqNo);
        SRP->HopCount = 0;

        //
        // Move a batch of messages into the SRP from the PCache.
        // Note: this call may invalidate PO->Next and PrevPO, so
        // start the next iteration at PCache->List which will
        // either be valid or NULL.
        //
        BatchSize = MsgLoadSRPfromList(PCache, &PCache->List, SRP);
        VRRASSERT(BatchSize != 0 && BatchSize <= PCache->Number);
        PCache->Number -= BatchSize;
        NumMessages = PCache->Number;
        PrevPO = NULL;

        //
        // Send the SRP using the maintenance buffer routines.
        //
        if (MaintBufSendPacket(VA, SRP, PbackSendComplete) == FALSE) {
            //
            // MaintBuf failed to send the packet, dropping the SRP and
            // the messages it contained. We must fail the link so that
            // the VRR protocol can recover to a consistent state.
            //
            // Note the handling of failing messages gets serialized on
            // the lock we are holding.
            //
            NeighborCacheEntry *NCE;

            VrrTrace(VA,2,"MQ:TO=FailLink",NULL,NULL,PO->Token.NextVAddress,"LocIF",PO->Token.LocIF,"RemIF",PO->Token.RemIF);
            KeAcquireSpinLockAtDpcLevel(&VA->NC.Lock);
            NCE=FindNCE(&VA->NC, PO->Token.NextVAddress, PO->Token.LocIF, PO->Token.RemIF, VRR_NCE_STATE_ANY);
            if (NCE != NULL)
                RouteFailLink(VA,NCE);
            KeReleaseSpinLockFromDpcLevel(&VA->NC.Lock);
        }
    }
    KeReleaseSpinLockFromDpcLevel(&PCache->Lock);

    //
    // Maintain counters on VA showing stalled message limits.
    //
    if ((uint)InterlockedCompareExchange(&VA->MaxMsgCountDelayed,0,0) < CountMsgDelayed)
        InterlockedExchange(&VA->MaxMsgCountDelayed, CountMsgDelayed );
    if ((uint)InterlockedCompareExchange(&VA->MaxMsgTimeDelay,0,0) < TIME_TO_MS(MaxMsgDelay))
        InterlockedExchange(&VA->MaxMsgTimeDelay, TIME_TO_MS(MaxMsgDelay));

    if (Timeout == 0)
        Timeout = MAXTIME;

    return Timeout;
}

⌨️ 快捷键说明

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