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

📄 mngprfx.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
// mngprfx.c

#include "mngprfx.h"
#include <winsock2.h>
#include <ipexport.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <winreg.h>

#define MAX_DOWNSTREAM_IFS          8
#ifdef DEBUG
// Only change the period for sending unsolicited RAs if running
// debug version of DHCPv6 to faciliate simpler debugging.
#define DEBUG_PREFIX_ADVERT_MIN_MS  4500
#define DEBUG_PREFIX_ADVERT_MAX_MS  5000
#endif

#define MAX_REG_STR                     128
#define DHCPV6_REGKEY_BASE              TEXT("\\COMM\\DHCPv6L")
#define DHCPV6_REGVAL_DOWNSTREAM_IFS    TEXT("DownstreamInterfaces")
#define DHCPV6_REGVAL_ACCEPT_PD         TEXT("AcceptPrefixDelegation")

HANDLE g_hIPv6Stack = INVALID_HANDLE_VALUE;

//
// Zero-out bits past the given PrefixLen.
//
void TrimPrefix(IPv6Addr* pPrefix, UINT PrefixLen) {
    UINT i;

    if (PrefixLen >= 128) return; // Nothing to do

    if (PrefixLen % 8 != 0) {
        UCHAR mask = 0;
        for (i = 1; i <= PrefixLen % 8; i += 1)
            mask |= 1<<(8-i);
        pPrefix->s6_bytes[PrefixLen/8] &= mask;
    }    
    for (i = (PrefixLen + 7) / 8; i < 16; i += 1)
        pPrefix->s6_bytes[i] = 0;
}

//
// Create a network prefix based on InPrefix and SubnetPrefix using method
// suggested in subnetting example provided in RFC 3633, section 1.2.
//
BOOL CreateSubnetPrefix(
    IPv6Addr* pInPrefix, UINT InPrefixLen, USHORT SubnetPrefix,
    IPv6Addr* pOutPrefix, UINT* pOutPrefixLen
) {
    ASSERT(pInPrefix != NULL && pOutPrefix != NULL && pOutPrefixLen != NULL);

    // We could handle spliting longer prefixes, but there is no need to do this.
    // RFC 3633 (section 1.2), suggests subnetting prefixes based on
    // delegated prefix of only 48 bits.
    //
    if (InPrefixLen > 48) return FALSE;

    memcpy(pOutPrefix, pInPrefix, sizeof(IPv6Addr));
    TrimPrefix(pOutPrefix, InPrefixLen);
    *pOutPrefixLen = InPrefixLen + (InPrefixLen % 16 ? 16 - (InPrefixLen % 16) : 0) + 16;
    pOutPrefix->s6_words[*pOutPrefixLen/16 - 1] = ntohs(SubnetPrefix);

    return TRUE;
}

IPv6Addr* GetIpFromSockAddr(SOCKET_ADDRESS* pSockAddr) {
    return &((PSOCKADDR_IN6)(pSockAddr->lpSockaddr))->sin6_addr;
}

//
// Reconfigures given interface for routing.
//
BOOL UpdateInterface(
    UINT IfIdx,
    BOOL fAdvertises,
    BOOL fForwards
) {
    IPV6_INFO_INTERFACE If;
    UINT BytesReturned;  

    IPV6_INIT_INFO_INTERFACE(&If);
    
    If.This.Index = IfIdx;
    If.Advertises = fAdvertises;
    If.Forwards = fForwards;

#if DEBUG
    If.MinRtrAdvInterval = DEBUG_PREFIX_ADVERT_MIN_MS;
    If.MaxRtrAdvInterval = DEBUG_PREFIX_ADVERT_MAX_MS;    
#endif
    // On RETAIL, use defaults (or otherwise configured current values)
    // for prefix advertisement period.

    return DeviceIoControl(g_hIPv6Stack,
                           IOCTL_IPV6_UPDATE_INTERFACE,
                           &If, sizeof If,
                           NULL, 0, &BytesReturned, NULL);
}

//
// Updates route table entry with given setttings.
//
BOOL UpdateRoute(
    UINT IfIdx,
    IPv6Addr* pIfAddr,
    IPv6Addr* pPrefix,
    UINT PrefixLen,
    UINT ValidLifetime,
    UINT PreferredLifetime,
    UINT Preference,
    BOOL bPublish
) {
    IPV6_INFO_ROUTE_TABLE Route;
    UINT BytesReturned;

    ASSERT(pIfAddr != NULL);
    ASSERT(pPrefix != NULL);
    
    Route.SitePrefixLength = 0;
    Route.ValidLifetime = ValidLifetime;
    Route.PreferredLifetime = PreferredLifetime;
    Route.Preference = Preference;
    Route.Type = RTE_TYPE_AUTOCONF;

    Route.This.Neighbor.IF.Index = IfIdx;
    Route.This.Neighbor.Address = *pIfAddr;

    Route.This.Prefix = *pPrefix;
    Route.This.PrefixLength = PrefixLen;

    Route.Publish = bPublish;
    Route.Immortal = FALSE; // Aging route
    
    return DeviceIoControl(g_hIPv6Stack,
                           IOCTL_IPV6_UPDATE_ROUTE_TABLE,
                           &Route, sizeof Route,
                           NULL, 0, &BytesReturned, NULL);
}

//
// Publish existing routes for the given interface (if not already published).
//
BOOL PublishExistingRoutes(
    UINT IfIdx,
    IPv6Addr* pIfAddr,
    IPv6Addr* pPrefix,
    UINT PrefixLen
) {
    IPV6_QUERY_ROUTE_TABLE Query, NextQuery;
    IPV6_INFO_ROUTE_TABLE Route;
    UINT BytesReturned;
    BOOL fRoutePublished = FALSE;

    NextQuery.Neighbor.IF.Index = 0;
    for (;;) {
        Query = NextQuery;

        if (! DeviceIoControl(g_hIPv6Stack,
                              IOCTL_IPV6_QUERY_ROUTE_TABLE,
                              &Query, sizeof Query,
                              &Route, sizeof Route,
                              &BytesReturned, NULL)) {
            return FALSE;
        }

        NextQuery = Route.Next;

        if (Query.Neighbor.IF.Index == IfIdx) {
            Route.This = Query;

            if (Route.Type != RTE_TYPE_SYSTEM && // Ignore loopback.
                IN6_ADDR_EQUAL(&Route.This.Prefix, pPrefix) &&
                Route.This.PrefixLength == PrefixLen) {

                if (Route.Publish) {
                    // Route has been already published; good enough.
                    fRoutePublished = TRUE;
                } else if (pIfAddr == NULL) {
                    fRoutePublished = 
                        UpdateRoute(IfIdx, &Route.This.Neighbor.Address,
                                    pPrefix, PrefixLen,
                                    Route.ValidLifetime, Route.PreferredLifetime,
                                    Route.Preference, TRUE);
                    if (! fRoutePublished) break; // Error!
                    // Address not specified, other routes are possible.
                } else if (IN6_ADDR_EQUAL(&Route.This.Neighbor.Address, pIfAddr)) {
                    fRoutePublished = 
                        UpdateRoute(IfIdx, pIfAddr,
                                    pPrefix, PrefixLen,
                                    Route.ValidLifetime, Route.PreferredLifetime,
                                    Route.Preference, TRUE);
                    // No more than default route with same address is expected
                    // to be on one interface.
                    break;
                }
            }
        }
        
        if (NextQuery.Neighbor.IF.Index == 0)
            break;
    }
    return fRoutePublished;
}

//
// Ungraciously stolen from tcpipv6\tcpip6\inc\ip6def.h
//
__inline int
IsLinkLocal(const IPv6Addr *Addr) {
    return ((Addr->s6_bytes[0] == 0xfe) &&
            ((Addr->s6_bytes[1] & 0xc0) == 0x80));
}

__inline int
IsSiteLocal(const IPv6Addr *Addr) {
    return ((Addr->s6_bytes[0] == 0xfe) &&
            ((Addr->s6_bytes[1] & 0xc0) == 0xc0));
}

//
// Set or refresh interface address, prefix and route settings and begin
// routing on the interface.
//
BOOL SetOrRefreshPrefix(
    PIP_ADAPTER_ADDRESSES pUpIf,   // Upstream interface
    PIP_ADAPTER_ADDRESSES pDownIf, // Downstream interface
    IPv6Addr* pPrefix,      // Prefix to be assigned
    UINT PrefixLen,         //   Length
    UINT ValidLifetime,     //   Valid lifetime; Note: can use INFINITE_LIFETIME
    UINT PreferredLifetime  //   Preferred lifetime; Note: can use INFINITE_LIFETIME
) {
    BOOL fRet = FALSE; // Be pessimistic
    IPv6Addr NullAddr;

    ASSERT(pUpIf != NULL);
    ASSERT(pDownIf != NULL);
    ASSERT(pPrefix != NULL);

    // Setup null addr that will be used to configure default routes, etc.
    memset(&NullAddr, 0, sizeof(NullAddr));

    //
    // Begin forwarding and advertising on downstream interface and
    // forwarding on the upstream interface
    //
    if (! UpdateInterface(pDownIf->Ipv6IfIndex, TRUE, TRUE ) ) goto cleanup;
    if (! UpdateInterface(pUpIf->Ipv6IfIndex, FALSE, TRUE) ) goto cleanup;
    
    //
    // Configure specific route on downstream interface.
    //
    if (! UpdateRoute(pDownIf->Ipv6IfIndex, &NullAddr,
                      pPrefix, PrefixLen,
                      ValidLifetime, PreferredLifetime,
                      ROUTE_PREF_HIGHEST, TRUE) )
        goto cleanup;

    //
    // Notes:
    // - No need for a default route for downstream interface.
    // - No need to assign global address on downstream interface - it
    //   will be assigned automatically when route is created.

    //
    // Find a default route for public interface and set it to published (if it is
    // not published already). Need to publish default route on upstream interface
    // so that router lifetime advertised in RAs is > 0. (This route will not be
    // advertised on public network.)
    //
    fRet = PublishExistingRoutes(pUpIf->Ipv6IfIndex, NULL,
                                 &NullAddr, 0);

cleanup:
    ASSERT(fRet);
    return fRet;
}

//
// Consult registry settings to determine whether:
// UpIfName   upstream interface can accept prefix delegations, and (optionally)
// DownIfName interface belongs to the set of downstream interfaces for
//            UpIfName. Can be NULL.
//
// If DownIfName is NULL, then function will only check whether UpIfName
// can accept PD.
//
BOOL IsPDEnabledInterface(PCHAR UpIfName, PCHAR DownIfName) {
    BOOL fRet = FALSE; // Be pessimistic
    HKEY hKey = INVALID_HANDLE_VALUE;
    TCHAR szRegValue[MAX_REG_STR];
    TCHAR szDownIfName[MAX_REG_STR];

⌨️ 快捷键说明

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