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

📄 ipv6.c

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

//
// This file contains procedures for supporting IPv6 over VRR.
//

#include "headers.h"
#include <packon.h>

extern void
MiniportTransmitPacket(
    MiniportAdapter *VA,
    NDIS_PACKET *Packet);

extern void
MiniportFreePacket(
    ProtocolAdapter *PA,
    NDIS_PACKET *Packet);

extern void
MiniportReceiveLocally(
    MiniportAdapter *VA,
    SRPacket *srp,
    void (*Complete)(MiniportAdapter *VA, SRPacket *srp, NDIS_STATUS Status));

extern void
MiniportReceiveComplete(
    MiniportAdapter *VA,
    SRPacket *srp,
    NDIS_STATUS Status);

// Forward declaration.
boolint
IPv6FakeDHTtxNA(
    MiniportAdapter *VA,
    IPv6Addr SolicitSource);

//
// Magic addresses used to support DHT functionality on VRR.
// These addresses are real addresses taken from host msrc-gregos05.
// Therefore nobody else should ever legitimately conflict with them.
//
IPv6Addr UnspecifiedAddr = { 0 };
IPv6Addr DHTtxAddr = {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                      0x02, 0x0d, 0x56, 0xff, 0xfe, 0x6d, 0xf0, 0x2c};
IPv6Addr DHTrxAddr = {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                      0x02, 0x04, 0x23, 0xff, 0xfe, 0xa3, 0x21, 0x13};
PhysicalAddress DHTMagicL2 = {0x00, 0x0d, 0x56, 0x6d, 0xf0, 0x2c};


#define ETYPE_IPv6 0x86dd
// gregos: these so we can snip types from ipv6 header files.
typedef unsigned char   u_char;
typedef unsigned short  u_short;
typedef unsigned int    u_int;
typedef unsigned long   u_long;
typedef unsigned char   uchar;
typedef unsigned short  ushort;
typedef unsigned int    uint;
typedef unsigned long   ulong;
typedef struct in6_addr in6_addr;


//* EthAddrIsIPv6ND
__inline boolint
EthAddrIsIPv6ND(const PhysicalAddress A)
{
    //
    // The MS IPv6 stacks emit ND frames with 802.3 prefix 0x3333ff/24.
    // The low order 32-bits are treated by eth as a multicast groups address.
    //
    return ((A[0] == 0x33) && (A[1] == 0x33) && (A[2] == 0xff));
}

__inline boolint
IPv6AddrIsLinkLocal(in6_addr *IPv6Addr)
{
    uchar *A = (uchar *)IPv6Addr;

    return ((A[0] == 0xfe) && ((A[1] & 0xc0) == 0x80));
}

//
// For comparing IPv6 addresseses.
//
__inline int
IP6_ADDR_EQUAL(const IPv6Addr *x, const IPv6Addr *y)
{
    __int64 UNALIGNED *a;
    __int64 UNALIGNED *b;

    a = (__int64 UNALIGNED *)x;
    b = (__int64 UNALIGNED *)y;

    return (a[1] == b[1]) && (a[0] == b[0]);
}

//
// Following taken from msripv6\inc\ip6.h
// IPv6 Header Format.
// See RFC 1883, page 5 (and subsequent draft updates to same).
//
typedef struct IPv6Header {
    ulong VersClassFlow;   // 4 bits Version, 8 Traffic Class, 20 Flow Label.
    ushort PayloadLength;  // Zero indicates Jumbo Payload hop-by-hop option.
    uchar NextHeader;      // Values are superset of IPv4's Protocol field.
    uchar HopLimit;
    struct in6_addr Source;
    struct in6_addr Dest;
} IPv6Header;

//
// Useful constants for working with various fields in the IPv6 header.
//
// NOTE: We keep the Version, Traffic Class and Flow Label fields as a single
// NOTE: 32 bit value (VersClassFlow) in network byte order (big-endian).
// NOTE: Since NT is little-endian, this means all loads/stores to/from this
// NOTE: field need to be byte swapped.
//
#define IP_VER_MASK 0x000000F0  // Version is high 4 bits of VersClassFlow.
#define IP_VERSION6 0x00000060   // This is 6 << 28 (after byte swap).

#define IP_PROTOCOL_ICMPv6    58  // IPv6 Internet Control Message Protocol.

//
// Following taken from msripv6\inc\icmp.h
// ICMPv6 Header.
// The actual message body follows this header and is type-specific.
//
typedef struct ICMPv6Header {
    uchar Type;       // Type of message (high bit zero for error messages).
    uchar Code;       // Type-specific differentiater.
    ushort Checksum;  // Calculated over ICMPv6 message and IPv6 psuedo-header.
} ICMPv6Header;

