📄 send.c
字号:
// -*- 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.
//
#include "headers.h"
//* VrrBroadcastComplete
//
// Completes an individual packet transmission for VrrBroadcastComplete.
//
void
VrrBroadcastComplete(
MiniportAdapter *VA,
NDIS_PACKET *Packet,
NDIS_STATUS Status)
{
SRPacket *srp = PC(Packet)->srp;
//
// Free the packet structure.
//
NdisFreePacketClone(Packet);
//
// Update the current cumulative status.
// If the current status is NDIS_STATUS_SUCCESS,
// we replace it with our new status.
//
InterlockedCompareExchange((PLONG)&srp->ForwardStatus,
Status,
NDIS_STATUS_SUCCESS);
if (InterlockedDecrement((PLONG)&srp->ForwardCount) == 0) {
//
// Complete the operation.
//
(*srp->TransmitComplete)(VA, srp, srp->ForwardStatus);
}
}
//* VrrBroadcastHello
//
// Sends a packet via every physical adapter simultaneously.
// The operation completes when the last underlying transmit completes.
// The operation completes successfully only if every
// underlying transmit is successful.
//
// Our caller supplies srp->TransmitComplete, which is always called
// to consume the SRPacket.
//
void
VrrBroadcastHello(
MiniportAdapter *VA,
SRPacket *srp)
{
ProtocolAdapter *PA;
NDIS_PACKET *PacketList = NULL;
NDIS_PACKET *Packet;
NDIS_STATUS Status;
KIRQL OldIrql;
uint HeaderLength = SROptionListLength((InternalOption *)srp->VrrHello);
//
// We start with one reference (our own) for the SRPacket.
//
srp->ForwardCount = 1;
srp->ForwardStatus = NDIS_STATUS_SUCCESS;
//
// First we build a temporary list of packet structures
// and corresponding physical adapters. While doing this,
// we also initialize the transmission count.
// It starts with one, for our own reference for OrigPacket.
//
KeAcquireSpinLock(&VA->Lock, &OldIrql);
for (PA = VA->PhysicalAdapters;
PA != NULL;
PA = PA->Next) {
void *Data;
EtherHeader *Ether;
VRRHeader *VRR;
char* Hello;
InternalOption *IntOpt;
//
// Insert Index for this physical adapter into the VrrHello message.
//
if (NULL != srp->VrrHello)
srp->VrrHello->Opt.SentFromIF = (VRRIf)PA->Index;
//
// Unpack SRPacket into NDIS packet for transmission.
// Do this manually: we hold VA->Lock which prevents
// us using the normal tx path through FindNextHop.
//
Status = MiniportMakeEmptyPacket(VA,
sizeof(EtherHeader) + sizeof(VRRHeader) + HeaderLength,
&Packet, &Data);
if (Status != NDIS_STATUS_SUCCESS) {
KdPrint(("VrrBroadcast: MiniportMakeEmptyPacket() -> %8x\n",Status));
continue;
}
//
// Initialize ether header.
//
Ether = (EtherHeader *) Data;
RtlFillMemory(Ether->Dest, IEEE_802_ADDR_LENGTH, (uchar)0xff);
Ether->Type = ETYPE_MSFT;
//
// Initialize VRR header.
//
VRR = (VRRHeader *) (Ether + 1);
VRR->Code = VRR_CODE;
RtlCopyMemory(VRR->IV, srp->IV, VRR_IV_LENGTH);
VRR->HeaderLength = (ushort) HeaderLength;
RtlCopyMemory(VRR->Source, VA->Address, sizeof(VirtualAddress));
RtlCopyMemory(VRR->Dest, srp->Token.Dest, sizeof(VirtualAddress));
RtlFillMemory(VRR->Dest, sizeof(VirtualAddress), (uchar)0xff);
RtlCopyMemory(VRR->Origin, VA->Address, sizeof(VirtualAddress));
VRR->FrameSeqNo = RtlUlongByteSwap(srp->FrameSeqNo);
VRR->HopCount = 1;
RtlCopyMemory(VRR->MAC, VA->CryptoKeyMAC, VRR_MAC_LENGTH);
//
// Initialize hello message.
//
Hello = (char*)(VRR + 1);
IntOpt = (InternalOption *)srp->VrrHello;
RtlCopyMemory(Hello, &srp->VrrHello->Opt, sizeof(VRROption) + IntOpt->Opt.optDataLen);
//
// Remember the packet and corresponding physical adapter.
// We temporarily use the OrigPacket field to build our list.
//
PC(Packet)->PA = PA;
PC(Packet)->OrigPacket = PacketList;
PacketList = Packet;
srp->ForwardCount++;
}
KeReleaseSpinLock(&VA->Lock, OldIrql);
//
// Now we can transmit the packet via each physical adapter,
// using the new packet structures.
//
while ((Packet = PacketList) != NULL) {
PacketList = PC(Packet)->OrigPacket;
PA = PC(Packet)->PA;
//
// Send the packet via a physical adapter.
//
PC(Packet)->srp = srp;
PC(Packet)->TransmitComplete = VrrBroadcastComplete;
ProtocolTransmit(PA, Packet);
}
//
// Release our reference for the original packet.
//
if (InterlockedDecrement((PLONG)&srp->ForwardCount) == 0) {
//
// Complete the operation.
//
(*srp->TransmitComplete)(VA, srp, srp->ForwardStatus);
}
}
//* VrrBroadcastSRPComplete
//
// Completion handler after sending an srp packet.
// Cleans up the SRP packet from which NDIS packets were cloned.
// Used by routines that set up an srp packet as input to VrrBroadcast.
//
void
VrrBroadcastSRPComplete(
MiniportAdapter *VA,
SRPacket *srp,
NDIS_STATUS Status)
{
UNREFERENCED_PARAMETER(VA);
UNREFERENCED_PARAMETER(Status);
SRPacketFree(srp);
}
//* GetPhysNeighborTxToken
//
// Attempts to construct a TxToken to a physical neighbor.
//
// Used during join operations to forward a packet before
// the route state for the destination has been created.
//
// Caller must not hold NC->Lock.
//
// Returns TRUE iff a TxToken was constructed.
//
boolint
GetPhysNeighborTxToken(
MiniportAdapter *VA,
VirtualAddress Dest,
VRRIf LocIF,
VRRIf RemIF,
TxToken *Tok,
uchar State)
{
KIRQL OldIrql;
NeighborCacheEntry *NCE = NULL;
ProtocolAdapter *PA;
KeAcquireSpinLock(&VA->NC.Lock, &OldIrql);
//
// Exists an NCE for the Destination?
//
NCE = FindNCE(&VA->NC, Dest, LocIF, RemIF, State);
if (NULL != NCE) {
PA = FindPhysicalAdapterFromIndex(VA, NCE->LocIF);
if (NULL == PA) {
//
// Cannot transmit without a PA. Abort the transmission.
//
NCE = NULL;
} else {
//
// Initialize the caller's token.
//
RtlZeroMemory(Tok, sizeof(TxToken));
RtlCopyMemory(Tok->Source, VA->Address, sizeof(VirtualAddress));
RtlCopyMemory(Tok->Dest, Dest, sizeof(VirtualAddress));
RtlCopyMemory(Tok->NextVAddress, NCE->VAddress, sizeof(VirtualAddress));
RtlCopyMemory(Tok->NextPAddress, NCE->PAddress, sizeof(PhysicalAddress));
Tok->LocIF = NCE->LocIF;
Tok->RemIF = NCE->RemIF;
Tok->PA = PA;
}
}
KeReleaseSpinLock(&VA->NC.Lock, OldIrql);
return (NULL != NCE) ? TRUE : FALSE;
}
//* SendTransmitComplete
//
// Simple completion routine for packets made with MiniportMakeEmptyPacket.
// Only use when there are no packet clones or SRPackets to be freed.
//
void
SendTransmitComplete(
MiniportAdapter *VA,
NDIS_PACKET *Packet,
NDIS_STATUS Status)
{
UNREFERENCED_PARAMETER(VA);
UNREFERENCED_PARAMETER(Status);
NdisFreePacketClone(Packet);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -