📄 miniport.c
字号:
//
void
MiniportSendComplete(
MiniportAdapter *VA,
SRPacket *srp,
NDIS_STATUS Status)
{
NDIS_PACKET *Packet = srp->Packet;
UNREFERENCED_PARAMETER(Status);
PrintfNdisStatus(__FUNCTION__,Status,FALSE);
//
// Return the original clear-text packet back to NDIS.
//
NdisMSendComplete(VA->MiniportHandle,
PC(Packet)->OrigPacket,
srp->ForwardStatus);
//
// This also frees Packet.
//
SRPacketFree(srp);
}
//* MiniportFreePacket
//
// Helper function for MiniportTransmitPacket.
//
void
MiniportFreePacket(
ProtocolAdapter *PA,
NDIS_PACKET *Packet)
{
UNREFERENCED_PARAMETER(PA);
NdisFreePacketClone(Packet);
}
//* MiniportTransmitPacket
//
// Called by layer 3 protocols wanting to tx a packet via VRR miniport.
//
void
MiniportTransmitPacket(
MiniportAdapter *VA,
NDIS_PACKET *Packet)
{
SRPacket *srp;
EtherHeader UNALIGNED *Ether;
NDIS_STATUS Status;
uint IsTransportPacket = TRUE;
uint IsIPv6NS = FALSE;
InterlockedIncrement((PLONG)&VA->CountXmitLocally);
//
// For testing purposes we may want to supress all user tx.
//
if (VA->TxDropAllButHello == TRUE) {
Status = NDIS_STATUS_RESOURCES;
goto ErrorReturn;
}
VrrTrace(VA,3,"MP:Tx=entered",NULL,NULL,NULL,NULL,0,NULL,0);
//
// Allocate an SRPacket structure for this packet.
//
srp = ExAllocatePool(NonPagedPool, sizeof *srp);
if (srp == NULL) {
Status = NDIS_STATUS_RESOURCES;
goto ErrorReturn;
}
RtlZeroMemory(srp, sizeof *srp);
//
// Encrypt the packet payload (including the EType).
// This generates an IV.
//
Status = CryptoEncryptPacket(VA, Packet,
sizeof(EtherHeader) - sizeof(ushort),
srp->IV, &srp->Packet);
if (Status != NDIS_STATUS_SUCCESS)
goto ErrorFreeSRP;
//
// MiniportFreePacket will free the encrypted packet
// using NdisFreePacketClone.
//
srp->PA = NULL;
srp->FreePacket = MiniportFreePacket;
//
// This is a dummy value, so srp->PacketLength vs srp->PayloadOffset
// comparisons will work properly. We do not need the actual
// length of srp->Packet.
//
srp->PacketLength = 1;
//
// MiniportSendComplete will complete the original packet.
//
PC(srp->Packet)->OrigPacket = Packet;
//
// Initialize the virtual source & destination addresses
// in the SRPacket. If our caller supplies a bogus
// source address, we ignore it. This can happen,
// for example when the IPv4 stack detects a duplicate address
// it sends an ARP with the "wrong" source address.
//
Ether = NdisFirstBuffer(Packet)->MappedSystemVa;
RtlCopyMemory(srp->Dest, Ether->Dest, SR_ADDR_LEN);
RtlCopyMemory(srp->Source, VA->Address, SR_ADDR_LEN);
RtlCopyMemory(srp->Origin, VA->Address, SR_ADDR_LEN);
srp->FrameSeqNo = InterlockedIncrement((unsigned long *)&VrrGlobal.NextFrameSeqNo);
srp->HopCount = 0;
//
// Special case handling for IPv6 NS and DHT application packets.
//
if (IPv6TrapOutboundNS(VA,Packet,Ether)) {
//
// IPv6: trap outbound IPv6 NS. We just handled special cases for
// magic DHT addresses, and for other IPv6 addresses we drop through
// and send to nearest(VRR) by unicast transmission.
//
RtlCopyMemory(srp->Dest, Ether->Dest, SR_ADDR_LEN);
IsIPv6NS = TRUE;
VrrTrace(VA,3,"MP:Tx=TrapOutNS",NULL,NULL,Ether->Dest,NULL,0,NULL,0);
}
#if BROADCAST_SUPPORTED
else if (IsBroadcastRelay(VA)==FALSE && IPv4TrapOutboundARPRequest(VA,Packet,Ether)) {
#else
else if (IPv4TrapOutboundARPRequest(VA,Packet,Ether))
#endif
//
// Catch outbound ARP request for resolution in DHT service, and cause
// the original packet to be dropped by DHTMagicL2 test (below).
//
RtlCopyMemory(srp->Dest, DHTMagicL2, SR_ADDR_LEN);
VrrTrace(VA,3,"MP:Tx=TrapOutARP",NULL,NULL,Ether->Dest,NULL,0,NULL,0);
}
else if (IPv6TrapOutboundDHT(VA,Packet,Ether, srp)) {
//
// DHT: catches outbound UDP(DHT) and reroutes towards key in UDP payload.
// In the case of DHT-generated packets the VRR dest may use the IEEE group
// and dest bits even though the VRR addresses assigned to hosts avoid them.
//
IsTransportPacket = FALSE;
VrrTrace(VA,3,"MP:Tx=TrapOutDHT",NULL,NULL,Ether->Dest,NULL,0,NULL,0);
}
//
// Mainline handling.
//
if (RtlEqualMemory(srp->Dest, DHTMagicL2, sizeof(PhysicalAddress))) {
//
// We never transmit to the magic DHT L2 address.
//
VrrTrace(VA,3,"MP:Tx=IsDHTMagicL2",NULL,NULL,Ether->Dest,NULL,0,NULL,0);
goto ErrorFreeSRP;
}
#if BROADCAST_SUPPORTED
else if (IsBroadcastRelay(VA) == TRUE &&
IsTransportPacket == TRUE &&
IsIPv6NS == FALSE &&
IEEE_802_ADDR_IS_BROADCAST(Ether->Dest)) {
//
// The packet was broadcast. Placing it on our
// Broadcast list will filter duplicates and
// set up for relay service if we provide one.
//
uint PacketLength;
uint PayloadLength;
char *Buffer;
uint SizeofTwoEthAddr = sizeof(VirtualAddress) * 2; // payload inc EThType but not Eth addrs.
NdisQueryPacketLength(Packet, &PacketLength);
Buffer = AllocFlatBuffer(Packet,PacketLength);
PayloadLength = PacketLength - SizeofTwoEthAddr;
UpdateBroadcastList(VA, VA->Address, // tx path
srp->FrameSeqNo,0,
VA->Address, Ether->Dest, IsBroadcastRelay(VA),
//Buffer + sizeof(EtherHeader),PayloadLength);
Buffer + SizeofTwoEthAddr,PayloadLength);
ExFreePool(Buffer);
VrrTrace(VA,3,"MP:Tx=UpdtBcastList",NULL,NULL,Ether->Dest,"PktLen",PacketLength,"PayloadLen",PayloadLength);
goto ErrorFreeSRP;
}
else if (IsBroadcastRelay(VA) == FALSE &&
IsTransportPacket == TRUE &&
IsIPv6NS == FALSE &&
IEEE_802_ADDR_IS_BROADCAST(srp->Dest)) {
#else
else if (IsTransportPacket && IEEE_802_ADDR_IS_BROADCAST(srp->Dest)) {
#endif
//
// VRR does not support multicast or broadcast by a transport protocol.
//
InterlockedIncrement((PLONG)&VA->CountXmitMulticast);
VrrTrace(VA,3,"MP:Tx=drop user bcast/mcast packet",NULL,NULL,srp->Dest,NULL,0,NULL,0);
goto ErrorFreeSRP;
}
else {
//
// Send transport packet towards FindNextHop(srp->Dest).
// Similar to MaintBufSendPacket() direct (non-MB) transmission.
//
NDIS_PACKET *NewPacket = NULL;
VrrTrace(VA,3,"MP:Tx=FNH path",NULL,NULL,Ether->Dest,NULL,0,NULL,0);
//
// Original unencrypted packet must be returned to NDIS on completion.
//
srp->TransmitComplete = MiniportSendComplete;
//
// In VRR we do not piggyback control messages on data packets.
//
//
// SRPacketToPkt() performs FNH(srp->Dest,&srp->Tok) and
// initializes the eth header in NewPacket.
//
Status = SRPacketToPkt(VA, srp, &NewPacket);
if (Status != NDIS_STATUS_SUCCESS) {
MiniportSendComplete(VA, srp, Status);
return;
}
//
// The additional packet clone ex SRPackettoPkt must be released
// on completion.
//
PC(NewPacket)->srp = srp;
PC(NewPacket)->TransmitComplete = MaintBufStaticSendComplete;
if (PC(NewPacket)->PA == NULL) {
//
// This means the packet is trying to use a physical adapter that
// no longer exists.
//
VrrKdPrint("MiniportTransmitPacket: PC(NewPacket)->PA=NULL",NULL,srp->Dest);
MaintBufStaticSendComplete(VA, NewPacket, NDIS_STATUS_FAILURE);
}
else {
ProtocolTransmit(PC(NewPacket)->PA, NewPacket);
}
}
return;
ErrorFreeSRP:
SRPacketFree(srp);
ErrorReturn:
NdisMSendComplete(VA->MiniportHandle, Packet, Status);
}
//* MiniportTransmitPackets
//
// Called by NDIS to send packets via our virtual adapter.
//
void
MiniportTransmitPackets(
IN NDIS_HANDLE MiniportAdapterContext,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets)
{
MiniportAdapter *VA = (MiniportAdapter *) MiniportAdapterContext;
uint i;
for (i = 0; i < NumberOfPackets; i++)
MiniportTransmitPacket(VA, PacketArray[i]);
}
//* MiniportReceiveLocally
//
// Receives an SRPacket locally, using NdisMIndicateReceivePacket.
// Decrypts the packet data for receiving it.
//
// The ReceiveComplete handler is always called.
//
// Does NOT directly consume srp or srp->Packet,
// but the ReceiveComplete handler may do that.
//
void
MiniportReceiveLocally(
MiniportAdapter *VA,
SRPacket *srp,
void (*Complete)(MiniportAdapter *VA, SRPacket *srp, NDIS_STATUS Status))
{
NDIS_PACKET *Packet;
NDIS_BUFFER *Buffer;
void *Data;
uint BufferLength;
EtherHeader UNALIGNED *Ether;
NDIS_STATUS Status;
//
// srp->Packet is NULL only in SRPackets that we generate ourself
// (for example, for Acks, Route Requests, Route Replies)
// and we should never try to receive such a packet locally.
//
VRRASSERT(srp->Packet != NULL);
if (srp->PacketLength == srp->PayloadOffset) {
//
// This happens when we receive a packet which only contains
// options, no payload.
//
InterlockedIncrement((PLONG)&VA->CountRecvEmpty);
(*Complete)(VA, srp, NDIS_STATUS_SUCCESS);
return;
}
//
// The ethernet Type field is part of the encrypted data.
//
Status = CryptoDecryptPacket(VA, srp->Packet,
srp->PayloadOffset,
sizeof *Ether - sizeof Ether->Type,
srp->IV, &Packet);
if (Status != NDIS_STATUS_SUCCESS) {
KdPrint(("VRR!MiniportReceiveLocally: CryptoDecryptPacket: %x\n", Status));
InterlockedIncrement((PLONG)&VA->CountRecvDecryptFailure);
(*Complete)(VA, srp, Status);
return;
}
//
// Get the ethernet header in the packet.
//
Buffer = NdisFirstBuffer(Packet);
NdisQueryBuffer(Buffer, &Data, &BufferLength);
if (BufferLength < sizeof *Ether) {
InterlockedIncrement((PLONG)&VA->CountRecvSmall);
NdisFreePacketClone(Packet);
(*Complete)(VA, srp, NDIS_STATUS_INVALID_PACKET);
return;
}
//
// If the Type is ETYPE_MSFT, we do not receive the packet.
//
Ether = (EtherHeader UNALIGNED *) Data;
if (Ether->Type == ETYPE_MSFT) {
InterlockedIncrement((PLONG)&VA->CountRecvRecursive);
NdisFreePacketClone(Packet);
(*Complete)(VA, srp, NDIS_STATUS_SUCCESS);
return;
}
InterlockedIncrement((PLONG)&VA->CountRecvLocally);
//
// Initialize the ethernet header.
//
RtlCopyMemory(Ether->Dest, VA->Address, SR_ADDR_LEN);
RtlCopyMemory(Ether->Source, srp->Source, SR_ADDR_LEN);
//
// Prepare for MiniportReturnPacket.
//
PC(Packet)->srp = srp;
PC(Packet)->ReceiveComplete = Complete;
//
// Indicate the packet up to any transports bound to us.
// MiniportReturnPacket will be called asynchronously.
//
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
NDIS_SET_PACKET_HEADER_SIZE(Packet, sizeof *Ether);
NdisMIndicateReceivePacket(VA->MiniportHandle, &Packet, 1);
}
//* MiniportReturnPacket
//
// Called by NDIS to return a packet after the transports have
// finished their receive processing.
//
void
MiniportReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet)
{
MiniportAdapter *VA = (MiniportAdapter *) MiniportAdapterContext;
SRPacket *srp = PC(Packet)->srp;
void (*Complete)(MiniportAdapter *VA, SRPacket *srp, NDIS_STATUS Status) =
PC(Packet)->ReceiveComplete;
//
// Free the clear-text packet that was created
// in MiniportReceiveLocally.
//
NdisFreePacketClone(Packet);
//
// Indicate the completion of receive processing.
//
(*Complete)(VA, srp, NDIS_STATUS_SUCCESS);
}
//* MiniportReceiveComplete
//
// Called after the completion of local receive processing
// of an SRPacket.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -