windows-nt/Source/XPSP1/NT/net/rras/ip/nathlp/dll/range.cpp

233 lines
4.8 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998, Microsoft Corporation
Module Name:
range.c
Abstract:
This module implements an efficient mapping from an arbitrary range of
IP addresses to a minimal set of IP address-mask pairs covering the range.
The key to the approach is to regard the set of all possible IP addresses
as a full 32-bit deep binary tree. Then a single IP address is a path
through that tree, and a range of addresses is the area between two paths
through the tree. We then describe such a path-delineated area by pruning
full subtrees of the area recursively from left to right.
Author:
Abolade Gbadegesin (aboladeg) 20-Mar-1998
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
VOID
DecomposeRange(
ULONG StartAddress,
ULONG EndAddress,
ULONG Mask,
PDECOMPOSE_RANGE_CALLBACK Callback,
PVOID CallbackContext
)
/*++
Routine Description:
This routine decomposes the range StartAddress-EndAddress into
a minimal set of address-mask pairs, passing the generated
pairs to the given callback routine.
Arguments:
StartAddress - the start of the range
EndAddress - the end of the range
Mask - the most general mask covering the range
Callback - routine invoked for each generated address-mask pair
CallbackContext - context passed to 'Callback'.
Return Value:
none.
--*/
{
ULONG temp;
//
// Step 1:
// Check for the first base case: the root of a full tree.
//
if ((StartAddress & ~Mask) == 0 && (EndAddress & ~Mask) == ~Mask) {
if (Callback) { Callback(StartAddress, Mask, CallbackContext); }
return;
}
//
// Step 2.
// Extend the mask by one bit to cover the first different position
// between the start and end address, essentially moving down in the tree
// to the node where the paths branch.
//
// . <- Most general mask
// |
// * <- branching point
// / \
//
Mask = ntohl(Mask);
Mask >>= 1; Mask |= (1<<31);
Mask = htonl(Mask);
//
// Step 3.
// Split the range, with the new right edge being a fully-rightward path
// (no left turns) starting below and to the left of the branching point.
//
// . <- branching point
// / \
// *
// \ <- new right edge
//
temp = StartAddress | ~Mask;
//
// Step 4.
// Check for the second base case:
// the left edge is a fully-leftward path (all-zeroes).
//
if ((StartAddress & ~Mask) == 0) {
if (Callback) { Callback(StartAddress, Mask, CallbackContext); }
}
else {
//
// Not a base case, so take the left branch.
//
DecomposeRange(
StartAddress,
temp,
Mask,
Callback,
CallbackContext
);
}
//
// we may be done, if the right edge is also fully rightward
//
if ((StartAddress | ~Mask) == EndAddress) { return; }
//
// Step 5.
// Decompose the remaining portion of the range,
// with the new left edge being the fully-leftward path which starts
// below and to the right of the original branching point.
//
// . <- branching point
// / \
// *
// / <- new left edge
//
temp = EndAddress & Mask;
//
// Step 6.
// Check for the third base case:
// the right edge is fully-rightward (all-ones).
//
if (EndAddress == (temp | ~Mask)) {
if (Callback) { Callback(EndAddress, Mask, CallbackContext); }
}
else {
//
// Not a base case; take the right branch.
//
DecomposeRange(
temp,
EndAddress,
MostGeneralMask(temp, EndAddress),
Callback,
CallbackContext
);
}
}
ULONG
MostGeneralMask(
ULONG StartAddress,
ULONG EndAddress
)
/*++
Routine Description:
This routine generates the most general mask covering the range
'StartAddress' - 'EndAddress'.
Arguments:
StartAddress - beginning of range, in network order
EndAddress - end of range, in network order
Return Value:
ULONG - the most general mask
--*/
{
ULONG CommonBits, Mask;
StartAddress = ntohl(StartAddress);
EndAddress = ntohl(EndAddress);
//
// find the bits common to the start address and end address
//
CommonBits = ~(StartAddress ^ EndAddress);
//
// CommonBits now has a 1 in each position where StartAddress and
// EndAddress are the same.
// We want to reduce this to only include the longest contiguous
// most significant bits
// e.g. 11101110 becomes 11100000 and 11111101 becomes 11111100
//
for (Mask = 0xffffffff; Mask && ((CommonBits & Mask) != Mask); Mask<<=1) { }
return htonl(Mask);
}