📄 maintbuf.c
字号:
//
void
MaintBufRecvAck(
MiniportAdapter *VA,
const VirtualAddress Address,
VRRIf InIf,
VRRIf OutIf,
VRRAckId AckNum)
{
MaintBuf *MB = VA->MaintBuf;
MaintBufNode *MBN;
MaintBufPacket **PrevMBP;
MaintBufPacket *MBP = NULL;
MaintBufPacket *NextMBP;
uint NumPackets;
KIRQL OldIrql;
//
// Find the appropriate MaintBufNode.
//
KeAcquireSpinLock(&MB->Lock, &OldIrql);
MBN = MaintBufFindNode(MB, Address, InIf, OutIf);
if (MBN != NULL) {
//
// Is this a valid ack?
// That is, between LastAckNum and NextAckNum.
//
if (MaintBufValidAck(MBN, AckNum)) {
//
// We have received a valid ack, confirming the link.
//
MBN->NumValidAcks++;
MBN->LastAckNum = AckNum;
MBN->LastAckRcv = KeQueryInterruptTime();
//
// Remove any acknowledged packets.
// This maintains the invariant that waiting packets
// have a sequence number between LastAckNum and NextAckNum.
//
NumPackets = 0;
for (PrevMBP = &MBN->MBP;
(MBP = *PrevMBP) != NULL;
PrevMBP = &MBP->Next) {
//
// If we receive MBP->AckNum, will it be valid?
//
if (! MaintBufValidAck(MBN, MBP->AckNum)) {
//
// Remove this packet (and any older ones).
//
*PrevMBP = NULL;
MB->NumPackets -= MBN->NumPackets - NumPackets;
MBN->NumPackets = NumPackets;
break;
}
NumPackets++;
}
}
else {
//
// This is an invalid ack, because the ack sequence number
// is not in the proper range.
//
MBN->NumInvalidAcks++;
}
}
//
// Track count of successful MB packet transmissions.
//
for (NextMBP = MBP; NextMBP != NULL; NextMBP = NextMBP->Next)
MBN->MBNTxSuccess++;
KeReleaseSpinLock(&MB->Lock, OldIrql);
//
// Did we find any packets to complete?
//
while (MBP != NULL) {
NextMBP = MBP->Next;
MaintBufPacketRelease(VA, MBP);
MBP = NextMBP;
}
}
//* MaintBufStaticSendComplete
//
// Completion handler for statically source-routed packets.
//
void
MaintBufStaticSendComplete(
MiniportAdapter *VA,
NDIS_PACKET *Packet,
NDIS_STATUS Status)
{
SRPacket *SRP = PC(Packet)->srp;
PrintfNdisStatus(__FUNCTION__,Status,FALSE);
NdisFreePacketClone(Packet);
(*SRP->TransmitComplete)(VA, SRP, Status);
}
//* MaintBufSendPacket
//
// Sends a Source-Routed packet that must be explicitly
// acked by the destination.
//
// TxQueueIsFull has already been called, but if we retransmit
// then we should call it again.
//
// NB: We must create a new NDIS_PACKET for every (re)transmission.
// We can not allow a single NDIS_PACKET to be sent twice simultaneously.
//
// Returns TRUE if the packet was transmitted successfully, else FALSE.
//
uint
MaintBufSendPacket(
MiniportAdapter *VA,
SRPacket *srp,
void (*Complete)(MiniportAdapter *VA, SRPacket *srp, NDIS_STATUS Status))
{
MaintBuf *MB = VA->MaintBuf;
InternalAcknowledgementRequest *AR = NULL;
MaintBufNode *MBN;
MaintBufPacket *MBP = NULL;
NDIS_PACKET *Packet = NULL;
Time Now;
Time Timeout = 0;
uint Index;
KIRQL OldIrql;
NDIS_STATUS Status;
VRRASSERT(srp->ackreq == NULL);
//
// We have to initialize this before unlocking MaintBuf.
//
srp->TransmitComplete = Complete;
//
// If the packet contains nothing more than ack(s) then
// we do not send it via the maintbuf in order to avoid
// generating Acks for Acks.
//
if (SRPContainsMessages(srp)) {
//
// Use the Maintenance Buffer to send the packet,
// requesting an acknowledgement.
//
InterlockedIncrement((PLONG)&VA->CountXmitMaintBuf);
//
// In testing we sometimes supress all tx.
//
if (VA->TxDropAllButHello) {
(*Complete)(VA, srp, NDIS_STATUS_RESOURCES);
return TRUE;
}
//
// VRR control messages have fixed NextHop.
// They must not be rerouted by FNH.
// At this point the NextHop should already be known.
//
VRRASSERT(! IsNullTxToken(&srp->Token) );
AR = ExAllocatePool(NonPagedPool, sizeof *AR);
if (AR == NULL) {
(*Complete)(VA, srp, NDIS_STATUS_RESOURCES);
return FALSE;
}
srp->ackreq = AR;
RtlZeroMemory(AR, sizeof *AR);
AR->opt.optionType = VRR_OPTION_TYPE_ACKREQ;
AR->opt.optDataLen = ACK_REQUEST_LEN;
RtlCopyMemory(&AR->opt.Source, &srp->Token.Source, sizeof(VirtualAddress));
RtlCopyMemory(&AR->opt.Dest, &srp->Token.NextVAddress, sizeof(VirtualAddress));
AR->opt.RackSourceIF = srp->Token.LocIF;
AR->opt.RackDestIF = srp->Token.RemIF;
// AR->opt.identification initialized in MaintBufAddPacket.
//
// Find the MaintBufNode for the packet.
//
KeAcquireSpinLock(&MB->Lock, &OldIrql);
Now = KeQueryInterruptTime();
MBN = MaintBufFindNode(MB,
srp->Token.NextVAddress,
srp->Token.LocIF, // InIf.
srp->Token.RemIF); // OutIf.
if (MBN != NULL) {
InterlockedIncrement((PLONG)&MBN->MBNCountPackets);
//
// Create and initialize a new MaintBufPacket structure.
//
MBP = ExAllocatePool(NonPagedPool, sizeof *MBP);
if (MBP != NULL) {
//
// Initialize the MaintBufPacket. It starts with 1 ref
// for its existence on MBN.
//
MBP->RefCnt = 1;
MBP->srp = srp;
//
// Are we requesting the first ack?
//
if (! MaintBufAckExpected(MBN))
MBN->FirstAckReq = Now;
//
// If MaintBufAddPacket returns an NDIS_PACKET,
// it also adds a reference to MBP.
//
if ((Packet=MaintBufAddPacket(VA, MBN, MBP))==NULL) {
MBN->MBP = MBP->Next;
ExFreePool(MBP);
MBP = NULL;
}
else {
//
// We are sending an Ack Request to this node.
//
MBN->NumAckReqs++;
MBN->LastAckReq = Now;
Timeout = MBN->LastAckReq + MAINTBUF_REXMIT_TIMEOUT;
}
}
}
KeReleaseSpinLock(&MB->Lock, OldIrql);
//
// Error handling.
//
if (MBP == NULL) {
(*Complete)(VA, srp, NDIS_STATUS_RESOURCES);
return FALSE;
}
//
// Reschedule the next MaintBufTimer call.
//
if (Timeout != 0)
MiniportRescheduleTimeout(VA, Now, Timeout);
//
// Ensure PC(PC(Packet)->PA is valid.
//
PC(Packet)->PA = FindPhysicalAdapterFromIndex(VA, srp->Token.LocIF);
MaintBufTransmit(VA, MBP, Packet);
}
else {
//
// Just send the packet directly.
//
Status = SRPacketToPkt(VA, srp, &Packet);
if (Status != NDIS_STATUS_SUCCESS) {
(*Complete)(VA, srp, Status);
return FALSE;
}
PC(Packet)->srp = srp;
PC(Packet)->TransmitComplete = MaintBufStaticSendComplete;
//
// In testing we sometimes supress all tx.
//
if (VA->TxDropAllButHello) {
MaintBufStaticSendComplete(VA, Packet, NDIS_STATUS_FAILURE);
return TRUE;
}
if (PC(Packet)->PA == NULL) {
//
// This means the packet is trying to use a physical adapter that
// no longer exists.
//
VrrKdPrint("MBSendPacket MaintBufStaticSendComplete",NULL,NULL);
MaintBufStaticSendComplete(VA, Packet, NDIS_STATUS_FAILURE);
return FALSE;
}
else {
VrrTrace(VA,3,"MB:MP=ReTx(MaintBufStaticSendComplete)",srp->Source,srp->Token.NextVAddress,srp->Dest,NULL,0,"FrameSeqNo",srp->FrameSeqNo);
ProtocolTransmit(PC(Packet)->PA, Packet);
}
}
return TRUE;
}
//* MaintBufSendAck
//
// Requests delayed transmission of an Ack.
//
void
MaintBufSendAck(
MiniportAdapter *VA,
VirtualAddress Source,
VirtualAddress Dest,
VRRAckId AckId,
VRRIf RackSourceIF,
VRRIf RackDestIF,
uchar NCEState)
{
InternalAcknowledgement *Ack;
//
// Allocate the Acknowledgement option.
//
Ack = ExAllocatePool(NonPagedPool, sizeof *Ack);
if (Ack == NULL)
return;
//
// Initialize the Acknowledgement option.
//
RtlZeroMemory(Ack, sizeof *Ack);
Ack->opt.optionType = VRR_OPTION_TYPE_ACK;
Ack->opt.optDataLen = ACKNOWLEDGEMENT_LEN;
Ack->opt.identification = AckId;
Ack->opt.RackSourceIF = RackSourceIF;
Ack->opt.RackDestIF = RackDestIF;
RtlCopyMemory(Ack->opt.from, Source, SR_ADDR_LEN);
RtlCopyMemory(Ack->opt.to, Dest, SR_ADDR_LEN);
//
// Send the Acknowledgement option.
//
MsgQueueMessage(VA, Ack->opt.to,(InternalOption *)Ack,RackDestIF,RackSourceIF,MAX_ACK_DELAY,NULL);
}
//* MaintBufResetStatistics
//
// Resets all counters and statistics gathering for the maintenance buffer.
//
void
MaintBufResetStatistics(MiniportAdapter *VA)
{
MaintBuf *MB = VA->MaintBuf;
MaintBufNode *MBN;
KIRQL OldIrql;
KeAcquireSpinLock(&MB->Lock, &OldIrql);
MB->HighWater = MB->NumPackets;
for (MBN = MB->MBN; MBN != NULL; MBN = MBN->Next) {
MBN->HighWater = MBN->NumPackets;
MBN->NumAckReqs = 0;
MBN->NumFastReqs = 0;
MBN->NumValidAcks = 0;
MBN->NumInvalidAcks = 0;
MBN->MBNCountPackets = 0;
MBN->MBNTxSuccess = 0;
MBN->MBNRexmits = 0;
MBN->MBNTxFailed = 0;
}
KeReleaseSpinLock(&MB->Lock, OldIrql);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -