|
|
/*++
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); }
|