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.

632 lines
14 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. wannet.c
  5. Abstract:
  6. Wan net allocation module
  7. Author:
  8. Stefan Solomon 11/03/1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. extern DWORD (WINAPI * RmCreateGlobalRoute)(PUCHAR Network);
  14. extern HANDLE g_hRouterLog;
  15. ULONG LastUsedRandSeed;
  16. //
  17. // Variable keeping the initialization state of the IPXCP Configuration Database
  18. //
  19. BOOL WanConfigDbaseInitialized = FALSE;
  20. // WAN net pool entry structure
  21. typedef struct _NET_ENTRY {
  22. BOOL InUse;
  23. UCHAR Network[4];
  24. } NET_ENTRY, *PNET_ENTRY;
  25. // Structure represents a pool of
  26. // wan net numbers. This pool dynamically
  27. // grows and shrinks as clients dial
  28. // in and hang up
  29. typedef struct _WAN_NET_POOL {
  30. DWORD dwMaxSize;
  31. DWORD dwCurSize;
  32. DWORD dwInUseCount;
  33. NET_ENTRY * pEntries;
  34. } WAN_NET_POOL, *PWAN_NET_POOL;
  35. #define WANNET_DEFAULT_SIZE 10
  36. #define WANNET_DEFAULT_GROW 100
  37. #define WANNET_MAXSIZE 64000
  38. //
  39. // WAN net numbers pool
  40. //
  41. WAN_NET_POOL WanNetPool = {WANNET_MAXSIZE, 0, 0, NULL};
  42. //
  43. // Global WAN net
  44. //
  45. //UCHAR GlobalConfig.RParams.GlobalWanNet[4] = {0,0,0,0};
  46. ULONG GlobalWanNetIndex; // when global wan net comes from pool - the index
  47. DWORD
  48. InitWanNetConfigDbase(VOID);
  49. DWORD
  50. WanNetAlloc(PUCHAR Network,
  51. PULONG AllocatedNetworkIndexp);
  52. DWORD
  53. CreateWanNetPool(VOID);
  54. DWORD
  55. GrowWanNetPool (WAN_NET_POOL * pPool);
  56. DWORD
  57. CreateGlobalWanNet(VOID);
  58. VOID
  59. DestroyWanNetPool(VOID);
  60. VOID
  61. DestroyGlobalWanNet(VOID);
  62. DWORD
  63. AllocWanNetFromPool(PUCHAR Network,
  64. PULONG AllocatedNetworkIndexp);
  65. VOID
  66. FreeWanNetToPool(ULONG AllocatedNetworkIndex);
  67. DWORD
  68. GetRandomNetNumber(PUCHAR Network);
  69. /*++
  70. Function: GetWanNetNumber
  71. Descr: This function is called by IPXCP or IPXWAN to get a network
  72. number from the pool.
  73. Parameters:
  74. Network
  75. AllocatedNetworkIndex - if the value returned by this param is
  76. not INVALID_NETWORK_INDEX then the caller must call ReleaseWanNetNumber
  77. to free the net to the pool.
  78. InterfaceType
  79. Returns NO_ERROR - a network has been successfully allocated
  80. --*/
  81. DWORD
  82. GetWanNetNumber(IN OUT PUCHAR Network,
  83. IN OUT PULONG AllocatedNetworkIndexp,
  84. IN ULONG InterfaceType)
  85. {
  86. DWORD rc;
  87. memcpy(Network, nullnet, 4);
  88. *AllocatedNetworkIndexp = INVALID_NETWORK_INDEX;
  89. // if this a router <-> router connection and we are configured for
  90. // Unnumbered RIP -> return 0.
  91. if((InterfaceType == IF_TYPE_WAN_ROUTER) ||
  92. (InterfaceType == IF_TYPE_PERSONAL_WAN_ROUTER)) {
  93. if(GlobalConfig.EnableUnnumberedWanLinks) {
  94. return NO_ERROR;
  95. }
  96. }
  97. ACQUIRE_DATABASE_LOCK;
  98. if(!WanConfigDbaseInitialized) {
  99. if((rc = InitWanNetConfigDbase()) != NO_ERROR) {
  100. RELEASE_DATABASE_LOCK;
  101. return rc;
  102. }
  103. }
  104. // check the interface type
  105. if((InterfaceType == IF_TYPE_WAN_WORKSTATION) &&
  106. GlobalConfig.RParams.EnableGlobalWanNet) {
  107. memcpy(Network, GlobalConfig.RParams.GlobalWanNet, 4);
  108. *AllocatedNetworkIndexp = INVALID_NETWORK_INDEX;
  109. rc = NO_ERROR;
  110. }
  111. else
  112. {
  113. rc = WanNetAlloc(Network,
  114. AllocatedNetworkIndexp);
  115. }
  116. RELEASE_DATABASE_LOCK;
  117. return rc;
  118. }
  119. /*++
  120. Function: ReleaseWanNetNumber
  121. Descr: This function will be called by ipxcp to release the net number
  122. used for configuring the WAN link. The call is issued when the
  123. WAN link gets disconnected.
  124. --*/
  125. VOID
  126. ReleaseWanNetNumber(ULONG AllocatedNetworkIndex)
  127. {
  128. ACQUIRE_DATABASE_LOCK;
  129. SS_ASSERT(WanConfigDbaseInitialized);
  130. SS_ASSERT(AllocatedNetworkIndex != INVALID_NETWORK_INDEX);
  131. FreeWanNetToPool(AllocatedNetworkIndex);
  132. RELEASE_DATABASE_LOCK;
  133. return;
  134. }
  135. /*++
  136. Function: InitWanNetConfigDatabase
  137. Descr: Configures the database of network numbers used for incoming
  138. WAN links.
  139. Remark: This function is called from the GetWanNetNumber (see below) when
  140. IPXCP has an incoming call and the router has been started and the
  141. database hasn't been configured yet.
  142. Remark2: >> called with database lock held <<
  143. --*/
  144. DWORD
  145. InitWanNetConfigDbase(VOID)
  146. {
  147. DWORD rc;
  148. // create wan net pool
  149. if(!GlobalConfig.EnableAutoWanNetAllocation) {
  150. if((rc = CreateWanNetPool()) != NO_ERROR) {
  151. return rc;
  152. }
  153. }
  154. // create global wan net
  155. if(GlobalConfig.RParams.EnableGlobalWanNet) {
  156. if((rc = CreateGlobalWanNet()) != NO_ERROR) {
  157. return rc;
  158. }
  159. }
  160. WanConfigDbaseInitialized = TRUE;
  161. return NO_ERROR;
  162. }
  163. /*++
  164. Function: DestroyWanNetConfigDatabase
  165. Descr: Frees resources allocated for the wan net config database
  166. Remark: called when the router stops
  167. --*/
  168. VOID
  169. DestroyWanNetConfigDatabase(VOID)
  170. {
  171. if(!WanConfigDbaseInitialized) {
  172. return;
  173. }
  174. // destroy wan net pool
  175. if(!GlobalConfig.EnableAutoWanNetAllocation) {
  176. DestroyWanNetPool();
  177. }
  178. WanConfigDbaseInitialized = FALSE;
  179. }
  180. /*++
  181. Function: WanNetAlloc
  182. Descr:
  183. Remark: >> called with database lock held <<
  184. --*/
  185. DWORD
  186. WanNetAlloc(IN OUT PUCHAR Network,
  187. IN OUT PULONG AllocatedNetworkIndexp)
  188. {
  189. DWORD rc;
  190. if(GlobalConfig.EnableAutoWanNetAllocation) {
  191. // try a number of times to generate a unique net number
  192. rc = GetRandomNetNumber(Network);
  193. *AllocatedNetworkIndexp = INVALID_NETWORK_INDEX;
  194. }
  195. else
  196. {
  197. rc = AllocWanNetFromPool(Network,
  198. AllocatedNetworkIndexp);
  199. }
  200. return rc;
  201. }
  202. /*++
  203. Function: CreateWanNetPool
  204. Descr:
  205. Remark: >> called with database lock held <<
  206. --*/
  207. DWORD
  208. CreateWanNetPool(VOID)
  209. {
  210. ULONG i;
  211. PNET_ENTRY nep;
  212. PWSTR nesp;
  213. ULONG wannet;
  214. UCHAR asc[9];
  215. PUCHAR ascp;
  216. // Create the pool of WAN network numbers to be used in configuring
  217. // incoming WAN links.
  218. if ((GlobalConfig.WanNetPoolStr.Buffer!=NULL) && (GlobalConfig.WanNetPoolStr.Length >0)) {
  219. DWORD strsz = 0;
  220. nesp = GlobalConfig.WanNetPoolStr.Buffer;
  221. strsz = 0;
  222. while (*nesp!=0) {
  223. strsz += 1;
  224. wannet = wcstoul (nesp, NULL, 16);
  225. if ((wannet==0) || (wannet==0xFFFFFFFF))
  226. break;
  227. nesp += wcslen (nesp) + 1;
  228. }
  229. if ((*nesp!=0) ||
  230. (strsz!=(GlobalConfig.WanNetPoolSize)) ||
  231. ((GlobalConfig.WanNetPoolSize) > WANNET_MAXSIZE)) {
  232. TraceIpx(WANNET_TRACE, "Invalid wan net pool config WanNetPoolSize =%d\n,"
  233. " entries: ",
  234. (GlobalConfig.WanNetPoolSize));
  235. nesp = GlobalConfig.WanNetPoolStr.Buffer;
  236. while (*nesp!=0) {
  237. TraceIpx(WANNET_TRACE|TRACE_NO_STDINFO, "%ls ", nesp);
  238. nesp += wcslen (nesp) + 1;
  239. }
  240. return ERROR_CAN_NOT_COMPLETE;
  241. }
  242. }
  243. else {
  244. if (((GlobalConfig.FirstWanNet) == 0) ||
  245. ((GlobalConfig.FirstWanNet) == 0xFFFFFFFF) ||
  246. ((GlobalConfig.WanNetPoolSize) > WANNET_MAXSIZE)) {
  247. TraceIpx(WANNET_TRACE, "Invalid wan net pool config, FirstWanNet=%x, WanNetPoolSize =%d\n",
  248. GlobalConfig.FirstWanNet, GlobalConfig.WanNetPoolSize);
  249. return ERROR_CAN_NOT_COMPLETE;
  250. }
  251. }
  252. // If the WanNetPoolSize is 0, then assume any size
  253. if ((GlobalConfig.WanNetPoolSize == 0) ||
  254. (GlobalConfig.WanNetPoolSize > WANNET_MAXSIZE))
  255. {
  256. GlobalConfig.WanNetPoolSize = WANNET_MAXSIZE;
  257. }
  258. // Initialize the wan net pool
  259. WanNetPool.dwMaxSize = GlobalConfig.WanNetPoolSize;
  260. WanNetPool.dwCurSize = 0;
  261. WanNetPool.dwInUseCount = 0;
  262. WanNetPool.pEntries = NULL;
  263. return GrowWanNetPool (&WanNetPool);
  264. }
  265. //
  266. // This function resizes the wan net pool to accomodate additional
  267. // callers.
  268. //
  269. DWORD GrowWanNetPool (WAN_NET_POOL * pPool) {
  270. PWCHAR pszNetList = GlobalConfig.WanNetPoolStr.Buffer;
  271. PNET_ENTRY pNewEntries, pCur;
  272. DWORD i, dwNewSize, dwNewNet;
  273. UCHAR uNetwork[9], *puNetwork;
  274. uNetwork[8] = 0;
  275. puNetwork = uNetwork;
  276. // Enforce that we aren't going to grow beyond our bounds
  277. if (pPool->dwCurSize >= pPool->dwMaxSize)
  278. return ERROR_CAN_NOT_COMPLETE;
  279. // Initialize the new size
  280. if (! pPool->dwCurSize)
  281. dwNewSize = WANNET_DEFAULT_SIZE;
  282. else
  283. dwNewSize = pPool->dwCurSize + WANNET_DEFAULT_GROW;
  284. // Truncate the new size to the maximum size
  285. if (dwNewSize > pPool->dwMaxSize)
  286. dwNewSize = pPool->dwMaxSize;
  287. // Initailize a new array of entries
  288. pNewEntries = GlobalAlloc(GPTR, sizeof(NET_ENTRY) * dwNewSize);
  289. if (pNewEntries == NULL) {
  290. SS_ASSERT(FALSE);
  291. return ERROR_NOT_ENOUGH_MEMORY;
  292. }
  293. // Copy over the old entries
  294. if (pPool->dwCurSize)
  295. CopyMemory (pNewEntries, pPool->pEntries, pPool->dwCurSize * sizeof(NET_ENTRY));
  296. // Go through the new entries verifying them on the network
  297. for(i = pPool->dwCurSize, pCur = &(pNewEntries[pPool->dwCurSize]); i < dwNewSize; i++, pCur++) {
  298. // If the user hadn't given a specific list of addresses,
  299. // then add test the next numeric network number
  300. if ((pszNetList == NULL) || (*pszNetList == L'\0'))
  301. dwNewNet = GlobalConfig.FirstWanNet + i;
  302. // Otherwise, get the next number from the list
  303. else {
  304. dwNewNet = wcstoul (pszNetList, NULL, 16);
  305. pszNetList += wcslen (pszNetList) + 1;
  306. }
  307. // check if this network number is unique. Generate an warning log
  308. // if it isn't
  309. PUTULONG2LONG(pCur->Network, dwNewNet);
  310. if(IsRoute(pCur->Network) || (dwNewNet == 0xFFFFFFFF) || (dwNewNet == 0)) {
  311. NetToAscii(puNetwork, pCur->Network);
  312. RouterLogWarningW(
  313. g_hRouterLog,
  314. ROUTERLOG_IPXCP_WAN_NET_POOL_NETWORK_NUMBER_CONFLICT,
  315. 1,
  316. (PWCHAR*)&puNetwork,
  317. NO_ERROR);
  318. TraceIpx(WANNET_TRACE, "InitWanNetConfigDbase: Configured WAN pool network %.2x%.2x%.2x%.2x is in use!\n",
  319. pCur->Network[0], pCur->Network[1], pCur->Network[2], pCur->Network[3]);
  320. pCur->InUse = TRUE;
  321. pPool->dwInUseCount++;
  322. }
  323. else
  324. pCur->InUse = FALSE;
  325. }
  326. // Free the old pool and assign the new one
  327. GlobalFree (pPool->pEntries);
  328. pPool->pEntries = pNewEntries;
  329. pPool->dwCurSize = dwNewSize;
  330. return NO_ERROR;
  331. }
  332. /*++
  333. Function: CreateGlobalWanNet
  334. Descr:
  335. Remark: >> called with database lock held <<
  336. --*/
  337. DWORD
  338. CreateGlobalWanNet(VOID)
  339. {
  340. DWORD rc;
  341. ULONG i;
  342. if(GlobalConfig.EnableAutoWanNetAllocation) {
  343. // create the global wan net "automatically".
  344. // We do that by trying to use the system timer value
  345. rc = GetRandomNetNumber(GlobalConfig.RParams.GlobalWanNet);
  346. }
  347. else
  348. {
  349. rc = AllocWanNetFromPool(GlobalConfig.RParams.GlobalWanNet,
  350. &GlobalWanNetIndex);
  351. }
  352. if(rc == NO_ERROR) {
  353. // add the global wan net to the routing table if router is started
  354. // if the router is not started, it will get the global wan net when
  355. // it will issue the IpxcpBind call
  356. if(RouterStarted) {
  357. rc =(*RmCreateGlobalRoute)(GlobalConfig.RParams.GlobalWanNet);
  358. }
  359. }
  360. return rc;
  361. }
  362. VOID
  363. DestroyWanNetPool(VOID)
  364. {
  365. WAN_NET_POOL DefaultPool = {WANNET_MAXSIZE, 0, 0, NULL};
  366. if (WanNetPool.dwCurSize) {
  367. if (WanNetPool.pEntries)
  368. GlobalFree (WanNetPool.pEntries);
  369. WanNetPool = DefaultPool;
  370. }
  371. }
  372. DWORD
  373. AllocWanNetFromPool(PUCHAR Network,
  374. PULONG NetworkIndexp)
  375. {
  376. ULONG i;
  377. PNET_ENTRY nep;
  378. DWORD rc;
  379. // First, see if we have to grow the pool
  380. if (WanNetPool.dwInUseCount >= WanNetPool.dwCurSize)
  381. GrowWanNetPool (&WanNetPool);
  382. // get a net from the pool
  383. for(i=0, nep=WanNetPool.pEntries; i<WanNetPool.dwCurSize; i++, nep++) {
  384. if(!nep->InUse) {
  385. nep->InUse = TRUE;
  386. WanNetPool.dwInUseCount++;
  387. memcpy(Network, nep->Network, 4);
  388. *NetworkIndexp = i;
  389. rc = NO_ERROR;
  390. goto Exit;
  391. }
  392. }
  393. // can't find a free net pool entry
  394. *NetworkIndexp = INVALID_NETWORK_INDEX;
  395. rc = ERROR_CAN_NOT_COMPLETE;
  396. Exit:
  397. return rc;
  398. }
  399. VOID
  400. FreeWanNetToPool(ULONG AllocatedNetworkIndex)
  401. {
  402. PNET_ENTRY nep;
  403. if(AllocatedNetworkIndex >= WanNetPool.dwCurSize) {
  404. return;
  405. }
  406. nep = &(WanNetPool.pEntries[AllocatedNetworkIndex]);
  407. SS_ASSERT(nep->InUse);
  408. nep->InUse = FALSE;
  409. WanNetPool.dwInUseCount--;
  410. return;
  411. }
  412. DWORD randn(DWORD seed)
  413. {
  414. seed = seed * 1103515245 + 12345;
  415. return seed;
  416. }
  417. DWORD
  418. GetRandomNetNumber(PUCHAR Network)
  419. {
  420. DWORD rc = ERROR_CAN_NOT_COMPLETE;
  421. ULONG i, seed, high, low, netnumber;
  422. for(i=0; i<100000; i++) {
  423. seed = GetTickCount();
  424. // check if this isn't the same seed as last used
  425. if(seed == LastUsedRandSeed) {
  426. seed++;
  427. }
  428. LastUsedRandSeed = seed;
  429. // generate a sequence of two random numbers using the time tick count
  430. // as seed
  431. low = randn(seed) >> 16;
  432. high = randn(randn(seed)) & 0xffff0000;
  433. netnumber = high + low;
  434. PUTULONG2LONG(Network, netnumber);
  435. if(!IsRoute(Network)) {
  436. rc = NO_ERROR;
  437. break;
  438. }
  439. }
  440. return rc;
  441. }
  442. //
  443. // Reconfigures the wannet database
  444. //
  445. DWORD WanNetReconfigure() {
  446. ACQUIRE_DATABASE_LOCK;
  447. // Destroy the current pool
  448. DestroyWanNetPool();
  449. // Mark everything as unintialized
  450. WanConfigDbaseInitialized = FALSE;
  451. RELEASE_DATABASE_LOCK;
  452. return NO_ERROR;
  453. }