#define ICMPv6_NEIGHBOR_SOLICIT           135
#define ICMPv6_NEIGHBOR_ADVERT            136

//
// IPv6 ND headers.
//
typedef struct IPv6NS {
    ICMPv6Header ICMPHeader;
    unsigned int  reserved;
    in6_addr TargetAddress;
} IPv6NS;

typedef struct IPv6NA {
    ICMPv6Header ICMPHeader;
    unsigned int Flags;
    in6_addr TargetAddress;
    uchar TLLAType;
    uchar TLLALength;
    PhysicalAddress TLLAddress;
} IPv6NA;

#define ND_NA_FLAG_SOLICITED 0x40000000
#define ND_NA_FLAG_OVERRIDE  0x20000000

//
// Following struct taken from msripv6\tcpip6\udp\udp.h
// Structure of a UDP header.
//
#define IP_PROTOCOL_UDP 17
typedef struct UDPHeader {
    ushort Source;    // Source port.
    ushort Dest;      // Destination port.
    ushort Length;    // Length.
    ushort Checksum;  // Checksum.
} UDPHeader;

//* DHTTrapPacketMaxSize
//
//  Returns max payload size supported via DHT_TRAP_PACKET API.
//
ULONG
DHTTrapPacketMaxSize()
{
    return PROTOCOL_MIN_FRAME_SIZE 
           - sizeof(EtherHeader)
           - sizeof(IPv6Header)
           - sizeof(UDPHeader)
           - sizeof(DHTHeader);
}

//* IPv6AddrToVirtualAddr
//
//  Extracts MAC address bits from an IPv6 address
//  into the correspondng VRR Address.
//
IPv6AddrToVirtualAddr(
    in6_addr *IPv6Addr,
    VirtualAddress VRRAddr)
{
    uchar *From = (uchar *)IPv6Addr;
    uchar *To = (uchar *)VRRAddr;
    To[0] = From[8];
    To[0] &= 0xfd;
    To[1] = From[9];
    To[2] = From[10];
    To[3] = From[13];
    To[4] = From[14];
    To[5] = From[15];
}

//* AllocFlatBuffer
//
//  Helper for IPv6 optimizations that facilitates parsing of headers.
//
//  Allocates and returns a flat buffer containing leading n bytes from 
//  an NDIS packet supplied by the caller.
//
//  The caller is responsible for releasing the memory returned.
//
char *
AllocFlatBuffer(
    NDIS_PACKET *Packet,
    uint BytesRequired)
{
    uint PacketLength;
    NDIS_BUFFER *Buffer;
    uint BufferLength;
    uint FlatBytes = 0;
    uchar *FlatBuffer;
    uchar *Flat;

    if (BytesRequired == 0)
        return NULL;
    NdisQueryPacketLength(Packet, &PacketLength);
    if (PacketLength < BytesRequired)
        return NULL;

    FlatBuffer=ExAllocatePool(NonPagedPool, BytesRequired);
    if (FlatBuffer == NULL)
        return NULL;

    Flat = FlatBuffer;
    Buffer = NdisFirstBuffer(Packet);

    while (FlatBytes < BytesRequired) {
        uchar *Data;
        uint Transfer;

        NdisQueryBuffer(Buffer, &Data, &BufferLength);
        Transfer = min(BufferLength, BytesRequired - FlatBytes);
        RtlCopyMemory(Flat, Data, Transfer);
        FlatBytes += Transfer;
        Flat += Transfer;
        NdisGetNextBuffer(Buffer, &Buffer);
    }

    return FlatBuffer;
}

//* Cksum
//
//  Helper for ChecksumPacket. See RFC793.
//
unsigned short
Cksum(
      unsigned char *c,
      unsigned int Length)
{
    unsigned int cks = 0;
    unsigned short *ps = (unsigned short *)c;
    unsigned short *pSentinel = ps + (Length >> 1);

    while (ps < pSentinel) 
        cks += *ps++;  // Next ushort.

    if (Length & 1)
        cks += *(c + Length - 1); // Final char.

    cks = (cks >> 16) + (cks & 0xFFFF);
    cks = (cks >> 16) + (cks & 0xFFFF);

    return (unsigned short)cks;
}

