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

📄 maintbuf.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 3 页
字号:
    // TxToken(LocIF,RemIF) from MBN(OutIf,InIf)
    //
    if (FindNextHop(VA, 
                    SRP->Dest, 
                    MBN->OutIf, 
                    MBN->InIf,
                    &SRP->Token, 
                    NULL,
                    NULL_SR_FLAGS) != SuccessFwd) {

        VrrKdPrint("MaintBufCreateAckRequest: Error: Fwd!=FNH(d)",NULL,(char *)SRP->Dest);
        ExFreePool(SRP);
        ExFreePool(AR);
        return NULL;
    }

    //
    // Initialize the Acknowledgement Request.
    //
    AR->next = NULL;
    AR->opt.optionType = VRR_OPTION_TYPE_ACKREQ;
    AR->opt.optDataLen = ACK_REQUEST_LEN;
    AR->opt.identification = MaintBufAckNum(MBN);
    RtlCopyMemory(AR->opt.Source, SRP->Source, sizeof(VirtualAddress));
    RtlCopyMemory(AR->opt.Dest, SRP->Dest, sizeof(VirtualAddress));
    VRRASSERT(SRP->Token.LocIF == MBN->OutIf);
    VRRASSERT(SRP->Token.RemIF == MBN->InIf);
    AR->opt.RackSourceIF = SRP->Token.LocIF;
    AR->opt.RackDestIF = SRP->Token.RemIF;

    VrrTrace(VA,3,"MB:AR=New",AR->opt.Source,AR->opt.Dest,AR->opt.Dest,"id",AR->opt.identification,NULL,0);

    return SRP;
}

//* MaintBufAckRequestSendComplete
//
//  Called to complete the transmission of a packet
//  from MaintBufCreateAckRequest.
//
static void
MaintBufAckRequestSendComplete(
    MiniportAdapter *VA,
    NDIS_PACKET *Packet,
    NDIS_STATUS Status)
{
    SRPacket *SRP = PC(Packet)->srp;

    UNREFERENCED_PARAMETER(VA);
    UNREFERENCED_PARAMETER(Status);

    NdisFreePacketClone(Packet);
    SRPacketFree(SRP);
}

//* RexmitFailNCE
//
//  Abort a Maintbuf packet and flush Msg queue of all msg for this
//  link.
//
Time
RexmitFailNCE(
    MiniportAdapter *VA,
    MaintBufPacket *MBP)
{
    NeighborCache *NC = &VA->NC;
    NeighborCacheEntry *NCE;
    SRPacket *srp = MBP->srp;
    InternalOption *Opt;
    InternalOption *NewOpt;
    KIRQL OldIrql;
    Time Now = KeQueryInterruptTime();
    Time Delay = min(TDOWN_DELAY,min(SETUP_DELAY, SR_DELAY));

    VrrTrace(VA,1,"MB:**=FailLink",srp->Source,srp->Token.NextVAddress,srp->Token.NextVAddress,"FrameSeqNo",srp->FrameSeqNo,NULL,0);

    //
    // Find and FAIL the NCE for this packet.
    //
    KeAcquireSpinLock(&NC->Lock, &OldIrql);
    NCE=FindNCE(NC, srp->Token.NextVAddress, srp->Token.LocIF, srp->Token.RemIF, VRR_NCE_STATE_ANY);
    if (NCE != NULL) {
        AddRefNCE(NCE);
        NCE->CountFailRexmit++;
        FailNCE(NCE, Now);
    }
    KeReleaseSpinLock(&NC->Lock, OldIrql);

    //
    // Purge message queue of messages for this destination.
    //
    MsgFailLink(VA, srp->Token.NextVAddress, srp->Token.LocIF, srp->Token.RemIF);

    //
    // Update route and vset. Send TearDowns. 
    //
    if (NCE != NULL)
        RouteUpdateNCE(VA, NCE, VRR_NCE_STATE_FAILED);
    else
        VrrKdPrint("RexmitFailNCE: cannot find NCE", NULL, NULL);

    //
    // In VRR we drop rather than attempt to salvage any VRR messages.
    //

    //
    // Release the failing MBP.
    //
    MaintBufPacketRelease(VA, MBP);

    if (NCE != NULL)
        ReleaseNCE(NCE);

    return Delay;

}

