📄 maintbuf.c
字号:
// 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 + -