//* IPv6TrapOutboundNS
//
//  We trap outbound IPv6 Neighbor Solicitations, thus:
//   - Duplicate Addresses detection packets are dropped;
//   - solicitations other than link-local drop through;
//   - link-local solicitations are handled as follows.
// 
//  Link-local solicitations are handled by rewriting and
//  redirecting them towards the VRR node with the closest
//  address to the address from which the Interface Id of
//  the target address in the solicitation was derived.
//  This allows applications to use VRR to perform DHT-type
//  operations of routing to the node with the closest key
//  to some given key where the closest key is a VRR address
//  and the given key is encoded in the interface Id of the
//  IPv6 target address.
//
//  Returns true if an IPv6 Neighbor Solicitation was found
//  and handled, otherwise returns false.
//
boolint
IPv6TrapOutboundNS(
    MiniportAdapter *VA,
    NDIS_PACKET *Packet,
    EtherHeader *eth)
{
    void *Address;
    uint BufferLength;
    uint PacketLength;
    NDIS_BUFFER *Buffer;
    const uint MinBuffSize = sizeof(EtherHeader)
                           + sizeof(IPv6Header)
                           + sizeof(IPv6NS);
    IPv6Header UNALIGNED *IPv6;
    ICMPv6Header UNALIGNED *ICMPv6;
    IPv6NS UNALIGNED *NS;
    uchar *Tgt;
    VirtualAddress VAddr;

    //
    // We are only interested in IPv6 packets that look
    // like they are destined to eth multicast address.
    //
    if (RtlUshortByteSwap(eth->Type) != ETYPE_IPv6)
        return FALSE;
    if (EthAddrIsIPv6ND(eth->Dest) == FALSE &&
        RtlEqualMemory(eth->Dest,DHTMagicL2,sizeof(PhysicalAddress)) == FALSE)
        return FALSE;

    //
    // Ethernet header looks like that of an IPv6 Neighbor Solicitation.
    // Check that packet is large enough to be an NS.
    //
    Buffer = NdisFirstBuffer(Packet);
    NdisQueryBuffer(Buffer, &Address, &BufferLength);
    NdisQueryPacketLength(Packet, &PacketLength);

    if (BufferLength < MinBuffSize)
        return FALSE;

    //
    // The packet is big enough to be an IPv6 Neighbor
    // solicitation. Now check the IPv6 and ICMPv6 headers.
    //
    IPv6 = (IPv6Header UNALIGNED *)(eth + 1);
    ICMPv6 = (ICMPv6Header UNALIGNED *)(IPv6 + 1);
    NS = (IPv6NS UNALIGNED *)ICMPv6;
    Tgt = (uchar *)&NS->TargetAddress;

    if ((IPv6->VersClassFlow & IP_VERSION6) != IP_VERSION6 ||
        ICMPv6->Type != ICMPv6_NEIGHBOR_SOLICIT ||
        ICMPv6->Code != 0) {

        KdPrint(("VrrKdPrint: (%u) IPv6OutNS: not ICMPv6 NS, ignored\n", TIMESTAMP));
        return FALSE;
    }

    //
    // This is indeed an IPv6 Neighbor Solicitation.
    //
    if (IP6_ADDR_EQUAL(&NS->TargetAddress,&DHTrxAddr)) {
        //
        // Drop NS to DHT rx address. This prevents DAD from detecting 
        // duplicate instances of this special address in VRR rings.
        //
        return TRUE;
    }
    else if (IP6_ADDR_EQUAL(&NS->TargetAddress,&DHTtxAddr)) {
        //
        // Trap NS for the DHT tx address and send a fake NA
        // up to our IPv6 protocol stack. This quietens DAD
        // for the DHT tx address and associates it with 
        // DHTMagicL2 in the local IPv6 Neighbor Cache.
        //
        IPv6FakeDHTtxNA(VA, IPv6->Source);
        return TRUE;
    }
    else if (IPv6AddrIsLinkLocal(&NS->TargetAddress)) {
        //
        // Determine the VRR address from which the interface
        // id of the target IPv6 address would have been
        // derived by IPv6 stateless address autoconfiguration.
        //
        IPv6AddrToVirtualAddr(&NS->TargetAddress,VAddr);

        //
        // What we do next has implications for IPv6 Duplicate
        // Address Detection or IPv6 Neighbor Discovery.
        //
        if (VirtualAddressEqual(VA->Address,VAddr)) {
            //
            // NS to self is dropped, therefore IPv6 depends upon
            // VRR to keep duplicate addresses out of the network.
            //
            KdPrint(("VrrKdPrint: (%u) IPv6OutNS: target=self, drop packet, note DAD skipped.)\n",TIMESTAMP));
        }
        else {
            //
            // Otherwise we route IPv6 Neighbor Solicitations towards
            // the VRR node with the closest matching VRR address.
            //
            RtlCopyMemory(eth->Dest,VAddr,sizeof(VirtualAddress));
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -