Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
5.0 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. range.c
  5. Abstract:
  6. This module implements an efficient mapping from an arbitrary range of
  7. IP addresses to a minimal set of IP address-mask pairs covering the range.
  8. The key to the approach is to regard the set of all possible IP addresses
  9. as a full 32-bit deep binary tree. Then a single IP address is a path
  10. through that tree, and a range of addresses is the area between two paths
  11. through the tree. We then describe such a path-delineated area by pruning
  12. full subtrees of the area recursively from left to right.
  13. Author:
  14. Abolade Gbadegesin (aboladeg) 20-Mar-1998
  15. Revision History:
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. VOID
  20. DecomposeRange(
  21. ULONG StartAddress,
  22. ULONG EndAddress,
  23. ULONG Mask,
  24. PDECOMPOSE_RANGE_CALLBACK Callback,
  25. PVOID CallbackContext
  26. )
  27. /*++
  28. Routine Description:
  29. This routine decomposes the range StartAddress-EndAddress into
  30. a minimal set of address-mask pairs, passing the generated
  31. pairs to the given callback routine.
  32. Arguments:
  33. StartAddress - the start of the range
  34. EndAddress - the end of the range
  35. Mask - the most general mask covering the range
  36. Callback - routine invoked for each generated address-mask pair
  37. CallbackContext - context passed to 'Callback'.
  38. Return Value:
  39. none.
  40. --*/
  41. {
  42. ULONG temp;
  43. //
  44. // Step 1:
  45. // Check for the first base case: the root of a full tree.
  46. //
  47. if ((StartAddress & ~Mask) == 0 && (EndAddress & ~Mask) == ~Mask) {
  48. if (Callback) { Callback(StartAddress, Mask, CallbackContext); }
  49. return;
  50. }
  51. //
  52. // Step 2.
  53. // Extend the mask by one bit to cover the first different position
  54. // between the start and end address, essentially moving down in the tree
  55. // to the node where the paths branch.
  56. //
  57. // . <- Most general mask
  58. // |
  59. // * <- branching point
  60. // / \
  61. //
  62. Mask = ntohl(Mask);
  63. Mask >>= 1; Mask |= (1<<31);
  64. Mask = htonl(Mask);
  65. //
  66. // Step 3.
  67. // Split the range, with the new right edge being a fully-rightward path
  68. // (no left turns) starting below and to the left of the branching point.
  69. //
  70. // . <- branching point
  71. // / \
  72. // *
  73. // \ <- new right edge
  74. //
  75. temp = StartAddress | ~Mask;
  76. //
  77. // Step 4.
  78. // Check for the second base case:
  79. // the left edge is a fully-leftward path (all-zeroes).
  80. //
  81. if ((StartAddress & ~Mask) == 0) {
  82. if (Callback) { Callback(StartAddress, Mask, CallbackContext); }
  83. }
  84. else {
  85. //
  86. // Not a base case, so take the left branch.
  87. //
  88. DecomposeRange(
  89. StartAddress,
  90. temp,
  91. Mask,
  92. Callback,
  93. CallbackContext
  94. );
  95. }
  96. //
  97. // we may be done, if the right edge is also fully rightward
  98. //
  99. if ((StartAddress | ~Mask) == EndAddress) { return; }
  100. //
  101. // Step 5.
  102. // Decompose the remaining portion of the range,
  103. // with the new left edge being the fully-leftward path which starts
  104. // below and to the right of the original branching point.
  105. //
  106. // . <- branching point
  107. // / \
  108. // *
  109. // / <- new left edge
  110. //
  111. temp = EndAddress & Mask;
  112. //
  113. // Step 6.
  114. // Check for the third base case:
  115. // the right edge is fully-rightward (all-ones).
  116. //
  117. if (EndAddress == (temp | ~Mask)) {
  118. if (Callback) { Callback(EndAddress, Mask, CallbackContext); }
  119. }
  120. else {
  121. //
  122. // Not a base case; take the right branch.
  123. //
  124. DecomposeRange(
  125. temp,
  126. EndAddress,
  127. MostGeneralMask(temp, EndAddress),
  128. Callback,
  129. CallbackContext
  130. );
  131. }
  132. }
  133. ULONG
  134. MostGeneralMask(
  135. ULONG StartAddress,
  136. ULONG EndAddress
  137. )
  138. /*++
  139. Routine Description:
  140. This routine generates the most general mask covering the range
  141. 'StartAddress' - 'EndAddress'.
  142. Arguments:
  143. StartAddress - beginning of range, in network order
  144. EndAddress - end of range, in network order
  145. Return Value:
  146. ULONG - the most general mask
  147. --*/
  148. {
  149. ULONG CommonBits, Mask;
  150. StartAddress = ntohl(StartAddress);
  151. EndAddress = ntohl(EndAddress);
  152. //
  153. // find the bits common to the start address and end address
  154. //
  155. CommonBits = ~(StartAddress ^ EndAddress);
  156. //
  157. // CommonBits now has a 1 in each position where StartAddress and
  158. // EndAddress are the same.
  159. // We want to reduce this to only include the longest contiguous
  160. // most significant bits
  161. // e.g. 11101110 becomes 11100000 and 11111101 becomes 11111100
  162. //
  163. for (Mask = 0xffffffff; Mask && ((CommonBits & Mask) != Mask); Mask<<=1) { }
  164. return htonl(Mask);
  165. }