233 lines
4.8 KiB
C++
233 lines
4.8 KiB
C++
/*++
|
||
|
||
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);
|
||
}
|
||
|
||
|