//* MaintBufTimer
//
//  Called periodically to retransmit packets in the Maintenance Buffer.
//
Time
MaintBufTimer(MiniportAdapter *VA, Time Now)
{
    MaintBuf *MB = VA->MaintBuf;
    MaintBufNode **PrevMBN, *MBN;
    MaintBufPacket *MBP;
    MaintBufPacket *Salvage = NULL;
    NDIS_PACKET *Packet;
    NDIS_PACKET *RexmitPackets = NULL;
    SRPacket *SRP;
    Time Timeout = MAXTIME;
    Time Deadline;
    KIRQL OldIrql;
    NDIS_STATUS Status;

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

    //
    // Inspect each MaintBufNode in the Maintenance Buffer.
    // We are only interested in MBNs that have unacknowledged ack requests.
    // While doing this, we update Timeout to track
    // the next time by which we want to run.
    //
    PrevMBN = &MB->MBN;
    while ((MBN = *PrevMBN) != NULL) {
        if (MaintBufAckExpected(MBN)) {

            NeighborCacheEntry *NCE;
            uchar NCEState = 0;

            Deadline = max(MBN->FirstAckReq, MBN->LastAckRcv) +
                                                        MAINTBUF_LINK_TIMEOUT;

            //
            // Abort the packet if the Destination is in state FAILED, or
            // if we are giving up retransmissions of the packet.
            //
            // Snapshot NCE state for the packet destination.
            //
            KeAcquireSpinLockAtDpcLevel(&VA->NC.Lock);
            NCE=FindNCE(&VA->NC, MBN->Address, MBN->InIf, MBN->OutIf, VRR_NCE_STATE_ANY);
            NCEState = (NCE == NULL) ? VRR_NCE_STATE_FAILED : NCE->State;
            KeReleaseSpinLockFromDpcLevel(&VA->NC.Lock);

            if (NCEState == VRR_NCE_STATE_FAILED || Deadline <= Now) {
                //
                // Move any waiting packets to the salvage list.
                //
                while ((MBP = MBN->MBP) != NULL) {
                    MBN->MBP = MBP->Next;
                    MBP->Next = Salvage;
                    Salvage = MBP;
                }
                MB->NumPackets -= MBN->NumPackets;
                MBN->MBNTxFailed += MBN->NumPackets;
                MBN->NumPackets = 0;

                //
                // We no longer expect an ack.
                //
                MBN->LastAckNum = MaintBufAckNum(MBN);
                // Next loop iteration will inspect the same MBN again.
                continue;
            }

            if (Deadline < Timeout)
                Timeout = Deadline;

            //
            // If it's been too long since we requested an ack,
            // we should retransmit the request.
            //
            Deadline = MBN->LastAckReq + MAINTBUF_REXMIT_TIMEOUT;
            if (Deadline <= Now) {
                //
                // Retransmit an ack request.
                //
                MBN->NumAckReqs++;
                MBN->LastAckReq = Now;
                Deadline = MBN->LastAckReq + MAINTBUF_REXMIT_TIMEOUT;

                //
                // Retransmit only the most recent packet.
                //
                MBP = MBN->MBP;
                if (MBP == NULL) {
                    //
                    // We do not have a packet to retransmit,
                    // so create a packet to carry the ack req.
                    //
                    SRP = MaintBufCreateAckRequest(VA, MBN);
                }
                else {
                    //
                    // Retransmit the existing packet,
                    // but update it with current sequence number.
                    //
                    SRP = MBP->srp;
                    SRP->ackreq->opt.identification = MaintBufAckNum(MBN);
                }

                if (SRP != NULL) {
                    //
                    // This will update the metric in the source route
                    // and bump the Usage counter for the link.
                    //
                    if (! TxQueueIsFull(VA, SRP)) {
                        InterlockedIncrement((PLONG)&VA->CountRexmitQueueFull);
                        goto DoNotTransmit;
                    }

                    //
                    // Check for options that can be piggy-backed.
                    //
                    MsgLoadSRPfromPCache(VA, SRP);

                    Status = SRPacketToPkt(VA, SRP, &Packet);

                    //
                    // We only want to send Acks once.
                    //
                    if (SRP->ack != NULL) {
                        SRFreeOptionList((InternalOption *) SRP->ack);
                        SRP->ack = NULL;
                    }

                    if (Status == NDIS_STATUS_SUCCESS) {
                        if (MBP == NULL) {
                            PC(Packet)->TransmitComplete =
                                MaintBufAckRequestSendComplete;
                            PC(Packet)->srp = SRP;
                        }
                        else {
                            //
                            // Need a reference to MBP, released in
                            // MaintBufTransmitComplete.
                            //
                            InterlockedIncrement((PLONG)&MBP->RefCnt);
                            PC(Packet)->TransmitComplete =
                                MaintBufTransmitComplete;
    
                            PC(Packet)->MBP = MBP;
                        }

                        //
                        // Queue the packet using the OrigPacket link.
                        //
                        PC(Packet)->OrigPacket = RexmitPackets;
                        RexmitPackets = Packet;
                        MBN->MBNRexmits++;
                    }
                    else {
                    DoNotTransmit:
                        MBN->MBNTxFailed++;
                        if (MBP == NULL) {
                            //
                            // We just need to free the packet.
                            //
                            SRPacketFree(SRP);
                        }
                        else {
                            //
                            // We leave the MBP on the MBN.
                            //
                        }
                    }
                }
            }
        }
        else {
            //
            // There are no outstanding ack requests.
            // Hence we must have no waiting packets.
            //
            VRRASSERT(MBN->MBP == NULL);

            Deadline = MBN->LastAckReq + MAINTBUF_IDLE_TIMEOUT;

            if (Deadline <= Now) {
                //
                // This Maintenance Buffer Node has been idle for a long time.
                // If we delete it, we lose the AckNum state for this neighbor.
                // But this is OK after sufficient time.
                //
                *PrevMBN = MBN->Next;
                ExFreePool(MBN);
                // Next loop iteration looks at the next MBN.
                continue;
            }
        }

        if (Deadline < Timeout)
            Timeout = Deadline;

        // Move to the next MBN.
        PrevMBN = &MBN->Next;
    }
    KeReleaseSpinLock(&MB->Lock, OldIrql);

    //
    // Send any queued retransmissions.
    //
    while ((Packet = RexmitPackets) != NULL) {
        RexmitPackets = PC(Packet)->OrigPacket;

        if (PC(Packet)->PA == NULL) {
            //
            // This means the source route is trying to use a physical adapter
            // that no longer exists.
            //
            if (PC(Packet)->TransmitComplete == MaintBufTransmitComplete) {

                VrrKdPrint("MaintBufTimer: rexmit via MiniportSendRouteError",NULL,PC(Packet)->srp->Dest);
            }
            (*PC(Packet)->TransmitComplete)(VA, Packet, NDIS_STATUS_FAILURE);
        }
        else {
            //
            // Transmit the packet.
            //
            VrrTrace(VA,3,"MB:MP=ReTx(ProtocolTransmit)",VA->Address,PC(Packet)->srp->Token.NextVAddress,PC(Packet)->srp->Token.NextVAddress,
                   "FrameSeqNo", PC(Packet)->srp->FrameSeqNo,NULL,0);
            ProtocolTransmit(PC(Packet)->PA, Packet);
        }
    }

    //
    // If there were any waiting packets,
    // send errors and salvage them.
    // NB: These packets may have outstanding references.
    //
    while ((MBP = Salvage) != NULL) {
        Salvage = MBP->Next;
        
        //
        // Abort the packet and ensure NCE(Dest) is in state FAILED.
        //
        RexmitFailNCE(VA, MBP);
        
        if (Deadline < Timeout)
            Timeout = Deadline;
    }

    //
    // Return the time of our next call.
    //
    VRRASSERT(Now < Timeout);
    return Timeout;
}

//* MaintBufRecvAck
//
//  Handles a received acknowledgement.

⌨️ 快捷键说明

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