📄 ipv6.c
字号:
//
// We are the closest node to the desination.
//
Reply->Success = TRUE;
RtlCopyMemory(Reply->NextHop, VA->Address, sizeof(VirtualAddress));
}
else {
//
// Result==Error, presumably.
//
Reply->Success = FALSE;
}
break;
}
case DHT_ERROR_NEXT_HOP: {
//
// Reply signals that Dest is not a 1-hop neighbor.
// Return error plus a copy of the UDP payload.
//
uchar *Reply = (uchar *)(DHT + 1);
DHT->Type.Type = DHT_ERROR_NEXT_HOP;
UDP->Length = RtlUshortByteSwap(sizeof(DHTHeader)
+ RequestLength);
RtlCopyMemory(Reply, (uchar UNALIGNED *)RequestDHT, RequestLength);
break;
}
case DHT_TRAP_PACKET: {
//
// Return opaque payload: whatever our caller supplied.
//
uchar *Reply = (uchar *)(DHT + 1);
DHT->Type.Type = DHT_TRAP_PACKET;
UDP->Length = RtlUshortByteSwap(sizeof(DHTHeader)
+ RequestLength);
RtlCopyMemory(Reply, (uchar UNALIGNED *)RequestDHT, RequestLength);
break;
}
case DHT_COMMAND: {
//
// Attempt Command(Arg) and return copy of cmd and result to caller.
//
DHTCommand UNALIGNED *Command = (DHTCommand UNALIGNED *)(RequestDHT+1);
DHTCommand UNALIGNED *Reply = (DHTCommand UNALIGNED *)(DHT + 1);
DHT->Type.Type = DHT_COMMAND;
Reply->Command = Command->Command;
Reply->Arg = Command->Arg;
Reply->Result = ExecCommand(VA,
Command->Command,
Command->Arg);
UDP->Length = RtlUshortByteSwap(sizeof(DHTHeader)
+ sizeof(DHTCommand));
break;
}
case DHT_LOOPBACK:
default: {
//
// Should be unreachable.
//
VrrKdPrint("DHTDriverRequest: unknown driver query type",NULL,NULL);
VRRASSERT(FALSE);
}
}
//
// Initialize UDP checksum.
//
{
ushort Checksum;
uint UDPOffset= (uint)UDP - (uint)Ether;
uint UDPLength = PacketLength - UDPOffset - sizeof(UDPHeader);
UDP->Checksum = 0;
Checksum = ChecksumPacket(Packet,
UDPOffset,
NULL,
UDPLength,
&IPv6->Source,
&IPv6->Dest,
IP_PROTOCOL_UDP);
UDP->Checksum = Checksum; // Note: no byte-swap.
}
//
// Send the packet to our local IPv6 protocol driver.
// The receive completion handling will free our NDIS packet.
//
ReceivePacket:
PC(Packet)->srp = NULL;
PC(Packet)->ReceiveComplete = MiniportReceiveComplete;
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
NDIS_SET_PACKET_HEADER_SIZE(Packet, sizeof(EtherHeader));
NdisMIndicateReceivePacket(VA->MiniportHandle, &Packet, 1);
return;
ReleaseAndReturn:
if (Packet != NULL)
NdisFreePacketClone(Packet);
}
//* IPv6TrapOutboundDHT
//
// If this is an outbound DHT payload then change ether
// dest to value of a key extracted from DHT app payload.
//
// Returns true if a DHT payload was found and handled,
// otherwise returns false.
//
boolint
IPv6TrapOutboundDHT(
MiniportAdapter *VA,
NDIS_PACKET *Packet,
EtherHeader *Eth,
SRPacket *SRP)
{
void *Address;
uint BufferLength;
uint PacketLength;
NDIS_BUFFER *Buffer;
const ushort MinBuffLength = sizeof(EtherHeader)
+ sizeof(IPv6Header)
+ sizeof(UDPHeader);
const ushort MinPacketLength = MinBuffLength
+ sizeof(DHTHeader);
IPv6Header UNALIGNED *IPv6;
ICMPv6Header UNALIGNED *ICMPv6;
UDPHeader UNALIGNED *UDP;
DHTHeader UNALIGNED *DHT;
ushort Checksum;
uint UDPOffset;
uint UDPLength;
char *FlatBuffer;
uint Response = FALSE;
EtherHeader UNALIGNED *FlatEth;
FindNextHopResult FNHResult;
uchar MessageType;
TxToken Token;
//
// We are only interested in packets with an Eth
// destination of our magic DHT L2 address.
//
if (! RtlEqualMemory(Eth->Dest, DHTMagicL2, sizeof(PhysicalAddress)))
return FALSE;
//
// Check that packet is large enough for a DHT payload.
// gregos: relax assumption that UDP header in first buffer?
//
Buffer = NdisFirstBuffer(Packet);
NdisQueryBuffer(Buffer, &Address, &BufferLength);
NdisQueryPacketLength(Packet, &PacketLength);
if (BufferLength < MinBuffLength) {
KdPrint(("VrrKdPrint: (%u) IPv6OutDHT: abort BuffLen(%u)<MinBuffSize(%u)\n",
TIMESTAMP, BufferLength, MinBuffLength));
return FALSE;
}
if (PacketLength < MinPacketLength) {
KdPrint(("VrrKdPrint: (%u) IPv6OutDHT: abort PacketLength(%u)<MinPacketSize(%u)\n",
TIMESTAMP, PacketLength, MinPacketLength));
return FALSE;
}
//
// In practice packets often have multiple buffers on tx path.
// We assumed everything up to UDP header in first buffer.
// Construct a local flat buffer for everthing after that.
//
FlatBuffer = AllocFlatBuffer(Packet,PacketLength);
if (FlatBuffer == NULL)
return FALSE;
//
// Find DHT header in Flat buffer.
//
FlatEth = (EtherHeader UNALIGNED *)FlatBuffer;
IPv6 = (IPv6Header UNALIGNED *)(FlatEth + 1);
UDP = (UDPHeader UNALIGNED *)(IPv6 + 1);
DHT = (DHTHeader UNALIGNED *)(UDP + 1);
MessageType = DHT->Type.Type;
//
// The packet is big enough to carry a DHT payload.
// Now check the IPv6 header.
//
if (RtlUshortByteSwap(Eth->Type) != ETYPE_IPv6) {
KdPrint(("VrrKdPrint: (%u) IPv6OutDHT: EthType!=ETYPE_IPv6\n",
TIMESTAMP));
goto ReleaseAndReturn;
}
IPv6 = (IPv6Header UNALIGNED *)(Eth + 1);
if ((IPv6->VersClassFlow & IP_VERSION6) != IP_VERSION6 ||
IPv6->NextHeader != IP_PROTOCOL_UDP) {
KdPrint(("VrrKdPrint: (%u) IPv6OutDHT: NextHdr(%u)!=IP_PROTOCOL_UDP(%u)\n",
TIMESTAMP,IPv6->NextHeader,IP_PROTOCOL_UDP));
goto ReleaseAndReturn;
}
//
// Treat the payload as a DHT message.
//
UDP = (UDPHeader UNALIGNED *)(IPv6 + 1);
//
// DHT apps may require that the next hop be to a 1-hop
// physical neighbor, indicated by a flag is set in
// DHT->Type. If the flag is set we test that Dest is in
// our pset. If the test succeeds we allow forwarding via
// FindNextHop, which will always prefer 1-hop, otherwise
// we indicate failure with an error packet.
//
if (DHT->Type.StrictPhysNeighbor == 1) {
KIRQL OldIrql;
NeighborCacheEntry *NCE = NULL;
//
// Satisfied if the destination is in our pset.
//
KeAcquireSpinLock(&VA->NC.Lock, &OldIrql);
NCE = FindNCE(&VA->NC,
DHT->Dest,
VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,
VRR_NCE_STATE_ACTIVE);
KeReleaseSpinLock(&VA->NC.Lock, OldIrql);
//
// Satisfied if self is closest to destination.
//
if (NCE == NULL)
FNHResult = FindNextHop(VA,
DHT->Dest,
VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,
NULL,
NULL,
NULL_SR_FLAGS);
//
// Bail and return error packet if not satisfied.
//
if (NCE == NULL)
if (FNHResult != SuccessRcvSelf)
if (FNHResult != SuccessRcvNearest)
MessageType = DHT_ERROR_NEXT_HOP;
}
//
// Special case handling for local query of driver state.
//
if (IS_DHT_DRIVER_REQUEST(MessageType)) {
//
// Construct and return a UDP packet encoding driver state.
//
ushort SizeofDHTPayload = (ushort)PacketLength - MinBuffLength;
DHTDriverRequest(VA,
MessageType,
DHT,
SizeofDHTPayload,
RtlUshortByteSwap(UDP->Dest));
//
// The original packet will get dropped because its eth destination
// is still the DHT magic layer2 address.
//
Response = TRUE;
goto ReleaseAndReturn;
}
//
// Drop outbound DHT traffic if DriverActive==FALSE.
//
if (IsDriverActive(VA)==FALSE) {
VrrKdPrint("IPv6TrapOutboundDHT: drop DHT tx: DriverActive=F",NULL,NULL);
Response = TRUE;
goto ReleaseAndReturn;
}
//
// Change IPv6 destination to well-known DHT rx address.
//
RtlCopyMemory(&IPv6->Dest, &DHTrxAddr, sizeof(IPv6Addr));
//
// Calculate the UDP checksum for the changed pseudo-header.
//
UDP->Checksum = 0;
UDPOffset = (uint)UDP - (uint)Eth;
UDPLength = PacketLength - UDPOffset;
Checksum = ChecksumPacket(Packet,
UDPOffset,
NULL,
UDPLength,
&IPv6->Source,
&IPv6->Dest,
IP_PROTOCOL_UDP);
UDP->Checksum = Checksum; // Note: no byte-swap.
//
// The redirected DHT packet must be looped back if there
// is no known node with a VirtualAddress that is closer
// to the desination key than our own VirtualAddress.
//
FNHResult = FindNextHop(VA,
DHT->Dest,
VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,
&Token,
NULL,
NULL_SR_FLAGS);
if (FNHResult == Error) {
//
// The packet will get dropped later in the tx path.
//
VrrKdPrint("IPv6OutDHT: FNH(d)=Error - cannot redirect DHT packet",NULL,Eth->Dest);
}
else if (FNHResult == SuccessFwd) {
//
// Redirect packet to VRR node whose address most closely matches the key.
// Change Eth destination to next hop. Caller must update srp->Dest.
//
RtlCopyMemory(Eth->Dest, &Token.NextVAddress, sizeof(PhysicalAddress));
RtlCopyMemory(SRP->Dest, DHT->Dest, sizeof(PhysicalAddress));
}
else if (FNHResult == SuccessRcvSelf || FNHResult == SuccessRcvNearest) {
//
// The packet must be looped back, rather than sent.
// Make and receive a copy of the original packet.
// The original packet will get dropped later in the tx path.
//
NDIS_PACKET *CopyPacket = NULL;
NDIS_STATUS Status;
uchar *CopyData;
uchar *FlatCopy;
//
// Avoid looping back DHT traffic where closer match exists in VSet or PLE.
// Instead just drop it - on unreliable transport it's up to the app to retry.
//
if (ExistsCloserNTEorPLEthanSelf(VA, DHT->Dest, TRUE, TRUE)) {
VrrKdPrint("IPv6OutDHT: drop loopback DHT(d) - exists closer VSet or PLE",NULL,DHT->Dest);
goto ReleaseAndReturn;
}
//
// Obtain flat buffer containing final state of original packet.
//
FlatCopy = AllocFlatBuffer(Packet,PacketLength);
if (FlatCopy == NULL)
goto ReleaseAndReturn;
//
// Obtain NDIS packet, NDIS buffer and memory for copy packet.
//
Status = MiniportMakeEmptyPacket(VA, PacketLength, &CopyPacket, &CopyData);
if (Status != NDIS_STATUS_SUCCESS) {
ExFreePool(FlatCopy);
goto ReleaseAndReturn;
}
//
// Initialize copy data from flat copy of original data.
//
RtlCopyMemory(CopyData,FlatCopy,PacketLength);
//
// Receive the copy packet.
//
PC(CopyPacket)->srp = NULL;
PC(CopyPacket)->ReceiveComplete = MiniportReceiveComplete;
NDIS_SET_PACKET_STATUS(CopyPacket, NDIS_STATUS_SUCCESS);
NDIS_SET_PACKET_HEADER_SIZE(CopyPacket, sizeof(EtherHeader));
NdisMIndicateReceivePacket(VA->MiniportHandle, &CopyPacket, 1);
ExFreePool(FlatCopy);
}
Response = TRUE;
ReleaseAndReturn:
if (FlatBuffer != NULL)
ExFreePool(FlatBuffer);
return Response;
}
#include <packoff.h>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -