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.

298 lines
8.8 KiB

  1. /*
  2. File autonet.c
  3. Contains routines that allow the ipx router to automatically select an
  4. internal network number.
  5. Paul Mayfield, 11/21/97.
  6. */
  7. #include <nt.h>
  8. #include <ntrtl.h>
  9. #include <nturtl.h>
  10. #include <windows.h>
  11. #include <winsvc.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <raserror.h>
  16. #include <dim.h>
  17. #include <rtm.h>
  18. #include <ipxrtprt.h>
  19. #include <rmrtm.h>
  20. #include <mprlog.h>
  21. #include <rtinfo.h>
  22. #include <ipxrtdef.h>
  23. #include <mprerror.h>
  24. #include <adapter.h>
  25. #include <fwif.h>
  26. #include <rtutils.h>
  27. #include "ipxanet.h"
  28. #include "utils.h"
  29. // Sends debug output to a debugger terminal
  30. DWORD OutputDebugger (LPSTR pszError, ...) {
  31. #if DBG
  32. va_list arglist;
  33. char szBuffer[1024], szTemp[1024];
  34. va_start(arglist, pszError);
  35. vsprintf(szTemp, pszError, arglist);
  36. va_end(arglist);
  37. sprintf(szBuffer, "IPXAUTO: %s", szTemp);
  38. OutputDebugStringA(szBuffer);
  39. #endif
  40. return NO_ERROR;
  41. }
  42. DWORD dwTraceId = 0;
  43. ULONG ulRandSeed = 0;
  44. DWORD InitTrace() {
  45. if (dwTraceId)
  46. return NO_ERROR;
  47. dwTraceId = TraceRegisterExA ("ipxautonet", 0);
  48. return NO_ERROR;
  49. }
  50. DWORD SetIpxInternalNetNumber(DWORD dwNetNum);
  51. // New helper functions from adptif
  52. DWORD FwIsStarted (OUT PBOOL pbIsStarted);
  53. DWORD IpxDoesRouteExist (IN PUCHAR puNetwork, OUT PBOOL pbRouteFound);
  54. DWORD IpxGetAdapterConfig(OUT LPDWORD lpdwInternalNetNum,
  55. OUT LPDWORD lpdwAdapterCount);
  56. // Outputs an error to the tracing facility
  57. VOID AutoTraceError(DWORD dwErr) {
  58. char buf[1024];
  59. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,dwErr,(DWORD)0,buf,1024,NULL);
  60. TracePrintfA (dwTraceId, buf);
  61. }
  62. // Seeds the random number generator
  63. DWORD SeedRandomGenerator() {
  64. DWORD dwTick;
  65. // Generate a unique number to seed the random number generator with
  66. dwTick = GetTickCount();
  67. ulRandSeed = dwTick ^ (dwTick << ((GetCurrentProcessId() % 16)));
  68. return NO_ERROR;
  69. }
  70. // Returns a random number between 11 and 2^32
  71. // Currently, the rand() function generates a random number between 0 and 0x7fff.
  72. // What we do to generate the random number is generate 8 random numbers each 4 bits
  73. // wide and then paste them together.
  74. DWORD RandomNetNumber() {
  75. DWORD dw[4], dwRand = 0, i;
  76. // Generate the numbers
  77. dw[0] = RtlRandom(&ulRandSeed) & 0xff;
  78. dw[1] = RtlRandom(&ulRandSeed) & 0xff;
  79. dw[2] = RtlRandom(&ulRandSeed) & 0xff;
  80. dw[3] = RtlRandom(&ulRandSeed) & 0xff;
  81. // Paste the numbers together
  82. for (i = 0; i < 4; i++)
  83. dwRand |= dw[i] << (i*8);
  84. // If by some small chance, an illegal value was choosen,
  85. // correct it.
  86. if (dwRand < 11)
  87. dwRand += 11;
  88. return dwRand;
  89. }
  90. //
  91. // Function: QueryStackForRouteExistance
  92. //
  93. // Asks the stack to check it's route table for the existance of the given network.
  94. // If no route exists in its table, the stack will send out a rip broadcast to be
  95. // doubly sure that the network does not exist.
  96. //
  97. // This function blocks until it completes.
  98. //
  99. // Params:
  100. // dwNetwork host-ordered network number to query
  101. // pbRouteExists set to TRUE if a route to the given network exists. false,
  102. // if the rip broadcast that the stack sends times out.
  103. //
  104. DWORD QueryStackForRouteExistance(IN DWORD dwNetwork, OUT PBOOL pbRouteExists) {
  105. UCHAR puNetwork[4];
  106. DWORD dwErr;
  107. // Prepare the network number
  108. PUTULONG2LONG(puNetwork, dwNetwork);
  109. // Initialize
  110. *pbRouteExists = FALSE;
  111. if ((dwErr = IpxDoesRouteExist (puNetwork, pbRouteExists)) != NO_ERROR)
  112. return dwErr;
  113. return NO_ERROR;
  114. }
  115. //
  116. // Function: QueryRtmForRouteExistance
  117. //
  118. // Discovers whether a route to a given network exists in rtm.
  119. //
  120. // This function blocks until it completes.
  121. //
  122. // Params:
  123. // dwNetwork host-ordered network number to query
  124. // pbRouteExists set to TRUE if a route to the route exists -- false, otherwise
  125. //
  126. DWORD QueryRtmForRouteExistance(IN DWORD dwNetwork, OUT PBOOL pbRouteExists) {
  127. *pbRouteExists = RtmIsRoute (RTM_PROTOCOL_FAMILY_IPX, &dwNetwork, NULL);
  128. return NO_ERROR;
  129. }
  130. //
  131. // Function: PnpAutoSelectInternalNetNumber
  132. //
  133. // Selects a new internal network number for this router and plumbs that network
  134. // number into the stack and the router.
  135. //
  136. // Depending on whether the forwarder and ipxrip are enabled, it will validate the
  137. // newly selected net number against the stack or rtm.
  138. //
  139. // Params:
  140. // dwNetwork host-ordered network number to query
  141. // pbRouteExists set to TRUE if a route to the route exists -- false, otherwise
  142. //
  143. DWORD PnpAutoSelectInternalNetNumber(DWORD dwGivenTraceId) {
  144. DWORD i, j, dwErr, dwNewNet;
  145. BOOL bNetworkFound = FALSE, bFwStarted;
  146. TracePrintfA (dwTraceId, "PnpAutoSelectInternalNetNumber: Entered");
  147. // Find out if the forwarder and ipx rip have been started
  148. if ((dwErr = FwIsStarted(&bFwStarted)) != NO_ERROR)
  149. return dwErr;
  150. TracePrintfA (dwTraceId, "PnpAutoSelectInternalNetNumber: Forwarder %s started",
  151. (bFwStarted) ? "has already been" : "has not been");
  152. __try {
  153. // Initialize the random number generator
  154. if ((dwErr = SeedRandomGenerator()) != NO_ERROR)
  155. return dwErr;
  156. // Discover a unique network number
  157. do {
  158. // Randomly select a new net number
  159. dwNewNet = RandomNetNumber();
  160. // Find out if the given network exists
  161. if (bFwStarted) {
  162. if ((dwErr = QueryRtmForRouteExistance (dwNewNet, &bNetworkFound)) != NO_ERROR)
  163. return dwErr;
  164. }
  165. else {
  166. if ((dwErr = QueryStackForRouteExistance (dwNewNet, &bNetworkFound)) != NO_ERROR)
  167. return dwErr;
  168. }
  169. // Send some debug output
  170. TracePrintfA (dwTraceId, "PnpAutoSelectInternalNetNumber: 0x%08x %s", dwNewNet, (bNetworkFound) ? "already exists." : "has been selected.");
  171. } while (bNetworkFound);
  172. // Set the internal network number to the discovered unique net number. This call
  173. // uses inetcfg to programmatically set the net network number.
  174. if ((dwErr = SetIpxInternalNetNumber(dwNewNet)) != NO_ERROR)
  175. return dwErr;
  176. }
  177. __finally {
  178. if (dwErr != NO_ERROR)
  179. AutoTraceError(dwErr);
  180. }
  181. return NO_ERROR;
  182. }
  183. BOOL NetNumIsValid (DWORD dwNum) {
  184. return ((dwNum != 0) && (dwNum != 0xffffffff));
  185. }
  186. //
  187. // Function: AutoValidateInternalNetNum
  188. //
  189. // Queries the stack to learn the internal network number and then
  190. // returns whether this number is valid for running an ipx router.
  191. //
  192. // Params:
  193. // pbIsValid set to TRUE if internal net num is valid -- false, otherwise
  194. //
  195. DWORD AutoValidateInternalNetNum(OUT PBOOL pbIsValid, IN DWORD dwGlobalTraceId) {
  196. DWORD dwErr, dwIntNetNum, dwAdapterCount;
  197. InitTrace();
  198. TracePrintfA (dwTraceId, "AutoValidateInternalNetNum: Entered");
  199. // Get the current internal network number
  200. if ((dwErr = IpxGetAdapterConfig(&dwIntNetNum, &dwAdapterCount)) != NO_ERROR) {
  201. TracePrintfA (dwTraceId, "AutoValidateInternalNetNum: couldn't get adapter config %x", dwErr);
  202. AutoTraceError(dwErr);
  203. return dwErr;
  204. }
  205. // Check the validity of the internal net number. If it's a valid
  206. // number, don't mess with it.
  207. *pbIsValid = !!(NetNumIsValid(dwIntNetNum));
  208. TracePrintfA (dwTraceId, "AutoValidateInternalNetNum: Net Number 0x%x is %s", dwIntNetNum,
  209. (*pbIsValid) ? "valid" : "not valid");
  210. return NO_ERROR;
  211. }
  212. //
  213. // Function: AutoWaitForValidNetNum
  214. //
  215. // Puts the calling thread to sleep until a valid internal network number
  216. // has been plumbed into the system.
  217. //
  218. // Params:
  219. // dwTimeout timeout in seconds
  220. // pbIsValid if provided, returns whether number is valid
  221. //
  222. DWORD AutoWaitForValidIntNetNum (IN DWORD dwTimeout,
  223. IN OUT OPTIONAL PBOOL pbIsValid) {
  224. DWORD dwErr, dwNum, dwCount, dwGran = 250;
  225. // Initialize optional params
  226. if (pbIsValid)
  227. *pbIsValid = TRUE;
  228. // Convert the timeout to milliseconds
  229. dwTimeout *= 1000;
  230. while (dwTimeout > dwGran) {
  231. // Get the current internal network number
  232. if ((dwErr = IpxGetAdapterConfig(&dwNum, &dwCount)) != NO_ERROR)
  233. return dwErr;
  234. if (NetNumIsValid (dwNum)) {
  235. if (pbIsValid)
  236. *pbIsValid = TRUE;
  237. break;
  238. }
  239. Sleep (dwGran);
  240. dwTimeout -= dwGran;
  241. }
  242. return NO_ERROR;
  243. }