⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipv6.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 3 页
字号:
                //
                // 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 + -