1409 lines
42 KiB
C
1409 lines
42 KiB
C
|
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
|
||
|
//
|
||
|
// Copyright (c) 1985-2000 Microsoft Corporation
|
||
|
//
|
||
|
// This file is part of the Microsoft Research IPv6 Network Protocol Stack.
|
||
|
// You should have received a copy of the Microsoft End-User License Agreement
|
||
|
// for this software along with this release; see the file "license.txt".
|
||
|
// If not, please see http://www.research.microsoft.com/msripv6/license.htm,
|
||
|
// or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// IPv6 private definitions.
|
||
|
//
|
||
|
// This file contains all of the definitions for IPv6 that
|
||
|
// are not visible to outside layers.
|
||
|
//
|
||
|
|
||
|
|
||
|
#ifndef IPv6DEF_INCLUDED
|
||
|
#define IPv6DEF_INCLUDED 1
|
||
|
|
||
|
typedef struct NeighborCacheEntry NeighborCacheEntry;
|
||
|
typedef struct AddressEntry AddressEntry;
|
||
|
typedef struct MulticastAddressEntry MulticastAddressEntry;
|
||
|
typedef struct AnycastAddressEntry AnycastAddressEntry;
|
||
|
typedef struct NetTableEntryOrInterface NetTableEntryOrInterface;
|
||
|
typedef struct NetTableEntry NetTableEntry;
|
||
|
typedef struct Interface Interface;
|
||
|
|
||
|
typedef struct IPSecProc IPSecProc;
|
||
|
|
||
|
// REVIEW: Added so the build will work.
|
||
|
typedef unsigned long IPAddr;
|
||
|
#define INADDR_ANY 0
|
||
|
|
||
|
//
|
||
|
// Override the default DDK definitions of ASSERT/ASSERTMSG.
|
||
|
// The default definitions use RtlAssert, which does nothing
|
||
|
// unless you are using a checked kernel.
|
||
|
//
|
||
|
#undef ASSERT
|
||
|
#undef ASSERTMSG
|
||
|
|
||
|
#if DBG
|
||
|
#define ASSERT(exp) \
|
||
|
if (!(exp)) { \
|
||
|
DbgPrint("assert failed (%s, %d): %s\n", __FILE__, __LINE__, #exp); \
|
||
|
DbgBreakPoint(); \
|
||
|
} else
|
||
|
|
||
|
#define ASSERTMSG(msg, exp) \
|
||
|
if (!(exp)) { \
|
||
|
DbgPrint("assert failed (%s, %d): %s\n", __FILE__, __LINE__, (msg)); \
|
||
|
DbgBreakPoint(); \
|
||
|
} else
|
||
|
|
||
|
#else
|
||
|
#define ASSERT(exp)
|
||
|
#define ASSERTMSG(msg, exp)
|
||
|
#endif // DBG
|
||
|
|
||
|
//
|
||
|
// Per-neighbor information. We keep address translation and unreachability
|
||
|
// detection info for each of our neighbors that we're in communication with.
|
||
|
//
|
||
|
// A non-zero reference count prevents the NCE from being reclaimed.
|
||
|
// An NCE with zero references may be kept cached.
|
||
|
// A per-interface lock protects all NCEs for that interface.
|
||
|
//
|
||
|
// NCEs with a non-zero reference count hold a reference for their interface.
|
||
|
// NCEs with a zero reference count do not hold a reference.
|
||
|
// This means if you hold a reference for an NCE,
|
||
|
// you can always safely access and dereference NCE->IF.
|
||
|
//
|
||
|
// The Next/Prev fields link NCEs into a circular doubly-linked list.
|
||
|
// They must be first and must match the IF->FirstNCE/LastNCE fields
|
||
|
// to make the casting work out.
|
||
|
//
|
||
|
// The list of NCEs is kept sorted, from most-recently-used to least.
|
||
|
//
|
||
|
struct NeighborCacheEntry { // a.k.a. NCE
|
||
|
NeighborCacheEntry *Next; // Next entry on I/F neighbor list.
|
||
|
NeighborCacheEntry *Prev; // Previous entry on I/F neighbor list.
|
||
|
IPv6Addr NeighborAddress; // Address of I/F on neighboring node.
|
||
|
void *LinkAddress; // Media address corresponding to above.
|
||
|
// NB: LinkAddressLength field not needed - use IF->LinkAddressLength.
|
||
|
ushort IsRouter:1, // Is the neighbor a router?
|
||
|
IsUnreachable:1, // Does ND indicate unreachability?
|
||
|
// DoRoundRobin is only meaningful if IsUnreachable is TRUE.
|
||
|
DoRoundRobin:1, // Should FindRoute do round-robin?
|
||
|
IsLoopback:1; // Do we loopback to this neighbor
|
||
|
// in software?
|
||
|
ushort NDState; // Neighbor Discovery Protocol state.
|
||
|
uint LastReachability; // Timestamp (IPv6Timer ticks).
|
||
|
ushort NSTimer; // In IPv6Timer ticks (see IPv6Timeout).
|
||
|
uchar NSCount; // Number of solicits sent so far.
|
||
|
uchar NSLimit; // Total number of solicits to send.
|
||
|
Interface *IF; // Interface on media with neighbor.
|
||
|
NDIS_PACKET *WaitQueue; // Queue of packets waiting on ND.
|
||
|
long RefCnt; // Reference count - interlocked.
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// The caller must already have a reference for the NCE.
|
||
|
// The interface need not be locked.
|
||
|
//
|
||
|
__inline void
|
||
|
AddRefNCE(NeighborCacheEntry *NCE)
|
||
|
{
|
||
|
long RefCnt = InterlockedIncrement(&NCE->RefCnt);
|
||
|
ASSERT(RefCnt != 1);
|
||
|
}
|
||
|
|
||
|
extern void
|
||
|
AddRefNCEInCache(NeighborCacheEntry *NCE);
|
||
|
|
||
|
extern void
|
||
|
ReleaseNCE(NeighborCacheEntry *NCE);
|
||
|
|
||
|
//
|
||
|
// Values for "NDState" above. See RFC 1970, section 7.3.2 for details.
|
||
|
// Note: only state names are documented, we chose the values used here.
|
||
|
//
|
||
|
// In the INCOMPLETE state, the LinkAddress is not valid.
|
||
|
// In all other states, LinkAddress may be used to send packets.
|
||
|
// WaitQueue is usually only non-NULL in the INCOMPLETE state,
|
||
|
// but sometimes a packet is left queued for NeighborCacheTimeout.
|
||
|
//
|
||
|
// The INCOMPLETE state has two flavors, dormant and active. If
|
||
|
// EventTimer and EventCount are both zero, then we are not actively
|
||
|
// trying to solicit the link address. If someone tries to send to
|
||
|
// this neighbor, then we start soliciting the link address. If the
|
||
|
// solicitation fails (or if we enter the PROBE state and then fail to
|
||
|
// confirm reachability), then any waiting packets are discarded and
|
||
|
// we reset to INCOMPLETE with zero EventTimer/EventCount. (So with
|
||
|
// the next use of this neighbor, we start soliciting again from scratch.)
|
||
|
//
|
||
|
// The DELAY state is not used internally. Instead we use the PROBE state
|
||
|
// with zero NSCount and non-zero NSTimer to indicate that we are delaying
|
||
|
// the start of probing. However link-layer lip_cvaddr functions can
|
||
|
// return ND_STATE_DELAY and IoctlQueryNeighborCache returns ND_STATE_DELAY.
|
||
|
//
|
||
|
// The IsUnreachable flag tracks separately whether the neighbor is
|
||
|
// *known* to be unreachable. For example, a new NCE will be in in the
|
||
|
// INCOMPLETE state, but IsUnreachable is FALSE because we don't know
|
||
|
// yet whether the neighbor is reachable. Because FindRoute uses
|
||
|
// IsUnreachable, code paths that change this flag must call
|
||
|
// InvalidateRouteCache.
|
||
|
//
|
||
|
// These definitions are also in llip6if.h and ntddip6.w.
|
||
|
//
|
||
|
#define ND_STATE_INCOMPLETE 0
|
||
|
#define ND_STATE_PROBE 1
|
||
|
#define ND_STATE_DELAY 2 // Not used internally.
|
||
|
#define ND_STATE_STALE 3
|
||
|
#define ND_STATE_REACHABLE 4
|
||
|
#define ND_STATE_PERMANENT 5
|
||
|
|
||
|
|
||
|
//
|
||
|
// There are a few places in the implementation where we need
|
||
|
// to pass a pointer which is either a NetTableEntry or an Interface.
|
||
|
// NetTableEntries and Interfaces share this structure as their
|
||
|
// first element. With Interfaces, the IF field points back
|
||
|
// at the Interface itself.
|
||
|
//
|
||
|
struct NetTableEntryOrInterface { // a.k.a. NTEorIF
|
||
|
Interface *IF;
|
||
|
};
|
||
|
|
||
|
__inline int
|
||
|
IsNTE(NetTableEntryOrInterface *NTEorIF)
|
||
|
{
|
||
|
return (NetTableEntryOrInterface *)NTEorIF->IF != NTEorIF;
|
||
|
}
|
||
|
|
||
|
__inline NetTableEntry *
|
||
|
CastToNTE(NetTableEntryOrInterface *NTEorIF)
|
||
|
{
|
||
|
ASSERT(IsNTE(NTEorIF));
|
||
|
return (NetTableEntry *) NTEorIF;
|
||
|
}
|
||
|
|
||
|
__inline NetTableEntryOrInterface *
|
||
|
CastFromNTE(NetTableEntry *NTE)
|
||
|
{
|
||
|
return (NetTableEntryOrInterface *) NTE;
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsIF(NetTableEntryOrInterface *NTEorIF)
|
||
|
{
|
||
|
return (NetTableEntryOrInterface *)NTEorIF->IF == NTEorIF;
|
||
|
}
|
||
|
|
||
|
__inline Interface *
|
||
|
CastToIF(NetTableEntryOrInterface *NTEorIF)
|
||
|
{
|
||
|
ASSERT(IsIF(NTEorIF));
|
||
|
return (Interface *) NTEorIF;
|
||
|
}
|
||
|
|
||
|
__inline NetTableEntryOrInterface *
|
||
|
CastFromIF(Interface *IF)
|
||
|
{
|
||
|
return (NetTableEntryOrInterface *) IF;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Local address information. Each interface keeps track of the addresses
|
||
|
// assigned to the interface. Depending on the type of address, each
|
||
|
// ADE structure is the first element of a larger NTE, MAE, or AAE structure.
|
||
|
// The address information is protected by the interface's lock.
|
||
|
//
|
||
|
// The NTEorIF field must be first. In NTEs, it points to the interface
|
||
|
// and holds a reference for the interface. In MAEs and AAEs, it can
|
||
|
// point to the interface or to one of the NTEs on the interface but in
|
||
|
// either case it does NOT hold a reference.
|
||
|
//
|
||
|
struct AddressEntry { // a.k.a. ADE
|
||
|
union {
|
||
|
Interface *IF;
|
||
|
NetTableEntry *NTE;
|
||
|
NetTableEntryOrInterface *NTEorIF;
|
||
|
};
|
||
|
AddressEntry *Next; // Linkage on chain.
|
||
|
IPv6Addr Address; // Address identifying this entry.
|
||
|
ushort Type; // Address type (unicast, multicast, etc).
|
||
|
ushort Scope; // Address scope (link, site, global, etc).
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Values for address Type.
|
||
|
//
|
||
|
#define ADE_UNICAST 0x00
|
||
|
#define ADE_ANYCAST 0x01
|
||
|
#define ADE_MULTICAST 0x02
|
||
|
#define ADE_NONE ((ushort)-1) // Indicates absence of an ADE.
|
||
|
|
||
|
//
|
||
|
// Values for address Scope.
|
||
|
//
|
||
|
#define ADE_SMALLEST_SCOPE 0x00
|
||
|
#define ADE_INTERFACE_LOCAL 0x01
|
||
|
#define ADE_LINK_LOCAL 0x02
|
||
|
#define ADE_SUBNET_LOCAL 0x03
|
||
|
#define ADE_ADMIN_LOCAL 0x04
|
||
|
#define ADE_SITE_LOCAL 0x05
|
||
|
#define ADE_ORG_LOCAL 0x08
|
||
|
#define ADE_GLOBAL 0x0e
|
||
|
#define ADE_LARGEST_SCOPE 0x0f
|
||
|
|
||
|
#define ADE_NUM_SCOPES (ADE_LARGEST_SCOPE - ADE_SMALLEST_SCOPE + 1)
|
||
|
|
||
|
//
|
||
|
// Multicast ADEs are really MAEs.
|
||
|
//
|
||
|
// MAEs can be a separate global QueryList.
|
||
|
// If an MAE on an Interface has a non-zero MCastTimer value,
|
||
|
// then it is on the QueryList.
|
||
|
//
|
||
|
// An MAE can be on the QueryList with a zero MCastTimer value
|
||
|
// only when it is not on any interface and it just needs
|
||
|
// a Done message sent before it can be deleted.
|
||
|
// When it is in this state (but not otherwise), MAE->IF
|
||
|
// holds a reference for the interface.
|
||
|
//
|
||
|
struct MulticastAddressEntry { // a.k.a. MAE
|
||
|
AddressEntry; // Inherit the ADE fields.
|
||
|
uint MCastRefCount; // Sockets/etc receiving from this group.
|
||
|
//
|
||
|
// The fields below are protected by the QueryList lock.
|
||
|
//
|
||
|
ushort MCastFlags:4, // Necessary info about a group.
|
||
|
MCastCount:4; // Count of initial reports left to send.
|
||
|
ushort MCastTimer; // Ticks until a membership report is sent.
|
||
|
MulticastAddressEntry *NextQL; // For the QueryList.
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Bit values for MCastFlags.
|
||
|
//
|
||
|
#define MAE_REPORTABLE 0x01 // We should send Reports.
|
||
|
#define MAE_LAST_REPORTER 0x02 // We should send Done.
|
||
|
|
||
|
|
||
|
//
|
||
|
// Anycast ADEs are really AAEs.
|
||
|
// Currently an AAE has no additional fields.
|
||
|
//
|
||
|
struct AnycastAddressEntry { // a.k.a. AAE
|
||
|
AddressEntry; // Inherit the ADE fields.
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Unicast ADEs are really NTEs.
|
||
|
// There is one NTE for each source (unicast) address
|
||
|
// assigned to an interface.
|
||
|
//
|
||
|
// NTEs hold a reference for their interface,
|
||
|
// so if you have a reference for an NTE
|
||
|
// you can always safely access and dereference NTE->IF.
|
||
|
//
|
||
|
// Most NTE fields are either read-only or are protected
|
||
|
// by the interface lock. The interface WorkerLock protects
|
||
|
// the TdiRegistrationHandle field.
|
||
|
//
|
||
|
// Anonyous addresses (AddrConf == ADDR_CONF_ANONYMOUS)
|
||
|
// have extra fields - see AnonNetTableEntry.
|
||
|
//
|
||
|
struct NetTableEntry { // a.k.a. NTE
|
||
|
AddressEntry; // Inherit the ADE fields.
|
||
|
NetTableEntry *NextOnNTL; // Next NTE on NetTableList.
|
||
|
NetTableEntry **PrevOnNTL; // Previous Next pointer in NetTableList.
|
||
|
HANDLE TdiRegistrationHandle; // Opaque token for TDI De/notification.
|
||
|
long RefCnt; // Reference count - interlocked.
|
||
|
uint ValidLifetime; // In IPv6Timer ticks (see IPv6Timeout).
|
||
|
uint PreferredLifetime; // In IPv6Timer ticks (see IPv6Timeout).
|
||
|
uchar AddrConf; // Address configuration status.
|
||
|
uchar DADState; // Address configuration state.
|
||
|
ushort DADCount; // How many DAD solicits left to send.
|
||
|
ushort DADTimer; // In IPv6Timer ticks (see IPv6Timeout).
|
||
|
};
|
||
|
|
||
|
__inline void
|
||
|
AddRefNTE(NetTableEntry *NTE)
|
||
|
{
|
||
|
InterlockedIncrement(&NTE->RefCnt);
|
||
|
}
|
||
|
|
||
|
__inline void
|
||
|
ReleaseNTE(NetTableEntry *NTE)
|
||
|
{
|
||
|
InterlockedDecrement(&NTE->RefCnt);
|
||
|
}
|
||
|
|
||
|
struct AddrConfEntry {
|
||
|
union {
|
||
|
uchar Value; // Address configuration status.
|
||
|
struct {
|
||
|
uchar InterfaceIdConf : 4;
|
||
|
uchar PrefixConf : 4;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Values for PrefixConf - must fit in 4 bits.
|
||
|
// These must match the values in ntddip6.h, as well as the
|
||
|
// IP_PREFIX_ORIGIN values in iptypes.h.
|
||
|
//
|
||
|
#define PREFIX_CONF_OTHER 0 // None of the ones below.
|
||
|
#define PREFIX_CONF_MANUAL 1 // From a user or administrator.
|
||
|
#define PREFIX_CONF_WELLKNOWN 2 // IANA-assigned.
|
||
|
#define PREFIX_CONF_DHCP 3 // Configured via DHCP.
|
||
|
#define PREFIX_CONF_RA 4 // From a Router Advertisement.
|
||
|
|
||
|
//
|
||
|
// Values for InterfaceIdConf - must fit in 4 bits.
|
||
|
// These must match the values in ntddip6.h, as well as the
|
||
|
// IP_SUFFIX_ORIGIN values in iptypes.h.
|
||
|
//
|
||
|
#define IID_CONF_OTHER 0 // None of the ones below.
|
||
|
#define IID_CONF_MANUAL 1 // From a user or administrator.
|
||
|
#define IID_CONF_WELLKNOWN 2 // IANA-assigned.
|
||
|
#define IID_CONF_DHCP 3 // Configured via DHCP.
|
||
|
#define IID_CONF_LL_ADDRESS 4 // Derived from the link-layer address.
|
||
|
#define IID_CONF_RANDOM 5 // Random, e.g. anonymous address.
|
||
|
|
||
|
//
|
||
|
// Values for AddrConf - must fit in 8 bits.
|
||
|
//
|
||
|
#define ADDR_CONF_MANUAL ((PREFIX_CONF_MANUAL << 4) | IID_CONF_MANUAL)
|
||
|
#define ADDR_CONF_PUBLIC ((PREFIX_CONF_RA << 4) | IID_CONF_LL_ADDRESS)
|
||
|
#define ADDR_CONF_ANONYMOUS ((PREFIX_CONF_RA << 4) | IID_CONF_RANDOM)
|
||
|
#define ADDR_CONF_DHCP ((PREFIX_CONF_DHCP << 4) | IID_CONF_DHCP)
|
||
|
#define ADDR_CONF_WELLKNOWN ((PREFIX_CONF_WELLKNOWN << 4) | IID_CONF_WELLKNOWN)
|
||
|
#define ADDR_CONF_LINK ((PREFIX_CONF_WELLKNOWN << 4) | IID_CONF_LL_ADDRESS)
|
||
|
|
||
|
__inline int
|
||
|
IsValidPrefixConfValue(uint PrefixConf)
|
||
|
{
|
||
|
return PrefixConf < (1 << 4);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsValidInterfaceIdConfValue(uint InterfaceIdConf)
|
||
|
{
|
||
|
return InterfaceIdConf < (1 << 4);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsStatelessAutoConfNTE(NetTableEntry *NTE)
|
||
|
{
|
||
|
return ((struct AddrConfEntry *)&NTE->AddrConf)->PrefixConf == PREFIX_CONF_RA;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Values for DADState.
|
||
|
//
|
||
|
// The "deprecated" and "preferred" states are valid,
|
||
|
// meaning that addresses in those two states can be
|
||
|
// used as a source address, can receive packets, etc.
|
||
|
// The invalid states mean that the address is
|
||
|
// not actually assigned to the interface,
|
||
|
// using the terminology of RFC 2462.
|
||
|
//
|
||
|
// Valid<->invalid and deprecated<->preferred transitions
|
||
|
// must call InvalidateRouteCache because they affect
|
||
|
// source address selection.
|
||
|
//
|
||
|
// Among valid states, bigger is better
|
||
|
// for source address selection.
|
||
|
//
|
||
|
#define DAD_STATE_INVALID 0
|
||
|
#define DAD_STATE_TENTATIVE 1
|
||
|
#define DAD_STATE_DUPLICATE 2
|
||
|
#define DAD_STATE_DEPRECATED 3
|
||
|
#define DAD_STATE_PREFERRED 4
|
||
|
|
||
|
__inline int
|
||
|
IsValidNTE(NetTableEntry *NTE)
|
||
|
{
|
||
|
return (NTE->DADState >= DAD_STATE_DEPRECATED);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsTentativeNTE(NetTableEntry *NTE)
|
||
|
{
|
||
|
return (NTE->DADState == DAD_STATE_TENTATIVE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We use this infinite lifetime value for prefix lifetimes,
|
||
|
// router lifetimes, address lifetimes, etc.
|
||
|
//
|
||
|
#define INFINITE_LIFETIME 0xffffffff
|
||
|
|
||
|
//
|
||
|
// Anonymous addresses have extra fields.
|
||
|
//
|
||
|
typedef struct AnonNetTableEntry {
|
||
|
NetTableEntry; // Inherit the NTE fields.
|
||
|
NetTableEntry *Public; // Does not hold a reference.
|
||
|
uint CreationTime; // In ticks (see IPv6TickCount).
|
||
|
} AnonNetTableEntry;
|
||
|
|
||
|
//
|
||
|
// Each interface keeps track of which link-layer multicast addresses
|
||
|
// are currently enabled for receive. A reference count is required because
|
||
|
// multiple IPv6 multicast addresses can map to a single link-layer
|
||
|
// multicast address. The low bit of RefCntAndFlags is a flag that, if set,
|
||
|
// indicates the link-layer address has been registered with the link.
|
||
|
//
|
||
|
typedef struct LinkLayerMulticastAddress {
|
||
|
uint RefCntAndFlags;
|
||
|
uchar LinkAddress[]; // The link-layer address follows in memory.
|
||
|
// Padded to provide alignment.
|
||
|
} LinkLayerMulticastAddress;
|
||
|
|
||
|
#define LLMA_FLAG_REGISTERED 0x1
|
||
|
|
||
|
__inline void
|
||
|
AddRefLLMA(LinkLayerMulticastAddress *LLMA)
|
||
|
{
|
||
|
LLMA->RefCntAndFlags += (LLMA_FLAG_REGISTERED << 1);
|
||
|
}
|
||
|
|
||
|
__inline void
|
||
|
ReleaseLLMA(LinkLayerMulticastAddress *LLMA)
|
||
|
{
|
||
|
LLMA->RefCntAndFlags -= (LLMA_FLAG_REGISTERED << 1);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsLLMAReferenced(LinkLayerMulticastAddress *LLMA)
|
||
|
{
|
||
|
return LLMA->RefCntAndFlags > LLMA_FLAG_REGISTERED;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Information about IPv6 interfaces. There can be multiple NTEs for each
|
||
|
// interface, but there is exactly one interface per NTE.
|
||
|
//
|
||
|
struct Interface { // a.k.a. IF
|
||
|
NetTableEntryOrInterface; // For NTEorIF. Points to self.
|
||
|
|
||
|
Interface *Next; // Next interface on chain.
|
||
|
|
||
|
long RefCnt; // Reference count - interlocked.
|
||
|
|
||
|
//
|
||
|
// Interface to the link layer. The functions all take
|
||
|
// the LinkContext as their first argument. See comments
|
||
|
// in llip6if.h.
|
||
|
//
|
||
|
void *LinkContext; // Link layer context.
|
||
|
void (*CreateToken)(void *Context, IPv6Addr *Address);
|
||
|
const void *(*ReadLLOpt)(void *Context, const uchar *OptionData);
|
||
|
void (*WriteLLOpt)(void *Context, uchar *OptionData,
|
||
|
const void *LinkAddress);
|
||
|
ushort (*ConvertAddr)(void *Context,
|
||
|
const IPv6Addr *Address, void *LinkAddress);
|
||
|
NTSTATUS (*SetRouterLLAddress)(void *Context, const void *TokenLinkAddress,
|
||
|
const void *RouterLinkAddress);
|
||
|
void (*Transmit)(void *Context, PNDIS_PACKET Packet,
|
||
|
uint Offset, const void *LinkAddress);
|
||
|
NDIS_STATUS (*SetMCastAddrList)(void *Context, const void *LinkAddresses,
|
||
|
uint NumKeep, uint NumAdd, uint NumDel);
|
||
|
void (*Close)(void *Context);
|
||
|
void (*Cleanup)(void *Context);
|
||
|
|
||
|
uint Index; // Node unique index of this I/F.
|
||
|
uint Type; // Values in ntddip6.h.
|
||
|
uint Flags; // Changes require lock, reads don't.
|
||
|
uint DefaultPreference; // Read-only.
|
||
|
uint Preference; // For routing.
|
||
|
|
||
|
//
|
||
|
// ZoneIndices[0] (ADE_SMALLEST_SCOPE) and
|
||
|
// ZoneIndices[1] (ADE_INTERFACE_LOCAL) must be Index.
|
||
|
// ZoneIndices[14] (ADE_GLOBAL) and
|
||
|
// ZoneIndices[15] (ADE_LARGEST_SCOPE) must be one.
|
||
|
// ZoneIndices must respect zone containment:
|
||
|
// If two interfaces have the same value for ZoneIndices[N],
|
||
|
// then they must have the same value for ZoneIndices[N+1].
|
||
|
// To ensure consistency, modifying ZoneIndices requires
|
||
|
// the global ZoneUpdateLock.
|
||
|
//
|
||
|
uint ZoneIndices[ADE_NUM_SCOPES]; // Changes require lock, reads don't.
|
||
|
|
||
|
AddressEntry *ADE; // List of ADEs on this I/F.
|
||
|
NetTableEntry *LinkLocalNTE; // Primary link-local address.
|
||
|
|
||
|
KSPIN_LOCK LockNC; // Neighbor cache lock.
|
||
|
NeighborCacheEntry *FirstNCE; // List of active neighbors on I/F.
|
||
|
NeighborCacheEntry *LastNCE; // Last NCE in the list.
|
||
|
uint NCENumUnused; // Number of unused NCEs - interlocked.
|
||
|
|
||
|
uint TrueLinkMTU; // Read-only, true maximum MTU.
|
||
|
uint DefaultLinkMTU; // Read-only, default for LinkMTU.
|
||
|
uint LinkMTU; // Manually configured or received from RAs.
|
||
|
|
||
|
uint CurHopLimit; // Default Hop Limit for unicast.
|
||
|
uint BaseReachableTime; // Base for random ReachableTime (in ms).
|
||
|
uint ReachableTime; // Reachable timeout (in IPv6Timer ticks).
|
||
|
uint RetransTimer; // NS timeout (in IPv6Timer ticks).
|
||
|
uint DefaultDupAddrDetectTransmits; // Read-only.
|
||
|
uint DupAddrDetectTransmits; // Number of solicits during DAD.
|
||
|
uint DupAddrDetects; // Number of consecutive DAD detects.
|
||
|
|
||
|
uint AnonStateAge; // Age of the anonymous state.
|
||
|
IPv6Addr AnonState; // State for generating anonymous addresses.
|
||
|
|
||
|
uint RSCount; // Number of Router Solicits sent.
|
||
|
uint RSTimer; // RS timeout (in IPv6Timer ticks).
|
||
|
uint RACount; // Number of "fast" RAs left to send.
|
||
|
uint RATimer; // RA timeout (in IPv6Timer ticks).
|
||
|
uint RALast; // Time of last RA (in IPv6Timer ticks).
|
||
|
|
||
|
uint LinkAddressLength; // Length of I/F link-level address.
|
||
|
uchar *LinkAddress; // Pointer to link-level address.
|
||
|
uint LinkHeaderSize; // Length of link-level header.
|
||
|
|
||
|
KSPIN_LOCK Lock; // Main interface lock.
|
||
|
KMUTEX WorkerLock; // Serializes worker thread operations.
|
||
|
|
||
|
LinkLayerMulticastAddress *MCastAddresses; // Current addresses.
|
||
|
uint MCastAddrNum; // Number of link-layer mcast addresses.
|
||
|
|
||
|
uint TcpInitialRTT; // InitialRTT that TCP connections should use
|
||
|
// on this interface.
|
||
|
|
||
|
HANDLE TdiRegistrationHandle; // Opaque token for TDI De/notification.
|
||
|
GUID Guid;
|
||
|
NDIS_STRING DeviceName; // IPV6_EXPORT_STRING_PREFIX + string Guid.
|
||
|
};
|
||
|
|
||
|
__inline NeighborCacheEntry *
|
||
|
SentinelNCE(Interface *IF)
|
||
|
{
|
||
|
return (NeighborCacheEntry *) &IF->FirstNCE;
|
||
|
}
|
||
|
|
||
|
__inline uint
|
||
|
SizeofLinkLayerMulticastAddress(Interface *IF)
|
||
|
{
|
||
|
uint RawSize = (sizeof(struct LinkLayerMulticastAddress) +
|
||
|
IF->LinkAddressLength);
|
||
|
uint Align = __builtin_alignof(struct LinkLayerMulticastAddress) - 1;
|
||
|
|
||
|
return (RawSize + Align) &~ Align;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// These values should agree with definitions also
|
||
|
// found in llip6if.h and ntddip6.h.
|
||
|
//
|
||
|
#define IF_TYPE_LOOPBACK 0
|
||
|
#define IF_TYPE_ETHERNET 1
|
||
|
#define IF_TYPE_FDDI 2
|
||
|
#define IF_TYPE_TUNNEL_AUTO 3
|
||
|
#define IF_TYPE_TUNNEL_6OVER4 4
|
||
|
#define IF_TYPE_TUNNEL_V6V4 5
|
||
|
#define IF_TYPE_TUNNEL_6TO4 6
|
||
|
#define IF_TYPE_TUNNEL_TEREDO 7
|
||
|
|
||
|
__inline int
|
||
|
IsIPv4TunnelIF(Interface *IF)
|
||
|
{
|
||
|
return ((IF_TYPE_TUNNEL_AUTO <= IF->Type) &&
|
||
|
(IF->Type <= IF_TYPE_TUNNEL_6TO4));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// These values should agree with definitions also
|
||
|
// found in llip6if.h and ntddip6.h.
|
||
|
//
|
||
|
#define IF_FLAG_PSEUDO 0x00000001
|
||
|
#define IF_FLAG_P2P 0x00000002
|
||
|
#define IF_FLAG_NEIGHBOR_DISCOVERS 0x00000004
|
||
|
#define IF_FLAG_FORWARDS 0x00000008
|
||
|
#define IF_FLAG_ADVERTISES 0x00000010
|
||
|
#define IF_FLAG_MULTICAST 0x00000020
|
||
|
#define IF_FLAG_ROUTER_DISCOVERS 0x00000040
|
||
|
#define IF_FLAG_PERIODICMLD 0x00000080
|
||
|
#define IF_FLAG_MEDIA_DISCONNECTED 0x00001000
|
||
|
|
||
|
#define IF_FLAGS_DISCOVERS \
|
||
|
(IF_FLAG_NEIGHBOR_DISCOVERS|IF_FLAG_ROUTER_DISCOVERS)
|
||
|
|
||
|
#define IF_FLAGS_BINDINFO 0x0000ffff
|
||
|
|
||
|
#define IF_FLAG_DISABLED 0x00010000
|
||
|
#define IF_FLAG_MCAST_SYNC 0x00020000
|
||
|
#define IF_FLAG_OTHER_STATEFUL_CONFIG 0x00040000
|
||
|
|
||
|
//
|
||
|
// The DISCONNECTED and RECONNECTED flags should not both be set.
|
||
|
// RECONNECTED indicates that the host interface was recently reconnected;
|
||
|
// it is cleared upon receiving a Router Advertisement.
|
||
|
//
|
||
|
#define IF_FLAG_MEDIA_RECONNECTED 0x00080000
|
||
|
|
||
|
//
|
||
|
// This function should be used after taking the interface lock
|
||
|
// or interface list lock, to check if the interface is disabled.
|
||
|
//
|
||
|
__inline int
|
||
|
IsDisabledIF(Interface *IF)
|
||
|
{
|
||
|
return IF->Flags & IF_FLAG_DISABLED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Called with the interface lock held.
|
||
|
//
|
||
|
__inline int
|
||
|
IsMCastSyncNeeded(Interface *IF)
|
||
|
{
|
||
|
return IF->Flags & IF_FLAG_MCAST_SYNC;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Active interfaces hold a reference to themselves.
|
||
|
// NTEs hold a reference to their interface.
|
||
|
// NCEs that have a non-zero ref count hold a reference.
|
||
|
// MAEs and AAEs do not hold a reference for their NTE or IF.
|
||
|
//
|
||
|
|
||
|
__inline void
|
||
|
AddRefIF(Interface *IF)
|
||
|
{
|
||
|
//
|
||
|
// A stronger assertion would be !IsDisabledIF(IF),
|
||
|
// which is mostly true, but that assertion would
|
||
|
// imply that AddRefIF could be used only while
|
||
|
// holding the interface list lock or the interface lock,
|
||
|
// which is an undesirable restriction.
|
||
|
//
|
||
|
ASSERT(IF->RefCnt > 0);
|
||
|
|
||
|
InterlockedIncrement(&IF->RefCnt);
|
||
|
}
|
||
|
|
||
|
__inline void
|
||
|
ReleaseIF(Interface *IF)
|
||
|
{
|
||
|
InterlockedDecrement(&IF->RefCnt);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// We have a periodic timer (IPv6Timer) that causes our IPv6Timeout
|
||
|
// routine to be called IPv6_TICKS_SECOND times per second. Most of the
|
||
|
// timers and timeouts in this implementation are driven off this routine.
|
||
|
//
|
||
|
// There is a trade-off here between timer granularity/resolution
|
||
|
// and overhead. The resolution should be subsecond because
|
||
|
// RETRANS_TIMER is only one second.
|
||
|
//
|
||
|
extern uint IPv6TickCount;
|
||
|
|
||
|
#define IPv6_TICKS_SECOND 2 // Two ticks per second.
|
||
|
|
||
|
#define IPv6_TIMEOUT (1000 / IPv6_TICKS_SECOND) // In milliseconds.
|
||
|
|
||
|
#define IPv6TimerTicks(seconds) ((seconds) * IPv6_TICKS_SECOND)
|
||
|
|
||
|
//
|
||
|
// ConvertSecondsToTicks and ConvertTicksToSeconds
|
||
|
// both leave the value INFINITE_LIFETIME unchanged.
|
||
|
//
|
||
|
|
||
|
extern uint
|
||
|
ConvertSecondsToTicks(uint Seconds);
|
||
|
|
||
|
extern uint
|
||
|
ConvertTicksToSeconds(uint Ticks);
|
||
|
|
||
|
//
|
||
|
// ConvertMillisToTicks and ConvertTicksToMillis
|
||
|
// do not have an infinite value.
|
||
|
//
|
||
|
|
||
|
extern uint
|
||
|
ConvertMillisToTicks(uint Millis);
|
||
|
|
||
|
__inline uint
|
||
|
ConvertTicksToMillis(uint Ticks)
|
||
|
{
|
||
|
return Ticks * IPv6_TIMEOUT;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// REVIEW: Hack to handle those few remaining places where we still need
|
||
|
// REVIEW: to allocate space for a link-level header before we know the
|
||
|
// REVIEW: outgoing inteface (and thus know how big said header will be).
|
||
|
// REVIEW: When these places have all been fixed, we won't need this.
|
||
|
//
|
||
|
#define MAX_LINK_HEADER_SIZE 32
|
||
|
|
||
|
|
||
|
//
|
||
|
// Various constants from the IPv6 RFCs...
|
||
|
//
|
||
|
// REVIEW: Some of these should be per link-layer type.
|
||
|
// REVIEW: Put them in the Interface structure?
|
||
|
//
|
||
|
#define MAX_INITIAL_RTR_ADVERT_INTERVAL IPv6TimerTicks(16)
|
||
|
#define MAX_INITIAL_RTR_ADVERTISEMENTS 3 // Produces 4 quick RAs.
|
||
|
#define MAX_FINAL_RTR_ADVERTISEMENTS 3
|
||
|
#define MIN_DELAY_BETWEEN_RAS IPv6TimerTicks(3)
|
||
|
#define MAX_RA_DELAY_TIME 1 // 0.5 seconds
|
||
|
#define MaxRtrAdvInterval IPv6TimerTicks(600)
|
||
|
#define MinRtrAdvInterval IPv6TimerTicks(200)
|
||
|
// MAX_RTR_SOLICITATION_DELAY IPv6_TIMEOUT is used instead.
|
||
|
#define RTR_SOLICITATION_INTERVAL IPv6TimerTicks(4) // 4 seconds.
|
||
|
#define SLOW_RTR_SOLICITATION_INTERVAL IPv6TimerTicks(15 * 60) // 15 minutes.
|
||
|
#define MAX_RTR_SOLICITATIONS 3
|
||
|
#define MAX_MULTICAST_SOLICIT 3 // Total transmissions before giving up.
|
||
|
#define MAX_UNICAST_SOLICIT 3 // Total transmissions before giving up.
|
||
|
#define MAX_UNREACH_SOLICIT 1 // Total transmissions before giving up.
|
||
|
#define UNREACH_SOLICIT_INTERVAL IPv6TimerTicks(60) // 1 minute.
|
||
|
#define MAX_ANYCAST_DELAY_TIME 1 // seconds.
|
||
|
#define REACHABLE_TIME (30 * 1000) // 30 seconds in milliseconds.
|
||
|
#define MAX_REACHABLE_TIME (60 * 60 * 1000) // 1 hour in milliseconds.
|
||
|
#define ICMP_MIN_ERROR_INTERVAL 1 // Ticks - a half second.
|
||
|
#define RETRANS_TIMER IPv6TimerTicks(1) // 1 second.
|
||
|
#define DELAY_FIRST_PROBE_TIME IPv6TimerTicks(5) // 5 seconds.
|
||
|
#define MIN_RANDOM_FACTOR 50 // Percentage of base value.
|
||
|
#define MAX_RANDOM_FACTOR 150 // Percentage of base value.
|
||
|
#define PREFIX_LIFETIME_SAFETY IPv6TimerTicks(2 * 60 * 60) // 2 hours.
|
||
|
#define RECALC_REACHABLE_INTERVAL IPv6TimerTicks(3 * 60 * 60) // 3 hours.
|
||
|
#define PATH_MTU_RETRY_TIME IPv6TimerTicks(10 * 60) // 10 minutes.
|
||
|
#define MLD_UNSOLICITED_REPORT_INTERVAL IPv6TimerTicks(10) // 10 seconds.
|
||
|
#define MLD_QUERY_INTERVAL IPv6TimerTicks(125) // 125 seconds.
|
||
|
#define MLD_NUM_INITIAL_REPORTS 2
|
||
|
#define MAX_ANON_DAD_ATTEMPTS 5
|
||
|
#define MAX_ANON_PREFERRED_LIFETIME (24 * 60 * 60) // 1 day.
|
||
|
#define MAX_ANON_VALID_LIFETIME (7 * MAX_ANON_PREFERRED_LIFETIME)
|
||
|
#define ANON_REGENERATE_TIME 5 // 5 seconds.
|
||
|
#define MAX_ANON_RANDOM_TIME (10 * 60) // 10 minutes.
|
||
|
#define DEFAULT_CUR_HOP_LIMIT 0x80
|
||
|
|
||
|
//
|
||
|
// Various implementation constants.
|
||
|
//
|
||
|
#define NEIGHBOR_CACHE_LIMIT 8
|
||
|
#define ROUTE_CACHE_LIMIT 32
|
||
|
#define BINDING_CACHE_LIMIT 32
|
||
|
#define SMALL_POOL 10000
|
||
|
#define MEDIUM_POOL 30000
|
||
|
#define LARGE_POOL 60000
|
||
|
|
||
|
//
|
||
|
// Under NT, we use the assembly language version of the common core checksum
|
||
|
// routine instead of the C language version.
|
||
|
//
|
||
|
ULONG
|
||
|
tcpxsum(IN ULONG Checksum, IN PUCHAR Source, IN ULONG Length);
|
||
|
|
||
|
#define Cksum(Buffer, Length) ((ushort)tcpxsum(0, (PUCHAR)(Buffer), (Length)))
|
||
|
|
||
|
|
||
|
//
|
||
|
// Protocol Receive Procedures ("Next Header" handlers) have this prototype.
|
||
|
//
|
||
|
typedef uchar ProtoRecvProc(IPv6Packet *Packet);
|
||
|
|
||
|
typedef struct StatusArg {
|
||
|
IP_STATUS Status;
|
||
|
unsigned long Arg;
|
||
|
IPv6Header UNALIGNED *IP;
|
||
|
} StatusArg;
|
||
|
|
||
|
//
|
||
|
// Protocol Control Receive Procedures have this prototype.
|
||
|
// These receive handlers are called for ICMP errors.
|
||
|
//
|
||
|
typedef uchar ProtoControlRecvProc(IPv6Packet *Packet, StatusArg *Arg);
|
||
|
|
||
|
typedef struct ProtocolSwitch {
|
||
|
ProtoRecvProc *DataReceive;
|
||
|
ProtoControlRecvProc *ControlReceive;
|
||
|
} ProtocolSwitch;
|
||
|
|
||
|
extern ProtoRecvProc IPv6HeaderReceive;
|
||
|
extern ProtoRecvProc ICMPv6Receive;
|
||
|
extern ProtoRecvProc FragmentReceive;
|
||
|
extern ProtoRecvProc DestinationOptionsReceive;
|
||
|
extern ProtoRecvProc RoutingReceive;
|
||
|
extern ProtoRecvProc EncapsulatingSecurityPayloadReceive;
|
||
|
extern ProtoRecvProc AuthenticationHeaderReceive;
|
||
|
|
||
|
extern ProtoControlRecvProc ICMPv6ControlReceive;
|
||
|
extern ProtoControlRecvProc ExtHdrControlReceive;
|
||
|
|
||
|
//
|
||
|
// Hop-by-Hop Options use a special receive handler.
|
||
|
// This is because they are processed even when a
|
||
|
// a packet is being forwarded instead of received.
|
||
|
// Note that they are only processed when immediately
|
||
|
// following an IPv6 header.
|
||
|
//
|
||
|
extern int
|
||
|
HopByHopOptionsReceive(IPv6Packet *Packet);
|
||
|
|
||
|
|
||
|
//
|
||
|
// The Raw Receive handler supports external protocol handlers.
|
||
|
//
|
||
|
extern int RawReceive(IPv6Packet *Packet, uchar Protocol);
|
||
|
|
||
|
|
||
|
//
|
||
|
// The actual definition of a reassembly structure
|
||
|
// can be found in fragment.h.
|
||
|
//
|
||
|
typedef struct Reassembly Reassembly;
|
||
|
|
||
|
#define USE_ANON_NO 0 // Don't use anonymous addresses.
|
||
|
#define USE_ANON_YES 1 // Use them.
|
||
|
#define USE_ANON_ALWAYS 2 // Always generating random numbers.
|
||
|
#define USE_ANON_COUNTER 3 // Use them with per-interface counter.
|
||
|
|
||
|
//
|
||
|
// Prototypes for global variables.
|
||
|
//
|
||
|
extern uint DefaultCurHopLimit;
|
||
|
extern uint MaxAnonDADAttempts;
|
||
|
extern uint MaxAnonPreferredLifetime; // Ticks.
|
||
|
extern uint MaxAnonValidLifetime; // Ticks.
|
||
|
extern uint AnonRegenerateTime; // Ticks.
|
||
|
extern uint UseAnonymousAddresses; // See values above.
|
||
|
extern uint MaxAnonRandomTime; // Ticks.
|
||
|
extern uint AnonRandomTime; // Ticks.
|
||
|
extern ProtocolSwitch ProtocolSwitchTable[];
|
||
|
extern KSPIN_LOCK NetTableListLock;
|
||
|
extern NetTableEntry *NetTableList; // Pointer to the net table.
|
||
|
extern KSPIN_LOCK IFListLock;
|
||
|
extern Interface *IFList; // List of all interfaces on the system.
|
||
|
extern KSPIN_LOCK ZoneUpdateLock;
|
||
|
extern struct EchoControl *ICMPv6OutstandingEchos;
|
||
|
extern LIST_ENTRY PendingEchoList; // def needed for initialization.
|
||
|
extern Interface *LoopInterface;
|
||
|
extern IPv6Addr UnspecifiedAddr;
|
||
|
extern IPv6Addr LoopbackAddr;
|
||
|
extern IPv6Addr AllNodesOnNodeAddr;
|
||
|
extern IPv6Addr AllNodesOnLinkAddr;
|
||
|
extern IPv6Addr AllRoutersOnLinkAddr;
|
||
|
extern IPv6Addr LinkLocalPrefix;
|
||
|
extern IPv6Addr SiteLocalPrefix;
|
||
|
extern IPv6Addr SixToFourPrefix;
|
||
|
extern IPv6Addr V4MappedPrefix;
|
||
|
extern PDEVICE_OBJECT IPDeviceObject;
|
||
|
extern HANDLE IPv6ProviderHandle;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Some handy functions for working with IPv6 addresses.
|
||
|
//
|
||
|
|
||
|
__inline IPv6Addr *
|
||
|
AlignAddr(IPv6Addr UNALIGNED *Addr)
|
||
|
{
|
||
|
//
|
||
|
// IPv6 addresses only have char & short members,
|
||
|
// so they need 2-byte alignment.
|
||
|
// In practice addresses in headers are always
|
||
|
// appropriately aligned.
|
||
|
//
|
||
|
ASSERT(((UINT_PTR)Addr % __builtin_alignof(IPv6Addr)) == 0);
|
||
|
return (IPv6Addr *) Addr;
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsUnspecified(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return IP6_ADDR_EQUAL(Addr, &UnspecifiedAddr);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsLoopback(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return IP6_ADDR_EQUAL(Addr, &LoopbackAddr);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsGlobal(const IPv6Addr *Addr)
|
||
|
{
|
||
|
//
|
||
|
// Check the format prefix and exclude addresses
|
||
|
// whose high 4 bits are all zero or all one.
|
||
|
// This is a cheap way of excluding v4-compatible,
|
||
|
// v4-mapped, loopback, multicast, link-local, site-local.
|
||
|
//
|
||
|
uint High = (Addr->s6_bytes[0] & 0xf0);
|
||
|
return (High != 0) && (High != 0xf0);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsMulticast(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return Addr->s6_bytes[0] == 0xff;
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsLinkLocal(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return ((Addr->s6_bytes[0] == 0xfe) &&
|
||
|
((Addr->s6_bytes[1] & 0xc0) == 0x80));
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsLinkLocalMulticast(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return IsMulticast(Addr) && ((Addr->s6_bytes[1] & 0xf) == ADE_LINK_LOCAL);
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsInterfaceLocalMulticast(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return (IsMulticast(Addr) &&
|
||
|
((Addr->s6_bytes[1] & 0xf) == ADE_INTERFACE_LOCAL));
|
||
|
}
|
||
|
|
||
|
extern int
|
||
|
IsSolicitedNodeMulticast(const IPv6Addr *Addr);
|
||
|
|
||
|
__inline int
|
||
|
IsSiteLocal(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return ((Addr->s6_bytes[0] == 0xfe) &&
|
||
|
((Addr->s6_bytes[1] & 0xc0) == 0xc0));
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsSiteLocalMulticast(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return IsMulticast(Addr) && ((Addr->s6_bytes[1] & 0xf) == ADE_SITE_LOCAL);
|
||
|
}
|
||
|
|
||
|
extern int
|
||
|
IP6_ADDR_LTEQ(const IPv6Addr *A, const IPv6Addr *B);
|
||
|
|
||
|
extern int
|
||
|
IsEUI64Address(const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
IsKnownAnycast(const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
IsSubnetRouterAnycast(const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
IsSubnetReservedAnycast(const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
IsInvalidSourceAddress(const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
IsNotManualAddress(const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
IsV4Compatible(const IPv6Addr *Addr);
|
||
|
|
||
|
extern void
|
||
|
CreateV4Compatible(IPv6Addr *Addr, IPAddr V4Addr);
|
||
|
|
||
|
extern int
|
||
|
IsV4Mapped(const IPv6Addr *Addr);
|
||
|
|
||
|
extern void
|
||
|
CreateV4Mapped(IPv6Addr *Addr, IPAddr V4Addr);
|
||
|
|
||
|
__inline IPAddr
|
||
|
ExtractV4Address(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return * (IPAddr UNALIGNED *) &Addr->s6_bytes[12];
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
Is6to4(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return Addr->s6_words[0] == 0x0220;
|
||
|
}
|
||
|
|
||
|
__inline IPAddr
|
||
|
Extract6to4Address(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return * (IPAddr UNALIGNED *) &Addr->s6_bytes[2];
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsISATAP(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return (((Addr->s6_words[4] & 0xFFFD) == 0x0000) &&
|
||
|
(Addr->s6_words[5] == 0xfe5e));
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsV4Multicast(IPAddr Addr)
|
||
|
{
|
||
|
return (Addr & 0x000000f0) == 0x000000e0;
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsV4Broadcast(IPAddr Addr)
|
||
|
{
|
||
|
return Addr == 0xffffffff;
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsV4Loopback(IPAddr Addr)
|
||
|
{
|
||
|
return (Addr & 0x000000ff) == 0x0000007f;
|
||
|
}
|
||
|
|
||
|
__inline int
|
||
|
IsV4Unspecified(IPAddr Addr)
|
||
|
{
|
||
|
return (Addr & 0x000000ff) == 0x00000000;
|
||
|
}
|
||
|
|
||
|
__inline ushort
|
||
|
MulticastAddressScope(const IPv6Addr *Addr)
|
||
|
{
|
||
|
return Addr->s6_bytes[1] & 0xf;
|
||
|
}
|
||
|
|
||
|
extern ushort
|
||
|
UnicastAddressScope(const IPv6Addr *Addr);
|
||
|
|
||
|
extern ushort
|
||
|
AddressScope(const IPv6Addr *Addr);
|
||
|
|
||
|
extern ushort
|
||
|
V4AddressScope(IPAddr Addr);
|
||
|
|
||
|
extern uint
|
||
|
DetermineScopeId(const IPv6Addr *Addr, Interface *IF);
|
||
|
|
||
|
extern void
|
||
|
CreateSolicitedNodeMulticastAddress(const IPv6Addr *Addr, IPv6Addr *MCastAddr);
|
||
|
|
||
|
extern int
|
||
|
HasPrefix(const IPv6Addr *Addr, const IPv6Addr *Prefix, uint PrefixLength);
|
||
|
|
||
|
extern void
|
||
|
CopyPrefix(IPv6Addr *Addr, const IPv6Addr *Prefix, uint PrefixLength);
|
||
|
|
||
|
extern uint
|
||
|
CommonPrefixLength(const IPv6Addr *Addr, const IPv6Addr *Addr2);
|
||
|
|
||
|
extern int
|
||
|
IntersectPrefix(const IPv6Addr *Prefix1, uint Prefix1Length,
|
||
|
const IPv6Addr *Prefix2, uint Prefix2Length);
|
||
|
|
||
|
//
|
||
|
// Function prototypes.
|
||
|
//
|
||
|
|
||
|
extern void
|
||
|
SeedRandom(const uchar *Seed, uint Length);
|
||
|
|
||
|
extern uint
|
||
|
Random(void);
|
||
|
|
||
|
extern uint
|
||
|
RandomNumber(uint Min, uint Max);
|
||
|
|
||
|
#define INET6_ADDRSTRLEN 46 // Max size of numeric form of IPv6 address
|
||
|
#define INET_ADDRSTRLEN 16 // Max size of numeric form of IPv4 address
|
||
|
|
||
|
__inline int
|
||
|
ParseV6Address(const WCHAR *Sz, const WCHAR **Terminator, IPv6Addr *Addr)
|
||
|
{
|
||
|
return NT_SUCCESS(RtlIpv6StringToAddressW(Sz, Terminator, Addr));
|
||
|
}
|
||
|
|
||
|
__inline void
|
||
|
FormatV6AddressWorker(char *Sz, const IPv6Addr *Addr)
|
||
|
{
|
||
|
(void) RtlIpv6AddressToStringA(Addr, Sz);
|
||
|
}
|
||
|
|
||
|
extern char *
|
||
|
FormatV6Address(const IPv6Addr *Addr);
|
||
|
|
||
|
__inline int
|
||
|
ParseV4Address(const WCHAR *Sz, const WCHAR **Terminator, IPAddr *Addr)
|
||
|
{
|
||
|
return NT_SUCCESS(RtlIpv4StringToAddressW(Sz, TRUE, Terminator, (struct in_addr *)Addr));
|
||
|
}
|
||
|
|
||
|
__inline void
|
||
|
FormatV4AddressWorker(char *Sz, IPAddr Addr)
|
||
|
{
|
||
|
(void) RtlIpv4AddressToStringA((struct in_addr *)&Addr, Sz);
|
||
|
}
|
||
|
|
||
|
extern char *
|
||
|
FormatV4Address(IPAddr Addr);
|
||
|
|
||
|
extern ushort
|
||
|
ChecksumPacket(PNDIS_PACKET Packet, uint Offset, uchar *Data, uint Length,
|
||
|
const IPv6Addr *Source, const IPv6Addr *Dest, uchar NextHeader);
|
||
|
|
||
|
extern void
|
||
|
LoopQueueTransmit(PNDIS_PACKET Packet);
|
||
|
|
||
|
extern NDIS_STATUS
|
||
|
IPv6SendLater(LARGE_INTEGER Time,
|
||
|
Interface *IF, PNDIS_PACKET Packet,
|
||
|
uint Offset, const void *LinkAddress);
|
||
|
|
||
|
extern void
|
||
|
IPv6SendLL(Interface *IF, PNDIS_PACKET Packet,
|
||
|
uint Offset, const void *LinkAddress);
|
||
|
|
||
|
extern void
|
||
|
IPv6SendND(PNDIS_PACKET Packet, uint Offset, NeighborCacheEntry *NCE,
|
||
|
const IPv6Addr *DiscoveryAddress);
|
||
|
|
||
|
#define SEND_FLAG_BYPASS_BINDING_CACHE 0x00000001
|
||
|
|
||
|
extern void
|
||
|
IPv6Send(PNDIS_PACKET Packet, uint Offset, IPv6Header UNALIGNED *IP,
|
||
|
uint PayloadLength, RouteCacheEntry *RCE, uint Flags,
|
||
|
ushort TransportProtocol, ushort SourcePort, ushort DestPort);
|
||
|
|
||
|
extern void
|
||
|
IPv6Forward(NetTableEntryOrInterface *RecvNTEorIF,
|
||
|
PNDIS_PACKET Packet, uint Offset, IPv6Header UNALIGNED *IP,
|
||
|
uint PayloadLength, int Redirect, IPSecProc *IPSecToDo,
|
||
|
RouteCacheEntry *RCE);
|
||
|
|
||
|
extern void
|
||
|
IPv6SendAbort(NetTableEntryOrInterface *NTEorIF,
|
||
|
PNDIS_PACKET Packet, uint Offset,
|
||
|
uchar ICMPType, uchar ICMPCode, ulong ErrorParameter,
|
||
|
int MulticastOverride);
|
||
|
|
||
|
extern void
|
||
|
ICMPv6EchoTimeout(void);
|
||
|
|
||
|
extern void
|
||
|
IPULUnloadNotify(void);
|
||
|
|
||
|
extern Interface *
|
||
|
FindInterfaceFromIndex(uint Index);
|
||
|
|
||
|
extern Interface *
|
||
|
FindInterfaceFromGuid(const GUID *Guid);
|
||
|
|
||
|
extern Interface *
|
||
|
FindNextInterface(Interface *IF);
|
||
|
|
||
|
extern Interface *
|
||
|
FindInterfaceFromZone(Interface *OrigIF, uint Scope, uint Index);
|
||
|
|
||
|
extern uint
|
||
|
FindNewZoneIndex(uint Scope);
|
||
|
|
||
|
extern void
|
||
|
InitZoneIndices(Interface *IF);
|
||
|
|
||
|
extern IP_STATUS
|
||
|
FindDefaultInterfaceForZone(uint Scope, uint ScopeId,
|
||
|
Interface **ScopeIF, ushort *ReturnConstrained);
|
||
|
|
||
|
extern void
|
||
|
IPv6Timeout(PKDPC MyDpcObject, void *Context, void *Unused1, void *Unused2);
|
||
|
|
||
|
extern int
|
||
|
MapNdisBuffers(NDIS_BUFFER *Buffer);
|
||
|
|
||
|
extern uchar *
|
||
|
GetDataFromNdis(PNDIS_BUFFER SrcBuffer, uint SrcOffset, uint Length,
|
||
|
uchar *DataBuffer);
|
||
|
|
||
|
extern IPv6Header UNALIGNED *
|
||
|
GetIPv6Header(PNDIS_PACKET Packet, uint Offset, IPv6Header *HdrBuffer);
|
||
|
|
||
|
extern int
|
||
|
CheckLinkLayerMulticastAddress(Interface *IF, const void *LinkAddress);
|
||
|
|
||
|
extern void
|
||
|
AddNTEToInterface(Interface *IF, NetTableEntry *NTE);
|
||
|
|
||
|
extern uint
|
||
|
InterfaceIndex(void);
|
||
|
|
||
|
extern void
|
||
|
AddInterface(Interface *IF);
|
||
|
|
||
|
extern void
|
||
|
UpdateLinkMTU(Interface *IF, uint MTU);
|
||
|
|
||
|
extern NetTableEntry *
|
||
|
CreateNTE(Interface *IF, const IPv6Addr *Address,
|
||
|
uint AddrConf,
|
||
|
uint ValidLifetime, uint PreferredLifetime);
|
||
|
|
||
|
extern MulticastAddressEntry *
|
||
|
FindOrCreateMAE(Interface *IF, const IPv6Addr *Addr, NetTableEntry *NTE);
|
||
|
|
||
|
extern MulticastAddressEntry *
|
||
|
FindAndReleaseMAE(Interface *IF, const IPv6Addr *Addr);
|
||
|
|
||
|
extern int
|
||
|
FindOrCreateAAE(Interface *IF, const IPv6Addr *Addr,
|
||
|
NetTableEntryOrInterface *NTEorIF);
|
||
|
|
||
|
extern int
|
||
|
FindAndDeleteAAE(Interface *IF, const IPv6Addr *Addr);
|
||
|
|
||
|
extern void
|
||
|
DestroyADEs(Interface *IF, NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
DestroyNTE(Interface *IF, NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
EnlivenNTE(Interface *IF, NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
DestroyIF(Interface *IF);
|
||
|
|
||
|
extern AddressEntry **
|
||
|
FindADE(Interface *IF, const IPv6Addr *Addr);
|
||
|
|
||
|
extern NetTableEntryOrInterface *
|
||
|
FindAddressOnInterface(Interface *IF, const IPv6Addr *Addr, ushort *AddrType);
|
||
|
|
||
|
extern NetTableEntry *
|
||
|
GetLinkLocalNTE(Interface *IF);
|
||
|
|
||
|
extern int
|
||
|
GetLinkLocalAddress(Interface *IF, IPv6Addr *Addr);
|
||
|
|
||
|
extern void
|
||
|
DeferRegisterNetAddress(NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
DeferSynchronizeMulticastAddresses(Interface *IF);
|
||
|
|
||
|
extern int
|
||
|
IPInit(void);
|
||
|
|
||
|
extern int Unloading;
|
||
|
|
||
|
extern void
|
||
|
IPUnload(void);
|
||
|
|
||
|
extern void
|
||
|
AddrConfUpdate(Interface *IF, const IPv6Addr *Prefix,
|
||
|
uint ValidLifetime, uint PreferredLifetime,
|
||
|
int Authenticated, NetTableEntry **pNTE);
|
||
|
|
||
|
extern int
|
||
|
FindOrCreateNTE(Interface *IF, const IPv6Addr *Addr,
|
||
|
uint AddrConf,
|
||
|
uint ValidLifetime, uint PreferredLifetime);
|
||
|
|
||
|
extern void
|
||
|
AddrConfDuplicate(Interface *IF, NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
AddrConfNotDuplicate(Interface *IF, NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
AddrConfResetAutoConfig(Interface *IF, uint MaxLifetime);
|
||
|
|
||
|
extern void
|
||
|
AddrConfTimeout(NetTableEntry *NTE);
|
||
|
|
||
|
extern void
|
||
|
NetTableTimeout(void);
|
||
|
|
||
|
extern void
|
||
|
NetTableCleanup(void);
|
||
|
|
||
|
extern void
|
||
|
InterfaceTimeout(void);
|
||
|
|
||
|
extern void
|
||
|
InterfaceCleanup(void);
|
||
|
|
||
|
extern void
|
||
|
InterfaceReset(void);
|
||
|
|
||
|
extern NTSTATUS
|
||
|
UpdateInterface(Interface *IF, int Advertises, int Forwards);
|
||
|
|
||
|
extern void
|
||
|
ReconnectInterface(Interface *IF);
|
||
|
|
||
|
extern void
|
||
|
InterfaceResetAutoConfig(Interface *IF);
|
||
|
|
||
|
extern int
|
||
|
LanInit(void);
|
||
|
|
||
|
extern void
|
||
|
LanUnload(void);
|
||
|
|
||
|
extern int
|
||
|
LoopbackInit(void);
|
||
|
|
||
|
extern void
|
||
|
ProtoTabInit(void);
|
||
|
|
||
|
extern void
|
||
|
ICMPv6Init(void);
|
||
|
|
||
|
extern int
|
||
|
IPSecInit(void);
|
||
|
|
||
|
extern void
|
||
|
IPSecUnload(void);
|
||
|
|
||
|
extern int
|
||
|
TunnelInit(void);
|
||
|
|
||
|
extern void
|
||
|
TunnelUnload(void);
|
||
|
|
||
|
extern NTSTATUS
|
||
|
TunnelCreateTunnel(IPAddr SrcAddr, IPAddr DstAddr,
|
||
|
uint Flags, Interface **ReturnIF);
|
||
|
|
||
|
extern int
|
||
|
TunnelGetSourceAddress(IPAddr Dest, IPAddr *Source);
|
||
|
|
||
|
extern ulong
|
||
|
NewFragmentId(void);
|
||
|
|
||
|
extern void
|
||
|
ReassemblyInit(void);
|
||
|
|
||
|
extern void
|
||
|
ReassemblyUnload(void);
|
||
|
|
||
|
extern void
|
||
|
ReassemblyRemove(Interface *IF);
|
||
|
|
||
|
extern void
|
||
|
CreateGUIDFromName(const char *Name, GUID *Guid);
|
||
|
|
||
|
extern void
|
||
|
ConfigureGlobalParameters(void);
|
||
|
|
||
|
extern void
|
||
|
ConfigureInterface(Interface *IF);
|
||
|
|
||
|
extern void
|
||
|
ConfigurePrefixPolicies(void);
|
||
|
|
||
|
extern void
|
||
|
ConfigurePersistentInterfaces(void);
|
||
|
|
||
|
#endif // IPv6DEF_INCLUDED
|