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.

3990 lines
149 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\rtm\rtm.c
  5. Abstract:
  6. Routing Table Manager DLL. Main module
  7. Author:
  8. Vadim Eydelman
  9. Revision History:
  10. --*/
  11. #include "pchrtm.h"
  12. #pragma hdrstop
  13. /* ****** Global data ****** */
  14. // Tables themselves
  15. RTM_TABLE Tables[RTM_NUM_OF_PROTOCOL_FAMILIES];
  16. MASK_ENTRY g_meMaskTable[ MAX_MASKS + 1 ] =
  17. {
  18. { 0x00000000, 0 },
  19. { 0x00000001, 0 },
  20. { 0x00000003, 0 },
  21. { 0x00000007, 0 },
  22. { 0x0000000F, 0 },
  23. { 0x0000001F, 0 },
  24. { 0x0000003F, 0 },
  25. { 0x0000007F, 0 },
  26. { 0x000000FF, 0 },
  27. { 0x000080FF, 0 },
  28. { 0x0000C0FF, 0 },
  29. { 0x0000E0FF, 0 },
  30. { 0x0000F0FF, 0 },
  31. { 0x0000F8FF, 0 },
  32. { 0x0000FCFF, 0 },
  33. { 0x0000FEFF, 0 },
  34. { 0x0000FFFF, 0 },
  35. { 0x0080FFFF, 0 },
  36. { 0x00C0FFFF, 0 },
  37. { 0x00E0FFFF, 0 },
  38. { 0x00F0FFFF, 0 },
  39. { 0x00F8FFFF, 0 },
  40. { 0x00FCFFFF, 0 },
  41. { 0x00FEFFFF, 0 },
  42. { 0x00FFFFFF, 0 },
  43. { 0x80FFFFFF, 0 },
  44. { 0xC0FFFFFF, 0 },
  45. { 0xE0FFFFFF, 0 },
  46. { 0xF0FFFFFF, 0 },
  47. { 0xF8FFFFFF, 0 },
  48. { 0xFCFFFFFF, 0 },
  49. { 0xFEFFFFFF, 0 },
  50. { 0xFFFFFFFF, 0 }
  51. };
  52. #if DBG
  53. DWORD dbgThreadId;
  54. ULONG TracingHandle;
  55. DWORD TracingInited;
  56. HANDLE LoggingHandle;
  57. ULONG LoggingLevel;
  58. #endif
  59. /* ***** Internal Function Prototypes ******* */
  60. VOID
  61. NotifyClients (
  62. PRTM_TABLE Table,
  63. HANDLE ClientHandle,
  64. DWORD Flags,
  65. PRTM_XX_ROUTE CurBestRoute,
  66. PRTM_XX_ROUTE PrevBestRoute
  67. );
  68. VOID APIENTRY
  69. ConsolidateNetNumberListsWI (
  70. PVOID Context
  71. );
  72. VOID
  73. ConsolidateNetNumberLists (
  74. PRTM_TABLE Table
  75. );
  76. VOID APIENTRY
  77. ScheduleUpdate (
  78. PVOID Context
  79. );
  80. VOID APIENTRY
  81. ProcessExpirationQueueWI (
  82. PVOID Table
  83. );
  84. VOID
  85. ProcessExpirationQueue (
  86. PRTM_TABLE Table
  87. );
  88. DWORD
  89. ReadRegistry (
  90. void
  91. );
  92. DWORD
  93. DoEnumerate (
  94. PRTM_TABLE Table,
  95. PRTM_ENUMERATOR EnumPtr,
  96. DWORD EnableFlag
  97. );
  98. VOID
  99. SetMaskCount(
  100. PIP_NETWORK pinNet,
  101. BOOL bAdd
  102. );
  103. #if 0 // Replaced by RTMv2's DLLMain
  104. // DLL main function. Called by crtdll startup routine that is
  105. // designated as entry point for this dll.
  106. //
  107. // At startup (DLL_PROCESS_ATTACH): creates all tables and starts update
  108. // thread
  109. // At shutdown (DLL_PROCESS_DETACH): stops update thread and disposes of all
  110. // resources
  111. BOOL WINAPI DllMain(
  112. HINSTANCE hinstDLL, // DLL instance handle
  113. DWORD fdwReason, // Why is it called
  114. LPVOID lpvReserved
  115. ) {
  116. switch (fdwReason) {
  117. case DLL_PROCESS_ATTACH: // We are being attached to a new process
  118. // Create all we need to operate
  119. DisableThreadLibraryCalls (hinstDLL);
  120. return Rtmv1DllStartup(hinstDLL);
  121. case DLL_PROCESS_DETACH: // The process is exiting
  122. Rtmv1DllCleanup();
  123. default: // Not interested in all other cases
  124. return TRUE;
  125. break;
  126. }
  127. }
  128. #endif
  129. BOOL
  130. Rtmv1DllStartup (
  131. HINSTANCE hinstDLL // DLL instance handle
  132. )
  133. {
  134. DWORD i;
  135. // Create all we need to operate
  136. #if DBG
  137. RTDlgThreadHdl = CreateThread (
  138. NULL,
  139. 0,
  140. &RTDialogThread,
  141. (LPVOID)hinstDLL,
  142. 0,
  143. &dbgThreadId);
  144. ASSERTERR (RTDlgThreadHdl!=NULL);
  145. #endif
  146. for (i=0; i<RTM_NUM_OF_PROTOCOL_FAMILIES; i++) {
  147. Tables[i].RT_APIclientCount = RTM_CLIENT_STOP_TRESHHOLD;
  148. Tables[i].RT_Heap = NULL;
  149. }
  150. return TRUE;
  151. }
  152. VOID
  153. Rtmv1DllCleanup (
  154. )
  155. {
  156. DWORD status;
  157. DWORD i;
  158. #if DBG
  159. PostThreadMessage (dbgThreadId, WM_QUIT, 0, 0);
  160. status = WaitForSingleObject (RTDlgThreadHdl, 5*1000);
  161. //
  162. // Give some time to the RTDialogThread to process
  163. // the WM_QUIT message and exit.
  164. // If it is not quitting, its better to just
  165. // leave it alone rather than terminating it.
  166. //
  167. // if (status!=WAIT_OBJECT_0)
  168. // TerminateThread (RTDlgThreadHdl, 0);
  169. CloseHandle (RTDlgThreadHdl);
  170. // Deregister with tracing utils
  171. STOP_TRACING();
  172. #endif
  173. // Dispose of all resources
  174. for (i=0; i<RTM_NUM_OF_PROTOCOL_FAMILIES; i++) {
  175. if (Tables[i].RT_Heap!=NULL)
  176. RtmDeleteRouteTable (i);
  177. }
  178. return;
  179. }
  180. /*++
  181. *******************************************************************
  182. R t m C r e a t e R o u t e T a b l e
  183. Routine Description:
  184. Create route table for protocol family
  185. Arguments:
  186. ProtocolFamily - index that identifies protocol family
  187. Config - protocol family table configuration parameters
  188. Return Value:
  189. NO_ERROR - table was created ok
  190. ERROR_NOT_ENOUGH_MEMORY - could not allocate memory to perform
  191. the operation
  192. ERROR_NO_SYSTEM_RESOURCES - not enough resources to perform the operation,
  193. try again later
  194. *******************************************************************
  195. --*/
  196. DWORD
  197. RtmCreateRouteTable (
  198. IN DWORD ProtocolFamily,
  199. IN PRTM_PROTOCOL_FAMILY_CONFIG Config
  200. ) {
  201. INT i;
  202. DWORD status;
  203. PRTM_TABLE Table;
  204. #if DBG
  205. // Register with tracing utils
  206. START_TRACING();
  207. #endif
  208. if (ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES) {
  209. #if DBG
  210. Trace2 ( ANY,
  211. "Undefined Protocol Family.\n\tat line %ld of %s\n",
  212. __LINE__, __FILE__);
  213. #endif
  214. return ERROR_INVALID_PARAMETER;
  215. }
  216. Table = &Tables[ProtocolFamily];
  217. if (Table->RT_Heap!=NULL) {
  218. #if DBG
  219. Trace2 ( ANY,
  220. "Table already exists for protocol family\n\tat line %ld of %s\n",
  221. __LINE__, __FILE__);
  222. #endif
  223. return ERROR_ALREADY_EXISTS;
  224. }
  225. memcpy (&Table->RT_Config, Config, sizeof (Table->RT_Config));
  226. status = NtCreateTimer (&Table->RT_ExpirationTimer,
  227. TIMER_ALL_ACCESS,
  228. NULL,
  229. NotificationTimer);
  230. if (!NT_SUCCESS (status))
  231. return ERROR_NO_SYSTEM_RESOURCES;
  232. status = NtCreateTimer (&Table->RT_UpdateTimer,
  233. TIMER_ALL_ACCESS,
  234. NULL,
  235. NotificationTimer);
  236. if (!NT_SUCCESS (status)) {
  237. NtClose (Table->RT_ExpirationTimer);
  238. return ERROR_NO_SYSTEM_RESOURCES;
  239. }
  240. Table->RT_Heap = HeapCreate (0, 0, Table->RT_Config.RPFC_MaxTableSize);
  241. if (Table->RT_Heap==NULL) {
  242. NtClose (Table->RT_UpdateTimer);
  243. NtClose (Table->RT_ExpirationTimer);
  244. return ERROR_NOT_ENOUGH_MEMORY;
  245. }
  246. Table->RT_NetNumberHash = (PRTM_SYNC_LIST)HeapAlloc (
  247. Table->RT_Heap,
  248. 0,
  249. sizeof (RTM_SYNC_LIST)*Table->RT_HashTableSize);
  250. if (Table->RT_NetNumberHash==NULL) {
  251. status = GetLastError ();
  252. HeapDestroy (Table->RT_Heap);
  253. NtClose (Table->RT_UpdateTimer);
  254. NtClose (Table->RT_ExpirationTimer);
  255. return status;
  256. }
  257. Table->RT_InterfaceHash = (PRTM_SYNC_LIST)HeapAlloc (
  258. Table->RT_Heap,
  259. 0,
  260. sizeof (RTM_SYNC_LIST)*RTM_INTF_HASH_SIZE);
  261. if (Table->RT_InterfaceHash==NULL) {
  262. status = GetLastError ();
  263. HeapDestroy (Table->RT_Heap);
  264. NtClose (Table->RT_UpdateTimer);
  265. NtClose (Table->RT_ExpirationTimer);
  266. return status;
  267. }
  268. try {
  269. InitializeCriticalSection (&Table->RT_Lock);
  270. }
  271. except (EXCEPTION_EXECUTE_HANDLER) {
  272. return GetLastError();
  273. }
  274. Table->RT_SyncObjectList.Next = NULL;
  275. for (i=0; i<Table->RT_HashTableSize; i++)
  276. InitializeSyncList (&Table->RT_NetNumberHash[i]);
  277. for (i=0; i<RTM_INTF_HASH_SIZE; i++)
  278. InitializeSyncList (&Table->RT_InterfaceHash[i]);
  279. #if RTM_USE_PROTOCOL_LISTS
  280. InitializeSyncList (&Table->RT_ProtocolList);
  281. #endif
  282. InitializeSyncList (&Table->RT_NetNumberMasterList);
  283. InitializeSyncList (&Table->RT_NetNumberTempList);
  284. InitializeSyncList (&Table->RT_DeletedList);
  285. InitializeSyncList (&Table->RT_ExpirationQueue);
  286. InitializeSyncList (&Table->RT_RouteChangeQueue);
  287. InitializeSyncList (&Table->RT_ClientList);
  288. Table->RT_NetNumberTempCount = 0;
  289. Table->RT_DeletedNodesCount = 0;
  290. Table->RT_UpdateWorkerPending = -1;
  291. Table->RT_ExpirationWorkerPending = -1;
  292. Table->RT_NetworkCount = 0;
  293. Table->RT_NumOfMessages = 0;
  294. InterlockedIncrement (&Table->RT_UpdateWorkerPending);
  295. status = RtlQueueWorkItem (ScheduleUpdate, Table, WT_EXECUTEINIOTHREAD);
  296. ASSERTMSG ("Could not queue update scheduling work item ", status==STATUS_SUCCESS);
  297. Table->RT_APIclientCount = 0;
  298. return NO_ERROR;
  299. }
  300. /*++
  301. *******************************************************************
  302. R t m D e l e t e R o u t e T a b l e
  303. Routine Description:
  304. Dispose of all resources allocated for the route table
  305. Arguments:
  306. ProtocolFamily - index that identifies protocol family
  307. Return Value:
  308. NO_ERROR - table was deleted ok
  309. ERROR_INVALID_PARAMETER - no table to delete
  310. *******************************************************************
  311. --*/
  312. DWORD
  313. RtmDeleteRouteTable (
  314. DWORD ProtocolFamily
  315. ) {
  316. PSINGLE_LIST_ENTRY cur;
  317. PRTM_TABLE Table;
  318. LONG curAPIclientCount;
  319. if (ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES) {
  320. #if DBG
  321. Trace2 (ANY,
  322. "Undefined Protocol Family.\n\tat line %ld of %s\n",
  323. __LINE__, __FILE__);
  324. #endif
  325. return ERROR_INVALID_PARAMETER;
  326. }
  327. Table = &Tables[ProtocolFamily];
  328. if (Table->RT_Heap==NULL) {
  329. #if DBG
  330. Trace3 (ANY,
  331. "Table does not exist or already deleted for protocol family %d\n"
  332. "\tat line %ld of %s\n",
  333. ProtocolFamily, __LINE__, __FILE__);
  334. #endif
  335. return ERROR_INVALID_PARAMETER;
  336. }
  337. while (!IsListEmpty (&Table->RT_ClientList.RSL_Head)) {
  338. PRTM_CLIENT ClientPtr = CONTAINING_RECORD (
  339. Table->RT_ClientList.RSL_Head.Flink,
  340. RTM_CLIENT,
  341. RC_Link);
  342. RtmDeregisterClient ((HANDLE)ClientPtr);
  343. }
  344. curAPIclientCount = InterlockedExchange (&Table->RT_APIclientCount,
  345. RTM_CLIENT_STOP_TRESHHOLD)
  346. + RTM_CLIENT_STOP_TRESHHOLD;
  347. while (Table->RT_APIclientCount > curAPIclientCount)
  348. Sleep (100);
  349. while (InterlockedIncrement (&Table->RT_ExpirationWorkerPending)>0) {
  350. while (Table->RT_ExpirationWorkerPending!=-1)
  351. Sleep (100);
  352. }
  353. while (InterlockedIncrement (&Table->RT_UpdateWorkerPending)>0) {
  354. while (Table->RT_UpdateWorkerPending!=-1)
  355. Sleep (100);
  356. }
  357. NtCancelTimer (Table->RT_UpdateTimer, NULL);
  358. NtCancelTimer (Table->RT_ExpirationTimer, NULL);
  359. Sleep (100);
  360. NtClose (Table->RT_UpdateTimer);
  361. NtClose (Table->RT_ExpirationTimer);
  362. Sleep (100);
  363. cur = PopEntryList (&Table->RT_SyncObjectList);
  364. while (cur!=NULL) {
  365. GlobalFree (CONTAINING_RECORD (cur, RTM_SYNC_OBJECT, RSO_Link));
  366. cur = PopEntryList (&Table->RT_SyncObjectList);
  367. }
  368. HeapFree (Table->RT_Heap, 0, Table->RT_InterfaceHash);
  369. HeapFree (Table->RT_Heap, 0, Table->RT_NetNumberHash);
  370. HeapDestroy (Table->RT_Heap);
  371. Table->RT_Heap = NULL;
  372. DeleteCriticalSection (&Table->RT_Lock);
  373. return NO_ERROR;
  374. }
  375. // Registers client as a handler of specified protocol
  376. // Returns a HANDLE be used for all subsequent
  377. // calls to identify which Protocol Family and Routing Protocol
  378. // should be affected by the call
  379. // Returns NULL in case of failure. Call GetLastError () to obtain
  380. // extended error information.
  381. // Error codes:
  382. // ERROR_INVALID_PARAMETER - specified protocol family is not supported
  383. // ERROR_CLIENT_ALREADY_EXISTS - another client already registered
  384. // to handle specified protocol
  385. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  386. // ERROR_NOT_ENOUGH_MEMORY - not enough memory to allocate client control block
  387. HANDLE WINAPI
  388. RtmRegisterClient (
  389. IN DWORD ProtocolFamily, // IP, IPX, etc.
  390. IN DWORD RoutingProtocol, // RIP, OSPF, etc.
  391. IN HANDLE ChangeEvent OPTIONAL,// Notified when best
  392. // routes change in the table (see
  393. // RtmDequeueRouteChangeMessage
  394. IN DWORD Flags
  395. ) {
  396. HANDLE ClientHandle;
  397. #define ClientPtr ((PRTM_CLIENT)ClientHandle) // To access handle fields
  398. // in this routine
  399. PRTM_TABLE Table; // Table we associated with
  400. DWORD status; // Operation result
  401. PLIST_ENTRY cur;
  402. // Check if we have the table of interest
  403. Table = &Tables[ProtocolFamily];
  404. if ((ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES)
  405. || !EnterTableAPI (Table)) {
  406. #if DBG
  407. Trace2 (ANY,
  408. "Undefined Protocol Family.\n\tat line %ld of %s\n",
  409. __LINE__, __FILE__);
  410. #endif
  411. SetLastError (ERROR_INVALID_PARAMETER);
  412. return NULL;
  413. }
  414. if (Flags & (~RTM_PROTOCOL_SINGLE_ROUTE)) {
  415. #if DBG
  416. Trace2 (ANY,
  417. "Invalid registration flags\n\tat line %ld of %s\n",
  418. __LINE__, __FILE__);
  419. #endif
  420. ExitTableAPI(Table);
  421. SetLastError (ERROR_INVALID_PARAMETER);
  422. return NULL;
  423. }
  424. // Allocate handle and initialize basic fields
  425. ClientHandle = GlobalAlloc (GMEM_FIXED, sizeof (RTM_CLIENT));
  426. if (ClientHandle==NULL) {
  427. ExitTableAPI(Table);
  428. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  429. return NULL;
  430. }
  431. ClientPtr->RC_RoutingProtocol = RoutingProtocol;
  432. ClientPtr->RC_NotificationEvent = ChangeEvent;
  433. ClientPtr->RC_Flags = Flags;
  434. // Lock client list as we adding a new one
  435. if (!EnterSyncList (Table, &Table->RT_ClientList, TRUE)) {
  436. GlobalFree (ClientHandle);
  437. ExitTableAPI (Table);
  438. SetLastError (ERROR_NO_SYSTEM_RESOURCES);
  439. return NULL;
  440. }
  441. // Check if we have another client with same
  442. // Routing Protocol
  443. cur = Table->RT_ClientList.RSL_Head.Flink;
  444. while (cur!=&Table->RT_ClientList.RSL_Head) {
  445. PRTM_CLIENT node = CONTAINING_RECORD (cur,
  446. RTM_CLIENT,
  447. RC_Link);
  448. if (ClientPtr->RC_RoutingProtocol< node->RC_RoutingProtocol)
  449. break;
  450. else if (ClientPtr->RC_RoutingProtocol==node->RC_RoutingProtocol) {
  451. LeaveSyncList (Table, &Table->RT_ClientList);
  452. GlobalFree (ClientHandle);
  453. ExitTableAPI (Table);
  454. SetLastError (ERROR_CLIENT_ALREADY_EXISTS);
  455. return NULL;
  456. }
  457. cur = cur->Flink;
  458. }
  459. // Check if client needs notifications
  460. if (ChangeEvent!= NULL) {
  461. status = ResetEvent (ChangeEvent); // Nothing yet
  462. ASSERTERRMSG ("Can't reset client's event.", status);
  463. // Lock notification messages queue
  464. if (!EnterSyncList (Table, &Table->RT_RouteChangeQueue, TRUE)) {
  465. LeaveSyncList (Table, &Table->RT_ClientList);
  466. GlobalFree (ClientHandle);
  467. ExitTableAPI (Table);
  468. SetLastError (ERROR_NO_SYSTEM_RESOURCES);
  469. return NULL;
  470. }
  471. // Point to the end of the queue: ignore
  472. // all previous messages
  473. ClientPtr->RC_PendingMessage = &Table->RT_RouteChangeQueue.RSL_Head;
  474. LeaveSyncList (Table, &Table->RT_RouteChangeQueue);
  475. }
  476. // Add client to the list
  477. InsertTailList (cur, &ClientPtr->RC_Link);
  478. LeaveSyncList (Table, &Table->RT_ClientList);
  479. ClientPtr->RC_ProtocolFamily = ProtocolFamily|RTM_CLIENT_HANDLE_TAG;
  480. ExitTableAPI (Table);
  481. return ClientHandle;
  482. #undef ClientPtr
  483. }
  484. // Frees resources and the HANDLE allocated above.
  485. // Deletes all routes associated with Routing Protocol that was represented
  486. // by the handle
  487. // Returned error codes:
  488. // NO_ERROR - handle was disposed of ok
  489. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  490. // ERROR_NOT_ENOUGH_MEMORY - not enough memory to allocate client control block
  491. DWORD WINAPI
  492. RtmDeregisterClient (
  493. IN HANDLE ClientHandle
  494. ) {
  495. #define ClientPtr ((PRTM_CLIENT)ClientHandle) // To access handle fields
  496. // in this routine
  497. RTM_XX_ROUTE Route;
  498. PRTM_TABLE Table;
  499. DWORD ProtocolFamily;
  500. try {
  501. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  502. Table = &Tables[ProtocolFamily];
  503. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  504. && EnterTableAPI (Table))
  505. NOTHING;
  506. else
  507. return ERROR_INVALID_HANDLE;
  508. }
  509. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  510. EXCEPTION_EXECUTE_HANDLER :
  511. EXCEPTION_CONTINUE_SEARCH) {
  512. return ERROR_INVALID_HANDLE;
  513. }
  514. // Lock client list
  515. if (!EnterSyncList (Table, &Table->RT_ClientList, TRUE)) {
  516. ExitTableAPI (Table);
  517. return ERROR_NO_SYSTEM_RESOURCES;
  518. }
  519. // Check if we need to dispose of messages
  520. // still waiting for this client
  521. if (ClientPtr->RC_NotificationEvent!= NULL) {
  522. if (!EnterSyncList (Table, &Table->RT_RouteChangeQueue, TRUE)) {
  523. LeaveSyncList (Table, &Table->RT_ClientList);
  524. ExitTableAPI (Table);
  525. return ERROR_NO_SYSTEM_RESOURCES;
  526. }
  527. while (ClientPtr->RC_PendingMessage
  528. != &Table->RT_RouteChangeQueue.RSL_Head) {
  529. PRTM_ROUTE_CHANGE_NODE node = CONTAINING_RECORD (
  530. ClientPtr->RC_PendingMessage,
  531. RTM_ROUTE_CHANGE_NODE,
  532. RCN_Link);
  533. ClientPtr->RC_PendingMessage = ClientPtr->RC_PendingMessage->Flink;
  534. if (node->RCN_ResponsibleClient!=ClientHandle) {
  535. // Tell that we processed this message so it can be freed
  536. // if no more clients are interested
  537. node->RCN_ReferenceCount -= 1;
  538. if (node->RCN_ReferenceCount<=0) {
  539. RemoveEntryList (&node->RCN_Link);
  540. if (node->RCN_Route2!=NULL)
  541. HeapFree (Table->RT_Heap, 0, node->RCN_Route2);
  542. HeapFree (Table->RT_Heap, 0, node);
  543. }
  544. }
  545. }
  546. LeaveSyncList (Table, &Table->RT_RouteChangeQueue);
  547. }
  548. RemoveEntryList (&ClientPtr->RC_Link);
  549. LeaveSyncList (Table, &Table->RT_ClientList);
  550. {
  551. RTM_CLIENT DeadClient;
  552. DeadClient.RC_ProtocolFamily = ClientPtr->RC_ProtocolFamily;
  553. DeadClient.RC_RoutingProtocol = ClientPtr->RC_RoutingProtocol;
  554. // Invlaidate client's handle memory block
  555. ClientPtr->RC_ProtocolFamily ^= RTM_CLIENT_HANDLE_TAG;
  556. GlobalFree (ClientHandle);
  557. // Delete all routes associated with routing protocol
  558. // controled by the client
  559. RtmBlockDeleteRoutes ((HANDLE)&DeadClient, 0, &Route);
  560. }
  561. ExitTableAPI (Table);
  562. return NO_ERROR;
  563. #undef ClientPtr
  564. }
  565. // Dequeues and returns the first change message from the queue.
  566. // Should be called if NotificationEvent is signalled to retrieve
  567. // chage messages pending for the client
  568. // Change messages are generated if best route to some destination
  569. // or any of its routing parameters (metric or protocol specific fields)
  570. // get changed as the result of some route being added, deleted, updated,
  571. // disabled, reenabled, or aged out. Note that change in protocol specific fields
  572. // or in TimeToLive parameters do not produce notification messages
  573. // Returns NO_ERROR and resets the event if there are no more messages
  574. // pending for the client,
  575. // otherwise ERROR_MORE_MESSAGES is returned (client should keep calling
  576. // until NO_ERROR is returned)
  577. // ERROR_NO_MESSAGES will be returned if there were no messages
  578. // to return (can happen if called when event was not signalled)
  579. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  580. DWORD WINAPI
  581. RtmDequeueRouteChangeMessage (
  582. IN HANDLE ClientHandle, // Handle that identifies client
  583. OUT DWORD *Flags, // Flags that indentify what
  584. // is this message about:
  585. // RTM_ROUTE_ADDED - this message informs
  586. // of new route (CurBestRoute is filled with
  587. // this route parameters if provided)
  588. // RTM_ROUTE_DELETED - this message informs
  589. // that route was deleted (PrevBestRoute is
  590. // filled with this route parameters if provuded)
  591. // RTM_ROUTE_CHANGED - best route to some network has
  592. // changed, (CurBestRoute is filled with parameter
  593. // of route that became the best, PrevBestRoute is
  594. // filled with parameters of route that was best
  595. // before this change)
  596. OUT PVOID CurBestRoute OPTIONAL,
  597. OUT PVOID PrevBestRoute OPTIONAL
  598. ){
  599. #define ClientPtr ((PRTM_CLIENT)ClientHandle) // To access handle fields
  600. // in this routine
  601. PRTM_ROUTE_CHANGE_NODE node=NULL;
  602. DWORD status;
  603. PRTM_TABLE Table;
  604. DWORD ProtocolFamily;
  605. try {
  606. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  607. Table = &Tables[ProtocolFamily];
  608. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  609. && EnterTableAPI (Table))
  610. NOTHING;
  611. else
  612. return ERROR_INVALID_HANDLE;
  613. }
  614. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  615. EXCEPTION_EXECUTE_HANDLER :
  616. EXCEPTION_CONTINUE_SEARCH) {
  617. return ERROR_INVALID_HANDLE;
  618. }
  619. // Events are reported only to the clients that
  620. // requested them by providing notification event
  621. if (ClientPtr->RC_NotificationEvent==NULL) {
  622. #if DBG
  623. Trace2 (ANY,
  624. "Dequeue message is called by the client that did not provide."
  625. " notification event\n"
  626. "\tat line %ld of %s\n",
  627. __LINE__, __FILE__);
  628. #endif
  629. ExitTableAPI (Table);
  630. return ERROR_INVALID_HANDLE;
  631. }
  632. if (!EnterSyncList (Table, &Table->RT_RouteChangeQueue, TRUE)) {
  633. ExitTableAPI (Table);
  634. return ERROR_NO_SYSTEM_RESOURCES;
  635. }
  636. // Traverse the queue to find the message that was not caused
  637. // by client's actions
  638. while (ClientPtr->RC_PendingMessage
  639. != &Table->RT_RouteChangeQueue.RSL_Head) {
  640. node = CONTAINING_RECORD (ClientPtr->RC_PendingMessage,
  641. RTM_ROUTE_CHANGE_NODE,
  642. RCN_Link);
  643. if (node->RCN_ResponsibleClient!=ClientHandle)
  644. break;
  645. ClientPtr->RC_PendingMessage = ClientPtr->RC_PendingMessage->Flink;
  646. }
  647. if (ClientPtr->RC_PendingMessage!=&Table->RT_RouteChangeQueue.RSL_Head)
  648. ClientPtr->RC_PendingMessage = ClientPtr->RC_PendingMessage->Flink;
  649. else {
  650. // There must be a pending message or we should have been
  651. // called
  652. #if DBG
  653. Trace2 (ANY,
  654. "Dequeue message is called, but nothing is pending.\n"
  655. "\tat line %ld of %s\n",
  656. __LINE__, __FILE__);
  657. #endif
  658. status = ResetEvent (ClientPtr->RC_NotificationEvent);
  659. ASSERTERRMSG ("Can't reset client's event.", status);
  660. LeaveSyncList (Table, &Table->RT_RouteChangeQueue);
  661. ExitTableAPI (Table);
  662. return ERROR_NO_MESSAGES;
  663. }
  664. // Copy message to client's buffers
  665. *Flags = node->RCN_Flags;
  666. switch (node->RCN_Flags) {
  667. case RTM_ROUTE_CHANGED:
  668. if (ARGUMENT_PRESENT (PrevBestRoute))
  669. memcpy (PrevBestRoute, &node->RCN_Route2->RN_Route,
  670. Table->RT_RouteSize);
  671. break;
  672. case RTM_ROUTE_ADDED:
  673. if (ARGUMENT_PRESENT (CurBestRoute))
  674. memcpy (CurBestRoute, &node->RCN_Route1, Table->RT_RouteSize);
  675. break;
  676. case RTM_ROUTE_DELETED:
  677. if (ARGUMENT_PRESENT (PrevBestRoute))
  678. memcpy (PrevBestRoute, &node->RCN_Route1, Table->RT_RouteSize);
  679. break;
  680. default:
  681. ASSERTMSG ("Invalid message flag", FALSE);
  682. break;
  683. }
  684. // Tell that we processed this message so it can be freed if
  685. // no more clients are interested
  686. node->RCN_ReferenceCount -= 1;
  687. if (node->RCN_ReferenceCount<=0) {
  688. Table->RT_NumOfMessages -= 1;
  689. RemoveEntryList (&node->RCN_Link);
  690. if (node->RCN_Route2!=NULL)
  691. HeapFree (Table->RT_Heap, 0, node->RCN_Route2);
  692. HeapFree (Table->RT_Heap, 0, node);
  693. }
  694. // Traverse the queue to locate next pending message
  695. // (not caused by the client)
  696. while (ClientPtr->RC_PendingMessage
  697. != &Table->RT_RouteChangeQueue.RSL_Head) {
  698. node = CONTAINING_RECORD (ClientPtr->RC_PendingMessage,
  699. RTM_ROUTE_CHANGE_NODE,
  700. RCN_Link);
  701. if (node->RCN_ResponsibleClient!=ClientHandle)
  702. break;
  703. ClientPtr->RC_PendingMessage = ClientPtr->RC_PendingMessage->Flink;
  704. }
  705. if (ClientPtr->RC_PendingMessage==&Table->RT_RouteChangeQueue.RSL_Head) {
  706. // All pending messages are processed: reset the event
  707. status = ResetEvent (ClientPtr->RC_NotificationEvent);
  708. ASSERTERRMSG ("Can't reset client's event.", status);
  709. status = NO_ERROR;
  710. }
  711. else
  712. status = ERROR_MORE_MESSAGES;
  713. LeaveSyncList (Table, &Table->RT_RouteChangeQueue);
  714. ExitTableAPI (Table);
  715. return status;
  716. #undef ClientPtr
  717. }
  718. // Adds new route change message to the queue and notifies
  719. // all interesed clients
  720. VOID
  721. NotifyClients (
  722. PRTM_TABLE Table, // Table to which this change applies
  723. HANDLE ClientHandle, // Client that caused this change (can
  724. // be NULL if this is a result of
  725. // route aging)
  726. DWORD Flags, // Change message flags
  727. PRTM_XX_ROUTE CurBestRoute, // Current best route for the network
  728. PRTM_XX_ROUTE PrevBestRoute // Previous best route for the network
  729. ) {
  730. PRTM_ROUTE_CHANGE_NODE node;
  731. PLIST_ENTRY cur;
  732. BOOL nodeInserted = FALSE;
  733. (*Table->RT_Config.RPFC_Change) (Flags, CurBestRoute, PrevBestRoute);
  734. // Allocate and initialize queue node
  735. node = (PRTM_ROUTE_CHANGE_NODE)HeapAlloc (
  736. Table->RT_Heap,
  737. 0,
  738. FIELD_OFFSET (RTM_ROUTE_NODE, RN_Route)+Table->RT_RouteSize);
  739. if (node==NULL)
  740. return;
  741. if (Flags==RTM_ROUTE_CHANGED) {
  742. node->RCN_Route2 = (PRTM_ROUTE_NODE)HeapAlloc (
  743. Table->RT_Heap,
  744. 0,
  745. FIELD_OFFSET (RTM_ROUTE_NODE, RN_Route)+Table->RT_RouteSize);
  746. if (node->RCN_Route2==NULL) {
  747. HeapFree (Table->RT_Heap, 0, node);
  748. return;
  749. }
  750. }
  751. else
  752. node->RCN_Route2 = NULL;
  753. node->RCN_ReferenceCount = 0;
  754. node->RCN_ResponsibleClient = ClientHandle;
  755. node->RCN_Flags = Flags;
  756. switch (Flags) {
  757. case RTM_ROUTE_CHANGED:
  758. if (ARGUMENT_PRESENT (PrevBestRoute))
  759. memcpy (&node->RCN_Route2->RN_Route, PrevBestRoute,
  760. Table->RT_RouteSize);
  761. break;
  762. case RTM_ROUTE_ADDED:
  763. if (ARGUMENT_PRESENT (CurBestRoute))
  764. memcpy (&node->RCN_Route1, CurBestRoute, Table->RT_RouteSize);
  765. break;
  766. case RTM_ROUTE_DELETED:
  767. if (ARGUMENT_PRESENT (PrevBestRoute))
  768. memcpy (&node->RCN_Route1, PrevBestRoute, Table->RT_RouteSize);
  769. break;
  770. default:
  771. ASSERTMSG ("Invalid message flag", FALSE);
  772. break;
  773. }
  774. if (!EnterSyncList (Table, &Table->RT_ClientList, TRUE)) {
  775. if (node->RCN_Route2!=NULL)
  776. HeapFree (Table->RT_Heap, 0, node->RCN_Route2);
  777. HeapFree (Table->RT_Heap, 0, node);
  778. return ;
  779. }
  780. // Find and notify interested clients
  781. cur = Table->RT_ClientList.RSL_Head.Flink;
  782. if (!EnterSyncList (Table, &Table->RT_RouteChangeQueue, TRUE)) {
  783. LeaveSyncList (Table, &Table->RT_ClientList);
  784. if (node->RCN_Route2!=NULL)
  785. HeapFree (Table->RT_Heap, 0, node->RCN_Route2);
  786. HeapFree (Table->RT_Heap, 0, node);
  787. return ;
  788. }
  789. while (cur!=&Table->RT_ClientList.RSL_Head) {
  790. PRTM_CLIENT clientPtr = CONTAINING_RECORD (
  791. cur,
  792. RTM_CLIENT,
  793. RC_Link);
  794. if (((HANDLE)clientPtr!=ClientHandle)
  795. && (clientPtr->RC_NotificationEvent!=NULL)) {
  796. node->RCN_ReferenceCount += 1;
  797. if (node->RCN_ReferenceCount==1) {
  798. InsertTailList (&Table->RT_RouteChangeQueue.RSL_Head,
  799. &node->RCN_Link);
  800. Table->RT_NumOfMessages += 1;
  801. }
  802. if (clientPtr->RC_PendingMessage
  803. ==&Table->RT_RouteChangeQueue.RSL_Head) {
  804. BOOL res = SetEvent (clientPtr->RC_NotificationEvent);
  805. ASSERTERRMSG ("Can't set client notification event.", res);
  806. clientPtr->RC_PendingMessage = &node->RCN_Link;
  807. }
  808. else if ((Table->RT_NumOfMessages>RTM_MAX_ROUTE_CHANGE_MESSAGES)
  809. && (clientPtr->RC_PendingMessage==
  810. Table->RT_RouteChangeQueue.RSL_Head.Flink)) {
  811. PRTM_ROUTE_CHANGE_NODE firstNode = CONTAINING_RECORD (
  812. clientPtr->RC_PendingMessage,
  813. RTM_ROUTE_CHANGE_NODE,
  814. RCN_Link);
  815. #if DBG
  816. Trace3 (ANY,
  817. "Dequeueing message for 'lazy' client %lx.\n"
  818. "\tat line %ld of %s\n",
  819. (ULONG_PTR)clientPtr, __LINE__, __FILE__);
  820. #endif
  821. clientPtr->RC_PendingMessage =
  822. clientPtr->RC_PendingMessage->Flink;
  823. firstNode->RCN_ReferenceCount -= 1;
  824. if (firstNode->RCN_ReferenceCount==0) {
  825. Table->RT_NumOfMessages -= 1;
  826. RemoveEntryList (&firstNode->RCN_Link);
  827. if (firstNode->RCN_Route2!=NULL)
  828. HeapFree (Table->RT_Heap, 0, firstNode->RCN_Route2);
  829. HeapFree (Table->RT_Heap, 0, firstNode);
  830. }
  831. }
  832. }
  833. cur = cur->Flink;
  834. }
  835. if (node->RCN_ReferenceCount==0) {
  836. if (node->RCN_Route2!=NULL)
  837. HeapFree (Table->RT_Heap, 0, node->RCN_Route2);
  838. HeapFree (Table->RT_Heap, 0, node);
  839. }
  840. LeaveSyncList (Table, &Table->RT_RouteChangeQueue);
  841. LeaveSyncList (Table, &Table->RT_ClientList);
  842. }
  843. PRTM_ROUTE_NODE
  844. CreateRouteNode (
  845. PRTM_TABLE Table,
  846. PLIST_ENTRY hashLink,
  847. PLIST_ENTRY intfLink,
  848. BOOL intfLinkFinal,
  849. #if RTM_USE_PROTOCOL_LISTS
  850. PLIST_ENTRY protLink,
  851. BOOL protLinkFinal,
  852. #endif
  853. PRTM_SYNC_LIST hashBasket,
  854. PRTM_XX_ROUTE ROUTE
  855. ) {
  856. PRTM_SYNC_LIST intfBasket;
  857. PRTM_ROUTE_NODE theNode = (PRTM_ROUTE_NODE)HeapAlloc (Table->RT_Heap, 0,
  858. FIELD_OFFSET (RTM_ROUTE_NODE, RN_Route)+Table->RT_RouteSize);
  859. if (theNode==NULL) {
  860. #if DBG
  861. // Report error in debuging builds
  862. Trace2 (ANY,
  863. "Can't allocate route\n\tat line %ld of %s\n",
  864. __LINE__, __FILE__);
  865. #endif
  866. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  867. return NULL;
  868. }
  869. theNode->RN_Flags = RTM_NODE_FLAGS_INIT;
  870. theNode->RN_Hash = hashBasket;
  871. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  872. InitializeListEntry (&theNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
  873. // Make sure we can lock all list before adding
  874. // We'll keep them locked untill we are sure
  875. // that route can be added to prevent "partially
  876. // inserted" entries in case of memory allocation failure, etc.
  877. #if RTM_USE_PROTOCOL_LISTS
  878. if (!EnterSyncList (Table, &Table->RT_ProtocolList, TRUE)) {
  879. HeapFree (Table->RT_Heap, 0, theNode);
  880. SetLastError (ERROR_NO_SYSTEM_RESOURCES);
  881. return NULL;
  882. }
  883. if (protLink==NULL) {// If we haven't seen any entries with same
  884. // net number and protocol, we'll find the
  885. // protocol list and insert at the end
  886. protLink = FindProtocolList (Table, ROUTE->XX_PROTOCOL);
  887. if (protLink==NULL) {
  888. LeaveSyncList (Table, &Table->RT_ProtocolList);
  889. HeapFree (Table->RT_Heap, 0, theNode);
  890. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  891. return NULL;
  892. }
  893. }
  894. #endif
  895. intfBasket = &Table->RT_InterfaceHash[IntfHashFunction(Table,
  896. ROUTE->XX_INTERFACE)];
  897. if (!EnterSyncList (Table, intfBasket, TRUE)) {
  898. #if RTM_USE_PROTOCOL_LISTS
  899. LeaveSyncList (Table, &Table->RT_ProtocolList);
  900. #endif
  901. HeapFree (Table->RT_Heap, 0, theNode);
  902. SetLastError (ERROR_NO_SYSTEM_RESOURCES);
  903. return NULL;
  904. }
  905. if (intfLink==NULL) {
  906. intfLink = FindInterfaceList (intfBasket, ROUTE->XX_INTERFACE, TRUE);
  907. if (intfLink==NULL) {
  908. #if RTM_USE_PROTOCOL_LISTS
  909. LeaveSyncList (Table, &Table->RT_ProtocolList);
  910. #endif
  911. LeaveSyncList (Table, intfBasket);
  912. HeapFree (Table->RT_Heap, 0, theNode);
  913. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  914. return NULL;
  915. }
  916. }
  917. if (!EnterSyncList (Table, &Table->RT_NetNumberTempList, TRUE)) {
  918. LeaveSyncList (Table, intfBasket);
  919. #if RTM_USE_PROTOCOL_LISTS
  920. LeaveSyncList (Table, &Table->RT_ProtocolList);
  921. #endif
  922. HeapFree (Table->RT_Heap, 0, theNode);
  923. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  924. return NULL;
  925. }
  926. // Add route to hash basket list
  927. InsertTailList (hashLink, &theNode->RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  928. // Add route to protocol list
  929. #if RTM_USE_PROTOCOL_LISTS
  930. if (protLinkFinal) {
  931. InsertTailList (protLink,
  932. &theNode->RN_Links[RTM_PROTOCOL_LIST_LINK]);
  933. }
  934. else {
  935. InsertHeadList (protLink,
  936. &theNode->RN_Links[RTM_PROTOCOL_LIST_LINK]);
  937. }
  938. #endif
  939. // Add it to interface list
  940. if (intfLinkFinal) {
  941. InsertTailList (intfLink,
  942. &theNode->RN_Links[RTM_INTERFACE_LIST_LINK]);
  943. }
  944. else {
  945. InsertHeadList (intfLink,
  946. &theNode->RN_Links[RTM_INTERFACE_LIST_LINK]);
  947. }
  948. // We can now release interface and procotol lists
  949. // because we are sure that addition to net number sorted
  950. // list won't fail
  951. LeaveSyncList (Table, intfBasket);
  952. #if RTM_USE_PROTOCOL_LISTS
  953. LeaveSyncList (Table, &Table->RT_ProtocolList);
  954. #endif
  955. // Add route to temporary net number list (to be later moved
  956. // to the master list by the update thread)
  957. AddNetNumberListNode (Table, theNode);
  958. Table->RT_NetNumberTempCount += 1;
  959. if (Table->RT_NetNumberTempCount==RTM_TEMP_LIST_MAX_COUNT) {
  960. if (InterlockedIncrement (&Table->RT_UpdateWorkerPending)==0) {
  961. DWORD status;
  962. status = RtlQueueWorkItem (ConsolidateNetNumberListsWI, Table, 0);
  963. ASSERTERRMSG ("Can't queue update work item", status==STATUS_SUCCESS);
  964. }
  965. }
  966. LeaveSyncList (Table, &Table->RT_NetNumberTempList);
  967. return theNode;
  968. }
  969. DWORD
  970. RemoveRouteNode (
  971. PRTM_TABLE Table,
  972. PRTM_ROUTE_NODE theNode
  973. ) {
  974. PLIST_ENTRY head;
  975. PRTM_SYNC_LIST intfBasket
  976. = &Table->RT_InterfaceHash[IntfHashFunction(Table,
  977. theNode->RN_Route.XX_INTERFACE)];
  978. #if RTM_USE_PROTOCOL_LISTS
  979. if (!EnterSyncList (Table, &Table->RT_ProtocolList, TRUE)) {
  980. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  981. return ERROR_NO_SYSTEM_RESOURCES;
  982. }
  983. #endif
  984. if (!EnterSyncList (Table, intfBasket, TRUE)) {
  985. #if RTM_USE_PROTOCOL_LISTS
  986. LeaveSyncList (Table, &Table->RT_ProtocolList);
  987. #endif
  988. return ERROR_NO_SYSTEM_RESOURCES;
  989. }
  990. if (!EnterSyncList (Table, &Table->RT_ExpirationQueue, TRUE)) {
  991. LeaveSyncList (Table, intfBasket);
  992. #if RTM_USE_PROTOCOL_LISTS
  993. LeaveSyncList (Table, &Table->RT_ProtocolList);
  994. #endif
  995. return ERROR_NO_SYSTEM_RESOURCES;
  996. }
  997. if (!EnterSyncList (Table, &Table->RT_DeletedList, TRUE)) {
  998. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  999. LeaveSyncList (Table, intfBasket);
  1000. #if RTM_USE_PROTOCOL_LISTS
  1001. LeaveSyncList (Table, &Table->RT_ProtocolList);
  1002. #endif
  1003. return ERROR_NO_SYSTEM_RESOURCES;
  1004. }
  1005. // Remove node from the interface list
  1006. head = theNode->RN_Links[RTM_INTERFACE_LIST_LINK].Flink;
  1007. RemoveEntryList (&theNode->RN_Links[RTM_INTERFACE_LIST_LINK]);
  1008. if (IsListEmpty (head)) {
  1009. PRTM_INTERFACE_NODE intfNode = CONTAINING_RECORD (head,
  1010. RTM_INTERFACE_NODE,
  1011. IN_Head);
  1012. RemoveEntryList (&intfNode->IN_Link);
  1013. GlobalFree (intfNode);
  1014. }
  1015. LeaveSyncList (Table, intfBasket);
  1016. #if RTM_USE_PROTOCOL_LISTS
  1017. RemoveEntryList (&theNode->RN_Links[RTM_PROTOCOL_LIST_LINK]);
  1018. // Remove node from the protocol list
  1019. LeaveSyncList (Table, &Table->RT_ProtocolList);
  1020. #endif
  1021. // Remove form expiration queue if it was there
  1022. if (IsListEntry (&theNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK])) {
  1023. RemoveEntryList (&theNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
  1024. }
  1025. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  1026. // Remove node from the hash basket list
  1027. RemoveEntryList (&theNode->RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  1028. // let update thread take care of disposing
  1029. InsertHeadList (&Table->RT_DeletedList.RSL_Head,
  1030. &theNode->RN_Links[RTM_DELETED_LIST_LINK]);
  1031. Table->RT_DeletedNodesCount += 1;
  1032. if (Table->RT_DeletedNodesCount==RTM_DELETED_LIST_MAX_COUNT) {
  1033. if (InterlockedIncrement (&Table->RT_UpdateWorkerPending)==0) {
  1034. DWORD status = RtlQueueWorkItem (ConsolidateNetNumberListsWI, Table, 0);
  1035. ASSERTERRMSG ("Can't queue update work item", status==STATUS_SUCCESS);
  1036. }
  1037. }
  1038. LeaveSyncList (Table, &Table->RT_DeletedList);
  1039. return NO_ERROR;
  1040. }
  1041. // Adds a given route or updates metric, TimeToLive, and reserved fields
  1042. // if route with same net number, interface, routing protocol,
  1043. // and next hop address already exists in the table
  1044. // Returns:
  1045. // NO_ERROR - if route was added OK or
  1046. // ERROR_INVALID_PARAMETER - if Route contains invalid parameter (suh as
  1047. // protocol does not match client's protocol)
  1048. // ERROR_NOT_ENOUGH_MEMORY - if route can not be inserted because of memory
  1049. // allocation problem
  1050. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  1051. DWORD WINAPI
  1052. RtmAddRoute(
  1053. IN HANDLE ClientHandle, // Handle that identifies protocol family
  1054. // and routing protocol of the route
  1055. // to add/update (RoutingProtocol field
  1056. // of the Route parameter is ignored)
  1057. // and coordinates this operation with
  1058. // notifications
  1059. // through the event (notificanitons will not
  1060. // be sent to the caller)
  1061. IN PVOID Route, // Route to add
  1062. // Route fields used as input:
  1063. // Destination network
  1064. // Interface through which route was received
  1065. // Address of next hop router
  1066. // Three fields above combined with protocol id uniquely
  1067. // identify the route in the table
  1068. // Data specific to protocol family
  1069. // Protocol independent metric
  1070. // Any data specific to routing
  1071. // protocol (subject to size limitation
  1072. // defined by PROTOCOL_SPECIFIC_DATA
  1073. // structure above)
  1074. IN DWORD TimeToLive, // In seconds. INFINITE if route is not to
  1075. // be aged out. The maximum value for
  1076. // this parameter is 2147483 sec (that
  1077. // is 24+ days)
  1078. OUT DWORD *Flags, // If added/updated route is the best route to the
  1079. // destination RTM_CURRENT_BEST_ROUTE will be set,
  1080. // AND if added/updated route changed (or
  1081. // replaced alltogether) previous
  1082. // best route info for the destination,
  1083. // RTM_PREVIOUS_BEST_ROUTE will be set
  1084. OUT PVOID CurBestRoute OPTIONAL,// This buffer (if present) will
  1085. // receive the route that became the best as
  1086. // the result of this addition/update if
  1087. // RTM_CURRENT_BEST_ROUTE is set
  1088. OUT PVOID PrevBestRoute OPTIONAL// This buffer (if present) will
  1089. // receive the route that was the best before
  1090. // this addition/update if
  1091. // RTM_PREVIOUS_BEST_ROUTE is set
  1092. ) {
  1093. #define ROUTE ((PRTM_XX_ROUTE)Route)
  1094. #define ClientPtr ((PRTM_CLIENT)ClientHandle)
  1095. DWORD status; // Operation result
  1096. INT res; // Comparison result
  1097. PRTM_SYNC_LIST hashBasket; // Hash basket to which added route
  1098. // belongs
  1099. // Links in all mantained lists for added route
  1100. PLIST_ENTRY cur, hashLink=NULL, intfLink=NULL, protLink=NULL;
  1101. // Node created for added route and best node for the
  1102. // network
  1103. PRTM_ROUTE_NODE theNode=NULL, curBestNode=NULL;
  1104. // Flags that indicate that corresponing links are determined
  1105. BOOL intfLinkFinal=FALSE;
  1106. #if RTM_USE_PROTOCOL_LISTS
  1107. BOOL protLinkFinal=FALSE;
  1108. #endif
  1109. BOOL newRoute=FALSE, updatedRoute=FALSE;
  1110. PRTM_TABLE Table;
  1111. DWORD ProtocolFamily;
  1112. try {
  1113. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  1114. Table = &Tables[ProtocolFamily];
  1115. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  1116. && EnterTableAPI (Table))
  1117. NOTHING;
  1118. else
  1119. return ERROR_INVALID_HANDLE;
  1120. }
  1121. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1122. EXCEPTION_EXECUTE_HANDLER :
  1123. EXCEPTION_CONTINUE_SEARCH) {
  1124. return ERROR_INVALID_HANDLE;
  1125. }
  1126. ROUTE->XX_PROTOCOL = ClientPtr->RC_RoutingProtocol;
  1127. GetSystemTimeAsFileTime (&ROUTE->XX_TIMESTAMP);
  1128. status = ValidateRoute (Table, ROUTE);
  1129. if (status!=NO_ERROR)
  1130. return status;
  1131. // Find and lock the hash basket for added route
  1132. hashBasket = &Table->RT_NetNumberHash [HashFunction (Table,
  1133. ((char *)ROUTE)
  1134. +sizeof(RTM_XX_ROUTE))];
  1135. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  1136. ExitTableAPI(Table);
  1137. return ERROR_NO_SYSTEM_RESOURCES;
  1138. }
  1139. // Traverse the list attached to the hash basket to
  1140. // find proper place for added route (entries in hash
  1141. // basket are ordered by network number and metric
  1142. cur = hashBasket->RSL_Head.Flink;
  1143. while (cur!=&hashBasket->RSL_Head) {
  1144. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  1145. cur,
  1146. RTM_ROUTE_NODE,
  1147. RN_Links[RTM_NET_NUMBER_HASH_LINK]
  1148. );
  1149. if (!IsEnumerator (node)) {
  1150. // Check if network numbers match
  1151. res = NetNumCmp (Table, ROUTE, &node->RN_Route);
  1152. if (res==0) { // We found block of entries with same net number
  1153. // We'll have to look through all of them
  1154. // Check all parameters of the node to see if we already
  1155. // have this route and this is just an update
  1156. if ((hashLink==NULL) && (theNode==NULL)) {
  1157. if (ROUTE->XX_PROTOCOL
  1158. == node->RN_Route.XX_PROTOCOL) {
  1159. if (ClientPtr->RC_Flags&RTM_PROTOCOL_SINGLE_ROUTE)
  1160. theNode = node;
  1161. else if (ROUTE->XX_INTERFACE
  1162. == node->RN_Route.XX_INTERFACE) {
  1163. res = NextHopCmp (Table, ROUTE, &node->RN_Route);
  1164. if (res == 0)
  1165. theNode = node;
  1166. else if (res < 0)
  1167. hashLink = cur;
  1168. }
  1169. else if (ROUTE->XX_INTERFACE
  1170. < node->RN_Route.XX_INTERFACE)
  1171. hashLink = cur;
  1172. }
  1173. else if (ROUTE->XX_PROTOCOL
  1174. < node->RN_Route.XX_PROTOCOL)
  1175. hashLink = cur;
  1176. }
  1177. // Just looking for current best route
  1178. // (not including added/updated route)
  1179. if ((node!=theNode)
  1180. && IsEnabled(node)
  1181. && ((curBestNode==NULL)
  1182. || IsBest(node)
  1183. || (MetricCmp (Table,
  1184. &curBestNode->RN_Route,
  1185. &node->RN_Route)>0)))
  1186. curBestNode = node;
  1187. // We have to check all entries with same net number
  1188. // anyway (to find the best route), so we might as
  1189. // well find links for the added route in protocol
  1190. // and interface list if such links exist (if not, we'll
  1191. // just insert new entry at the end of the list)
  1192. #if RTM_USE_PROTOCOL_LISTS
  1193. // If we need and haven't found yet a proper place to
  1194. // insert added route into the protocol list and this route
  1195. // has the same protocol as added route we should
  1196. // consider it.
  1197. if (!protLinkFinal && (theNode==NULL)
  1198. && (ROUTE->XX_PROTOCOL
  1199. ==node->RN_Route.XX_PROTOCOL)) {
  1200. protLink = &node->RN_Links[RTM_PROTOCOL_LIST_LINK];
  1201. // If added route has lower interface number than
  1202. // this one we'll insert it in protocol list right
  1203. // BEFORE this one, otherwise
  1204. // we are not sure if this is a proper place yet (there
  1205. // may be other routes with same protocol that have
  1206. // lower interface number), but we note the position
  1207. // and insert added route right AFTER this one if there
  1208. // are no more routes of this protocol.
  1209. protLinkFinal = ROUTE->XX_INTERFACE
  1210. < node->RN_Route.XX_INTERFACE;
  1211. }
  1212. #endif
  1213. // Same story with the interface list
  1214. if (!intfLinkFinal
  1215. && (ROUTE->XX_INTERFACE
  1216. ==node->RN_Route.XX_INTERFACE)) {
  1217. intfLink = &node->RN_Links[RTM_INTERFACE_LIST_LINK];
  1218. intfLinkFinal = ROUTE->XX_PROTOCOL
  1219. < node->RN_Route.XX_PROTOCOL;
  1220. }
  1221. }
  1222. else if (res < 0) // We must have seen all entries with
  1223. // matching network number -> nothing
  1224. // to look for anymore
  1225. break;
  1226. }
  1227. cur = cur->Flink;
  1228. }
  1229. if (theNode!=NULL) {
  1230. // We found the route, so just need to update its parameters
  1231. if (ClientPtr->RC_Flags&RTM_PROTOCOL_SINGLE_ROUTE) {
  1232. updatedRoute = (MetricCmp (Table, &theNode->RN_Route, ROUTE)!=0)
  1233. || (theNode->RN_Route.XX_INTERFACE!=ROUTE->XX_INTERFACE)
  1234. || (NextHopCmp (Table, &theNode->RN_Route, ROUTE)!=0)
  1235. || !FSDCmp (Table, &theNode->RN_Route, ROUTE);
  1236. if (ROUTE->XX_INTERFACE!=theNode->RN_Route.XX_INTERFACE) {
  1237. PRTM_SYNC_LIST intfBasketOld
  1238. = &Table->RT_InterfaceHash[IntfHashFunction(Table,
  1239. theNode->RN_Route.XX_INTERFACE)];
  1240. PRTM_SYNC_LIST intfBasketNew
  1241. = &Table->RT_InterfaceHash[IntfHashFunction(Table,
  1242. ROUTE->XX_INTERFACE)];
  1243. // Make sure we lock interface hash table basket
  1244. // in the same order to prevent possible deadlock
  1245. if (intfBasketOld<intfBasketNew) {
  1246. if (!EnterSyncList (Table, intfBasketOld, TRUE)) {
  1247. status = ERROR_NO_SYSTEM_RESOURCES;
  1248. goto ExitAddRoute;
  1249. }
  1250. if (!EnterSyncList (Table, intfBasketNew, TRUE)) {
  1251. LeaveSyncList (Table, intfBasketOld);
  1252. status = ERROR_NO_SYSTEM_RESOURCES;
  1253. goto ExitAddRoute;
  1254. }
  1255. }
  1256. else if (intfBasketOld>intfBasketNew) {
  1257. if (!EnterSyncList (Table, intfBasketNew, TRUE)) {
  1258. status = ERROR_NO_SYSTEM_RESOURCES;
  1259. goto ExitAddRoute;
  1260. }
  1261. if (!EnterSyncList (Table, intfBasketOld, TRUE)) {
  1262. LeaveSyncList (Table, intfBasketOld);
  1263. status = ERROR_NO_SYSTEM_RESOURCES;
  1264. goto ExitAddRoute;
  1265. }
  1266. }
  1267. else {
  1268. if (!EnterSyncList (Table, intfBasketOld, TRUE)) {
  1269. status = ERROR_NO_SYSTEM_RESOURCES;
  1270. goto ExitAddRoute;
  1271. }
  1272. }
  1273. if (intfLink==NULL) {
  1274. intfLink = FindInterfaceList (intfBasketNew, ROUTE->XX_INTERFACE, TRUE);
  1275. if (intfLink==NULL) {
  1276. status = ERROR_NOT_ENOUGH_MEMORY;
  1277. LeaveSyncList (Table, intfBasketOld);
  1278. if (intfBasketNew!=intfBasketOld)
  1279. LeaveSyncList (Table, intfBasketNew);
  1280. goto ExitAddRoute;
  1281. }
  1282. }
  1283. // Add it to interface list
  1284. RemoveEntryList (&theNode->RN_Links[RTM_INTERFACE_LIST_LINK]);
  1285. InsertTailList (intfLink,
  1286. &theNode->RN_Links[RTM_INTERFACE_LIST_LINK]);
  1287. LeaveSyncList (Table, intfBasketOld);
  1288. if (intfBasketNew!=intfBasketOld)
  1289. LeaveSyncList (Table, intfBasketNew);
  1290. }
  1291. }
  1292. else
  1293. updatedRoute = MetricCmp (Table, &theNode->RN_Route, ROUTE)
  1294. || !FSDCmp (Table, &theNode->RN_Route, ROUTE)!=0;
  1295. }
  1296. else /*if (theNode==NULL)*/ { // We haven't found matching route,
  1297. // so we'll add a new one
  1298. // If we were not able to find place to insert added route
  1299. // into the list, we use the place where we stop
  1300. // the search (it is either end of the list or
  1301. // network with higher number if we did not see our
  1302. // network or all other entries had lower metric
  1303. if (hashLink==NULL)
  1304. hashLink = cur;
  1305. theNode = CreateRouteNode (Table,
  1306. hashLink,
  1307. intfLink,
  1308. intfLinkFinal,
  1309. #if RTM_USE_PROTOCOL_LISTS
  1310. protLink,
  1311. protLinkFinal,
  1312. #endif
  1313. hashBasket,
  1314. ROUTE);
  1315. if (theNode==NULL) {
  1316. status = GetLastError ();
  1317. goto ExitAddRoute;
  1318. }
  1319. if (curBestNode==NULL) {
  1320. InterlockedIncrement (&Table->RT_NetworkCount);
  1321. SetBest (theNode); // This is the first
  1322. // route to the network, and thus
  1323. // it is the best.
  1324. newRoute = TRUE;
  1325. }
  1326. else {
  1327. newRoute = FALSE;
  1328. }
  1329. }
  1330. // All routes (new or old) need to be placed into the Expiration list
  1331. // to be properly aged out
  1332. if (!EnterSyncList (Table, &Table->RT_ExpirationQueue, TRUE)) {
  1333. status = ERROR_NO_SYSTEM_RESOURCES;
  1334. goto ExitAddRoute;
  1335. }
  1336. if (IsListEntry (&theNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK])) {
  1337. RemoveEntryList (&theNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
  1338. }
  1339. if (TimeToLive!=INFINITE) {
  1340. TimeToLive *= 1000;
  1341. if (TimeToLive > (MAXTICKS/2-1))
  1342. TimeToLive = MAXTICKS/2-1;
  1343. theNode->RN_ExpirationTime = (GetTickCount () + TimeToLive)&0xFFFFFF00;
  1344. if (AddExpirationQueueNode (Table, theNode)) {
  1345. if (InterlockedIncrement (&Table->RT_ExpirationWorkerPending)==0) {
  1346. // New route expiration time comes before the update thread
  1347. // is scheduled to wakeup next time, so wake it up NOW
  1348. status = RtlQueueWorkItem (ProcessExpirationQueueWI, Table,
  1349. WT_EXECUTEINIOTHREAD);
  1350. ASSERTERRMSG ("Can't queue expiration work item", status==STATUS_SUCCESS);
  1351. }
  1352. }
  1353. }
  1354. else
  1355. // Initilaize this list link, so we know it is not
  1356. // in the list and we do not have to remove it from
  1357. // there
  1358. InitializeListEntry (&theNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
  1359. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  1360. if (!IsEnabled(theNode)) {// Ignore disabled nodes
  1361. if (updatedRoute)
  1362. // Update the route data
  1363. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1364. else {
  1365. memcpy (&theNode->RN_Route.XX_TIMESTAMP,
  1366. &ROUTE->XX_TIMESTAMP,
  1367. sizeof (theNode->RN_Route.XX_TIMESTAMP));
  1368. memcpy (&theNode->RN_Route.XX_PSD,
  1369. &ROUTE->XX_PSD,
  1370. sizeof (theNode->RN_Route.XX_PSD));
  1371. }
  1372. *Flags = 0;
  1373. }
  1374. else if (curBestNode!=NULL) { // There is at least one other route to the
  1375. // same network as the route we're adding/updating
  1376. if (MetricCmp (Table, ROUTE, &curBestNode->RN_Route)<0) {
  1377. // Added/updated route metric is lower, it is the best
  1378. if (!IsBest(theNode)) {// The best route has changed, we need to
  1379. // update best route designation
  1380. ResetBest (curBestNode);
  1381. SetBest (theNode);
  1382. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1383. // include previous best route info
  1384. // in notificaion message
  1385. *Flags = RTM_PREVIOUS_BEST_ROUTE|RTM_CURRENT_BEST_ROUTE;
  1386. if (ARGUMENT_PRESENT (CurBestRoute))
  1387. memcpy (CurBestRoute, ROUTE, Table->RT_RouteSize);
  1388. if (ARGUMENT_PRESENT (PrevBestRoute))
  1389. memcpy (PrevBestRoute, &curBestNode->RN_Route, Table->RT_RouteSize);
  1390. NotifyClients (Table, ClientHandle, *Flags, ROUTE,
  1391. &curBestNode->RN_Route);
  1392. }
  1393. else {
  1394. if (updatedRoute) {
  1395. *Flags = RTM_PREVIOUS_BEST_ROUTE|RTM_CURRENT_BEST_ROUTE;
  1396. if (ARGUMENT_PRESENT (CurBestRoute))
  1397. memcpy (CurBestRoute, ROUTE, Table->RT_RouteSize);
  1398. if (ARGUMENT_PRESENT (PrevBestRoute))
  1399. memcpy (PrevBestRoute, &theNode->RN_Route, Table->RT_RouteSize);
  1400. NotifyClients (Table, ClientHandle, *Flags, ROUTE, &theNode->RN_Route);
  1401. // Update the route data
  1402. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1403. }
  1404. else {
  1405. memcpy (&theNode->RN_Route.XX_TIMESTAMP,
  1406. &ROUTE->XX_TIMESTAMP,
  1407. sizeof (theNode->RN_Route.XX_TIMESTAMP));
  1408. memcpy (&theNode->RN_Route.XX_PSD,
  1409. &ROUTE->XX_PSD,
  1410. sizeof (theNode->RN_Route.XX_PSD));
  1411. }
  1412. }
  1413. }
  1414. else if (IsBest(theNode)) {
  1415. if (MetricCmp (Table, ROUTE, &curBestNode->RN_Route)>0) {
  1416. // We are downgrading our best route,
  1417. // and new best route poped up.
  1418. // Update best route designation
  1419. ResetBest (theNode);
  1420. SetBest (curBestNode);
  1421. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1422. // Inform clients about the change
  1423. *Flags = RTM_CURRENT_BEST_ROUTE | RTM_PREVIOUS_BEST_ROUTE;
  1424. if (ARGUMENT_PRESENT (PrevBestRoute))
  1425. memcpy (PrevBestRoute, &curBestNode->RN_Route, Table->RT_RouteSize);
  1426. if (ARGUMENT_PRESENT (CurBestRoute))
  1427. memcpy (CurBestRoute, ROUTE, Table->RT_RouteSize);
  1428. NotifyClients (Table, ClientHandle, *Flags, &curBestNode->RN_Route,
  1429. ROUTE);
  1430. }
  1431. else if (updatedRoute) {
  1432. *Flags = RTM_PREVIOUS_BEST_ROUTE|RTM_CURRENT_BEST_ROUTE;
  1433. if (ARGUMENT_PRESENT (CurBestRoute))
  1434. memcpy (CurBestRoute, ROUTE, Table->RT_RouteSize);
  1435. if (ARGUMENT_PRESENT (PrevBestRoute))
  1436. memcpy (PrevBestRoute, &theNode->RN_Route, Table->RT_RouteSize);
  1437. NotifyClients (Table, ClientHandle, *Flags, ROUTE, &theNode->RN_Route);
  1438. // Update the route data
  1439. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1440. }
  1441. else {
  1442. memcpy (&theNode->RN_Route.XX_TIMESTAMP,
  1443. &ROUTE->XX_TIMESTAMP,
  1444. sizeof (theNode->RN_Route.XX_TIMESTAMP));
  1445. memcpy (&theNode->RN_Route.XX_PSD,
  1446. &ROUTE->XX_PSD,
  1447. sizeof (theNode->RN_Route.XX_PSD));
  1448. }
  1449. }
  1450. else { // Added route metric was and is higher and thus has no
  1451. // effect on best route to the network
  1452. *Flags = 0;
  1453. // Update the route data
  1454. if (updatedRoute) {
  1455. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1456. }
  1457. else {
  1458. memcpy (&theNode->RN_Route.XX_TIMESTAMP,
  1459. &ROUTE->XX_TIMESTAMP,
  1460. sizeof (theNode->RN_Route.XX_TIMESTAMP));
  1461. memcpy (&theNode->RN_Route.XX_PSD,
  1462. &ROUTE->XX_PSD,
  1463. sizeof (theNode->RN_Route.XX_PSD));
  1464. }
  1465. }
  1466. }
  1467. else { // Not other node exist for this network
  1468. if (newRoute) {
  1469. *Flags = RTM_CURRENT_BEST_ROUTE;
  1470. if (ARGUMENT_PRESENT (CurBestRoute))
  1471. memcpy (CurBestRoute, ROUTE, Table->RT_RouteSize);
  1472. NotifyClients (Table, ClientHandle, *Flags, ROUTE, NULL);
  1473. }
  1474. else if (updatedRoute) {
  1475. *Flags = RTM_CURRENT_BEST_ROUTE | RTM_PREVIOUS_BEST_ROUTE;
  1476. if (ARGUMENT_PRESENT (CurBestRoute))
  1477. memcpy (CurBestRoute, ROUTE, Table->RT_RouteSize);
  1478. if (ARGUMENT_PRESENT (CurBestRoute))
  1479. memcpy (PrevBestRoute, &theNode->RN_Route, Table->RT_RouteSize);
  1480. NotifyClients (Table, ClientHandle, *Flags, ROUTE, &theNode->RN_Route);
  1481. // Update the route data
  1482. memcpy (&theNode->RN_Route, ROUTE, Table->RT_RouteSize);
  1483. }
  1484. else {
  1485. memcpy (&theNode->RN_Route.XX_TIMESTAMP,
  1486. &ROUTE->XX_TIMESTAMP,
  1487. sizeof (theNode->RN_Route.XX_TIMESTAMP));
  1488. memcpy (&theNode->RN_Route.XX_PSD,
  1489. &ROUTE->XX_PSD,
  1490. sizeof (theNode->RN_Route.XX_PSD));
  1491. *Flags = 0;
  1492. }
  1493. }
  1494. //
  1495. // for each new route added the size of the net mask is noted.
  1496. //
  1497. // This is useful at route lookup time. For now since there
  1498. // is no efficient way to do a route lookup, it is necessary to
  1499. // guess the (sub)net mask associated with a destination to find
  1500. // the best route associated with it. By tracking the net mask
  1501. // for each added route the number of guesses for the mask can
  1502. // be minimized.
  1503. //
  1504. if ( newRoute )
  1505. {
  1506. #if ROUTE_LOOKUP_BDG
  1507. TRACE2(
  1508. ANY, "Network : %x %x",
  1509. ((PIP_NETWORK) NNM(ROUTE))->N_NetNumber,
  1510. ((PIP_NETWORK) NNM(ROUTE))->N_NetMask
  1511. );
  1512. TRACE1(
  1513. ANY, "Next Hop : %x",
  1514. ((PRTM_IP_ROUTE) NNM(ROUTE))-> RR_NextHopAddress.N_NetNumber
  1515. );
  1516. #endif
  1517. SetMaskCount( (PIP_NETWORK) NNM( ROUTE ), TRUE );
  1518. }
  1519. status = NO_ERROR;
  1520. ExitAddRoute:
  1521. LeaveSyncList (Table, hashBasket);
  1522. ExitTableAPI(Table);
  1523. #undef ClientPtr
  1524. #undef ROUTE
  1525. return status;
  1526. }
  1527. // Deletes a given route
  1528. //
  1529. // Returns:
  1530. // NO_ERROR - if route was deleted OK or
  1531. // ERROR_NO_SUCH_ROUTE - if route to be deleted was not found in the table
  1532. DWORD WINAPI
  1533. RtmDeleteRoute (
  1534. IN HANDLE ClientHandle, // Handle to coordinate
  1535. // this operation with notifications
  1536. // through the event (notificanitons will not
  1537. // be sent to the caller)
  1538. IN PVOID Route, // ROUTE to delete
  1539. OUT DWORD *Flags, // If deleted route was the best
  1540. // route, RTM_PREVIOUS_BEST_ROUTE will be set
  1541. // AND if there is another route for the same
  1542. // network, RTM_CURRENT_BEST_ROUTE will be set
  1543. OUT PVOID CurBestRoute OPTIONAL// // This buffer will (optionally) receive
  1544. // the best route for the same network
  1545. // if RTM_CURRENT_BEST_ROUTE is set
  1546. ) {
  1547. #define ROUTE ((PRTM_XX_ROUTE)Route)
  1548. #define ClientPtr ((PRTM_CLIENT)ClientHandle)
  1549. DWORD status; // Operation result
  1550. INT res; // Comparison result
  1551. PRTM_SYNC_LIST hashBasket; // Hash basket to which the route belongs
  1552. PLIST_ENTRY cur;
  1553. PRTM_ROUTE_NODE theNode=NULL,// Table node associated with the route
  1554. curBestNode=NULL; // New best route for the
  1555. // network which route is deleted
  1556. // (if any)
  1557. PRTM_TABLE Table;
  1558. DWORD ProtocolFamily;
  1559. try {
  1560. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  1561. Table = &Tables[ProtocolFamily];
  1562. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  1563. && EnterTableAPI (Table))
  1564. NOTHING;
  1565. else
  1566. return ERROR_INVALID_HANDLE;
  1567. }
  1568. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1569. EXCEPTION_EXECUTE_HANDLER :
  1570. EXCEPTION_CONTINUE_SEARCH) {
  1571. return ERROR_INVALID_HANDLE;
  1572. }
  1573. ROUTE->XX_PROTOCOL = ClientPtr->RC_RoutingProtocol;
  1574. // Try locate the node in hash basket
  1575. hashBasket = &Table->RT_NetNumberHash [HashFunction (Table,
  1576. ((char *)ROUTE)
  1577. +sizeof(RTM_XX_ROUTE))];
  1578. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  1579. ExitTableAPI (Table);
  1580. return ERROR_NO_SYSTEM_RESOURCES;
  1581. }
  1582. cur = hashBasket->RSL_Head.Flink;
  1583. while (cur!=&hashBasket->RSL_Head) {
  1584. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  1585. cur,
  1586. RTM_ROUTE_NODE,
  1587. RN_Links[RTM_NET_NUMBER_HASH_LINK]
  1588. );
  1589. if (!IsEnumerator (node)) {
  1590. // Check if network number matches
  1591. res = NetNumCmp (Table, ROUTE, &node->RN_Route);
  1592. if (res==0) {
  1593. // Go through entries for network of interest
  1594. // Try to locate the route to be deleted
  1595. if ((theNode==NULL)
  1596. && (ROUTE->XX_INTERFACE
  1597. == node->RN_Route.XX_INTERFACE)
  1598. && (ROUTE->XX_PROTOCOL
  1599. == node->RN_Route.XX_PROTOCOL)
  1600. && (NextHopCmp (Table, ROUTE, &node->RN_Route)
  1601. ==0)) {
  1602. theNode = node;
  1603. if (!IsBest(theNode))
  1604. break;
  1605. }
  1606. else if (IsEnabled(node)
  1607. && ((curBestNode==NULL)
  1608. || (MetricCmp (Table,
  1609. &curBestNode->RN_Route,
  1610. &node->RN_Route)>0)))
  1611. curBestNode = node;
  1612. }
  1613. else if (res < 0)
  1614. // We passed the place where routes for our
  1615. // network are located
  1616. break;
  1617. }
  1618. cur = cur->Flink;
  1619. }
  1620. if (theNode!=NULL) { // Yes, we found the node
  1621. if (IsBest(theNode)) { // And it was the best,
  1622. // inform interested clients
  1623. if (curBestNode!=NULL) { // There is another best node
  1624. ResetBest (theNode);
  1625. SetBest (curBestNode);
  1626. *Flags = RTM_CURRENT_BEST_ROUTE | RTM_PREVIOUS_BEST_ROUTE;
  1627. if (ARGUMENT_PRESENT(CurBestRoute))
  1628. memcpy (CurBestRoute, &curBestNode->RN_Route,
  1629. Table->RT_RouteSize);
  1630. NotifyClients (Table, ClientHandle, *Flags,
  1631. &curBestNode->RN_Route,
  1632. &theNode->RN_Route);
  1633. }
  1634. else { // This one was the only available node
  1635. InterlockedDecrement (&Table->RT_NetworkCount);
  1636. *Flags = RTM_PREVIOUS_BEST_ROUTE;
  1637. NotifyClients (Table, ClientHandle, *Flags, NULL, &theNode->RN_Route);
  1638. //
  1639. // Decrement mask count
  1640. //
  1641. SetMaskCount( (PIP_NETWORK) NNM( ROUTE ), FALSE );
  1642. }
  1643. }
  1644. else // This was not the best node, nobody cares
  1645. *Flags = 0;
  1646. status = RemoveRouteNode (Table, theNode);
  1647. }
  1648. else
  1649. // Well, we don't have this node already (aged out ?)
  1650. status = ERROR_NO_SUCH_ROUTE;
  1651. LeaveSyncList (Table, hashBasket);
  1652. ExitTableAPI (Table);
  1653. #undef ClientPtr
  1654. #undef ROUTE
  1655. return status;
  1656. }
  1657. // Check if route exists and return it if so.
  1658. // Returns:
  1659. // TRUE if route exists for the given network
  1660. // FALSE otherwise
  1661. // If one of the parameters is invalid, the function returns FALSE
  1662. // and GetLastError() returns ERROR_INVALID_PARAMETER
  1663. BOOL WINAPI
  1664. RtmIsRoute (
  1665. IN DWORD ProtocolFamily,
  1666. IN PVOID Network, // Network whose existence is being checked
  1667. OUT PVOID BestRoute OPTIONAL // Returns the best route if the network
  1668. // is found
  1669. ) {
  1670. INT res;
  1671. PRTM_TABLE Table;
  1672. PRTM_SYNC_LIST hashBasket;
  1673. PLIST_ENTRY cur;
  1674. PRTM_ROUTE_NODE bestNode = NULL;
  1675. BOOL result = FALSE;
  1676. Table = &Tables[ProtocolFamily];
  1677. if ((ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES)
  1678. || !EnterTableAPI (Table)) {
  1679. #if DBG
  1680. Trace2 (ANY,
  1681. "Undefined Protocol Family\n\tat line %ld of %s\n",
  1682. __LINE__, __FILE__);
  1683. #endif
  1684. SetLastError (ERROR_INVALID_PARAMETER);
  1685. return FALSE;
  1686. }
  1687. // Locate the network in the hash basket
  1688. hashBasket = &Table->RT_NetNumberHash[HashFunction (Table, Network)];
  1689. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  1690. ExitTableAPI (Table);
  1691. SetLastError (ERROR_NO_SYSTEM_RESOURCES);
  1692. return FALSE;
  1693. }
  1694. cur = hashBasket->RSL_Head.Flink;
  1695. while (cur!=&hashBasket->RSL_Head) {
  1696. PRTM_ROUTE_NODE node;
  1697. node = CONTAINING_RECORD (
  1698. cur,
  1699. RTM_ROUTE_NODE,
  1700. RN_Links[RTM_NET_NUMBER_HASH_LINK]
  1701. );
  1702. if (!IsEnumerator (node)
  1703. && IsEnabled(node)) {
  1704. res = (*Table->RT_Config.RPFC_NNcmp) (
  1705. Network,
  1706. NNM(&node->RN_Route));
  1707. if ((res == 0)
  1708. && IsBest(node)) {
  1709. bestNode = node;
  1710. break;
  1711. }
  1712. else if (res < 0)
  1713. break;
  1714. }
  1715. cur = cur->Flink;
  1716. }
  1717. if (bestNode!=NULL) { // We found a match
  1718. if (ARGUMENT_PRESENT(BestRoute)) {
  1719. memcpy (BestRoute, &bestNode->RN_Route, Table->RT_RouteSize);
  1720. }
  1721. LeaveSyncList (Table, hashBasket);
  1722. result = TRUE;
  1723. }
  1724. else {
  1725. // We don't have one (result is FALSE by default)
  1726. LeaveSyncList (Table, hashBasket);
  1727. // This is not an error condition, we just do not have it
  1728. SetLastError (NO_ERROR);
  1729. }
  1730. ExitTableAPI (Table);
  1731. return result;
  1732. }
  1733. // Gets number of networks with known routes for a specific protocol family
  1734. ULONG WINAPI
  1735. RtmGetNetworkCount (
  1736. IN DWORD ProtocolFamily
  1737. ) {
  1738. PRTM_TABLE Table;
  1739. Table = &Tables[ProtocolFamily];
  1740. if ((ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES)
  1741. || !EnterTableAPI (&Tables[ProtocolFamily])) {
  1742. #if DBG
  1743. Trace2 (ANY,
  1744. "Undefined Protocol Family\n\tat line %ld of %s\n",
  1745. __LINE__, __FILE__);
  1746. #endif
  1747. SetLastError (ERROR_INVALID_PARAMETER);
  1748. return 0;
  1749. }
  1750. ExitTableAPI (Table);
  1751. return Table->RT_NetworkCount;
  1752. }
  1753. // Gets route age (time since it was created or updated last) in seconds
  1754. // from its time stamp.
  1755. // Rtm time stamps routes whenever they are added or updated.
  1756. // Note: that information returned by this routine is actually
  1757. // derived from TimeStamp field of the route structure, so it
  1758. // returns valid results only if route structure passed to was
  1759. // actually filled by Rtm
  1760. // If value in TimeStamp field is invalid this routing returns 0xFFFFFFFF
  1761. ULONG WINAPI
  1762. RtmGetRouteAge (
  1763. IN PVOID Route
  1764. ) {
  1765. #define ROUTE ((PRTM_XX_ROUTE)Route)
  1766. ULONGLONG curTime;
  1767. GetSystemTimeAsFileTime ((FILETIME *)&curTime);
  1768. curTime -= *((PULONGLONG)&ROUTE->XX_TIMESTAMP);
  1769. if (((PULARGE_INTEGER)&curTime)->HighPart<10000000)
  1770. return (ULONG)(curTime/10000000);
  1771. else {
  1772. SetLastError (ERROR_INVALID_PARAMETER);
  1773. return 0xFFFFFFFF;
  1774. }
  1775. #undef ROUTE
  1776. }
  1777. // Creates enumeration handle to start scan by specified criteria.
  1778. // Places a dummy node in the beginning of the table.
  1779. // Returns NULL in case of failure. Call GetLastError () to get extended
  1780. // error information
  1781. // Error codes:
  1782. // ERROR_INVALID_PARAMETER - specified protocol family is not supported or
  1783. // undefined enumeration flag
  1784. // ERROR_NO_ROUTES - no routes exist with specified criteria
  1785. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  1786. // ERROR_NOT_ENOUGH_MEMORY - not enough memory to allocate client control block
  1787. HANDLE WINAPI
  1788. RtmCreateEnumerationHandle (
  1789. IN DWORD ProtocolFamily,
  1790. IN DWORD EnumerationFlags, // Limitation flags
  1791. IN PVOID CriteriaRoute // Criteria for limitation flags
  1792. // The following fields shout be set
  1793. // Protocol if interest if RTM_ONLY_THIS_PROTOCOL is set
  1794. // Network of interest if RTM_ONLY_THIS_NETWORK is set
  1795. // Interface of interest if RTM_ONLY_THIS_INTERFACE is set
  1796. ) {
  1797. #define ROUTE ((PRTM_XX_ROUTE)CriteriaRoute)
  1798. HANDLE EnumerationHandle;
  1799. #define EnumPtr ((PRTM_ENUMERATOR)EnumerationHandle) // To access fields
  1800. // in this routine
  1801. PRTM_TABLE Table;
  1802. Table = &Tables[ProtocolFamily];
  1803. if ((ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES)
  1804. || !EnterTableAPI (&Tables[ProtocolFamily])) {
  1805. #if DBG
  1806. Trace2 (ANY,
  1807. "Undefined Protocol Family\n\tat line %ld of %s\n",
  1808. __LINE__, __FILE__);
  1809. #endif
  1810. SetLastError (ERROR_INVALID_PARAMETER);
  1811. return NULL;
  1812. }
  1813. if (EnumerationFlags &
  1814. (~(RTM_ONLY_THIS_NETWORK|RTM_ONLY_THIS_INTERFACE
  1815. |RTM_ONLY_THIS_PROTOCOL|RTM_ONLY_BEST_ROUTES
  1816. |RTM_INCLUDE_DISABLED_ROUTES))) {
  1817. ExitTableAPI (Table);
  1818. SetLastError (ERROR_INVALID_PARAMETER);
  1819. return NULL;
  1820. }
  1821. // Allocate and initialize enumerator
  1822. EnumerationHandle = GlobalAlloc (GMEM_FIXED,
  1823. FIELD_OFFSET (RTM_ENUMERATOR, RE_Route)+Table->RT_RouteSize);
  1824. if (EnumerationHandle!=NULL) {
  1825. EnumPtr->RE_Flags = RTM_ENUMERATOR_FLAGS_INIT;
  1826. EnumPtr->RE_EnumerationFlags = EnumerationFlags;
  1827. if (EnumerationFlags
  1828. & (RTM_ONLY_THIS_NETWORK
  1829. |RTM_ONLY_THIS_INTERFACE
  1830. |RTM_ONLY_THIS_PROTOCOL))
  1831. memcpy (&EnumPtr->RE_Route, CriteriaRoute, Table->RT_RouteSize);
  1832. EnumPtr->RE_Hash = NULL;
  1833. EnumPtr->RE_Head = NULL;
  1834. // WHICH LIST TO USE ?
  1835. // In general we should have more interfaces than protocols,
  1836. // so:
  1837. // if they only want a specific interface, we'll use
  1838. // the interface list even if they want a specific protocol too
  1839. if (EnumerationFlags & RTM_ONLY_THIS_INTERFACE) {
  1840. EnumPtr->RE_Link = RTM_INTERFACE_LIST_LINK;
  1841. EnumPtr->RE_Lock = &Table->RT_InterfaceHash[IntfHashFunction(Table,
  1842. EnumPtr->RE_Route.XX_INTERFACE)];
  1843. if (EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  1844. EnumPtr->RE_Head = FindInterfaceList (EnumPtr->RE_Lock,
  1845. EnumPtr->RE_Route.XX_INTERFACE, FALSE);
  1846. if (EnumPtr->RE_Head!=NULL) {
  1847. InsertTailList (EnumPtr->RE_Head,
  1848. &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  1849. }
  1850. LeaveSyncList (Table, EnumPtr->RE_Lock);
  1851. }
  1852. }
  1853. #if RTM_USE_PROTOCOL_LISTS
  1854. else if (EnumerationFlags & RTM_ONLY_THIS_PROTOCOL) {
  1855. // if they only want a specific protocol, we'll use
  1856. // the protocol list
  1857. EnumPtr->RE_Link = RTM_PROTOCOL_LIST_LINK;
  1858. EnumPtr->RE_Lock = &Table->RT_ProtocolList;
  1859. if (EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  1860. EnumPtr->RE_Head = FindProtocolList (Table,
  1861. EnumPtr->RE_Route.XX_PROTOCOL, FALSE);
  1862. if (EnumPtr->RE_Head!=NULL) {
  1863. InsertTailList (EnumPtr->RE_Head,
  1864. &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  1865. }
  1866. LeaveSyncList (Table, EnumPtr->RE_Lock);
  1867. }
  1868. }
  1869. #endif
  1870. else {
  1871. // otherwise, we have to use hash table
  1872. EnumPtr->RE_Link = RTM_NET_NUMBER_HASH_LINK;
  1873. // Now, if they want a specific network,
  1874. // we'll only search in one hash basket
  1875. if (EnumerationFlags & RTM_ONLY_THIS_NETWORK) {
  1876. EnumPtr->RE_Lock = &Table->RT_NetNumberHash[HashFunction (
  1877. Table,
  1878. ((char *)ROUTE)
  1879. +sizeof(RTM_XX_ROUTE))];
  1880. if (EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  1881. if (!IsListEmpty (&EnumPtr->RE_Lock->RSL_Head)) {
  1882. EnumPtr->RE_Head = &EnumPtr->RE_Lock->RSL_Head;
  1883. InsertTailList (EnumPtr->RE_Head,
  1884. &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  1885. }
  1886. LeaveSyncList (Table, EnumPtr->RE_Lock);
  1887. }
  1888. }
  1889. else {
  1890. // Otherwise, we'll have to go through all of them
  1891. // starting with the first one
  1892. EnumPtr->RE_Lock = &Table->RT_NetNumberHash[0];
  1893. if (EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  1894. EnumPtr->RE_Head = &EnumPtr->RE_Lock->RSL_Head;
  1895. InsertTailList (EnumPtr->RE_Head,
  1896. &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  1897. LeaveSyncList (Table, EnumPtr->RE_Lock);
  1898. }
  1899. }
  1900. }
  1901. if (EnumPtr->RE_Head!=NULL)
  1902. EnumPtr->RE_ProtocolFamily = ProtocolFamily | RTM_CLIENT_HANDLE_TAG;
  1903. else {
  1904. GlobalFree (EnumerationHandle);
  1905. EnumerationHandle = NULL;
  1906. SetLastError (ERROR_NO_ROUTES);
  1907. }
  1908. }
  1909. ExitTableAPI (Table);
  1910. return EnumerationHandle;
  1911. #undef EnumPtr
  1912. }
  1913. // Returns first route that satisfies criteria of the enumeration handle
  1914. // and advances handle's dummy node past the returned route.
  1915. // Routes are not returned in any particular order.
  1916. // Returns
  1917. // NO_ERROR - if next route was found in the table acording
  1918. // to specified criteria
  1919. // ERROR_NO_MORE_ROUTES - when end of the table is reached,
  1920. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  1921. DWORD WINAPI
  1922. RtmEnumerateGetNextRoute (
  1923. IN HANDLE EnumerationHandle, // Handle returned by prev call
  1924. OUT PVOID Route // Next route found
  1925. ) {
  1926. #define EnumPtr ((PRTM_ENUMERATOR)EnumerationHandle) // To access fields
  1927. // in this routine
  1928. DWORD status;
  1929. PRTM_TABLE Table;
  1930. DWORD ProtocolFamily;
  1931. try {
  1932. ProtocolFamily = EnumPtr->RE_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  1933. Table = &Tables[ProtocolFamily];
  1934. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  1935. && EnterTableAPI (Table))
  1936. NOTHING;
  1937. else
  1938. return ERROR_INVALID_HANDLE;
  1939. }
  1940. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  1941. EXCEPTION_EXECUTE_HANDLER :
  1942. EXCEPTION_CONTINUE_SEARCH) {
  1943. return ERROR_INVALID_HANDLE;
  1944. }
  1945. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  1946. ExitTableAPI (Table);
  1947. return ERROR_NO_SYSTEM_RESOURCES;
  1948. }
  1949. status = DoEnumerate (Table, EnumPtr,
  1950. (EnumPtr->RE_EnumerationFlags&RTM_INCLUDE_DISABLED_ROUTES)
  1951. ? RTM_ANY_ENABLE_STATE
  1952. : RTM_ENABLED_NODE_FLAG);
  1953. if (status==NO_ERROR) {
  1954. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  1955. EnumPtr->RE_Links[EnumPtr->RE_Link].Flink,
  1956. RTM_ROUTE_NODE,
  1957. RN_Links[EnumPtr->RE_Link]
  1958. );
  1959. // Copy found route to the client's buffer
  1960. memcpy (Route, &node->RN_Route, Table->RT_RouteSize);
  1961. if (EnumPtr->RE_EnumerationFlags&RTM_ONLY_BEST_ROUTES) {
  1962. // Move past all entries of given network
  1963. // so we don't return more than one best route
  1964. // for same network in case best route gets reassigned
  1965. // while client is processing results of this call
  1966. // (because we enumerate in the direction opposite
  1967. // to the direction of insertion, new node can't
  1968. // be inserted before the enumerator)
  1969. PLIST_ENTRY cur = EnumPtr->RE_Links[EnumPtr->RE_Link].Blink;
  1970. while (cur!=EnumPtr->RE_Head) {
  1971. node = CONTAINING_RECORD (cur, RTM_ROUTE_NODE,
  1972. RN_Links[EnumPtr->RE_Link]);
  1973. if (!IsEnumerator (node)
  1974. && (NetNumCmp (Table, Route, &node->RN_Route)!=0))
  1975. break;
  1976. cur = cur->Blink;
  1977. }
  1978. RemoveEntryList (&EnumPtr->RE_Links[EnumPtr->RE_Link]);
  1979. InsertHeadList (cur, &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  1980. }
  1981. }
  1982. else if (status==ERROR_NO_MORE_ROUTES) {
  1983. // We are at the end of the list, nothing to return
  1984. ;
  1985. }
  1986. else {
  1987. // There was an error (DoEnumerate cleaned up everything itself)
  1988. ExitTableAPI (Table);
  1989. return status;
  1990. }
  1991. if (EnumPtr->RE_Hash!=NULL) {
  1992. LeaveSyncList (Table, EnumPtr->RE_Hash);
  1993. EnumPtr->RE_Hash = NULL;
  1994. }
  1995. LeaveSyncList (Table, EnumPtr->RE_Lock);
  1996. ExitTableAPI (Table);
  1997. return status;
  1998. #undef EnumPtr
  1999. }
  2000. // Frees resources allocated for enumeration handle
  2001. // Returned error codes:
  2002. // NO_ERROR - handle was disposed of ok
  2003. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  2004. DWORD WINAPI
  2005. RtmCloseEnumerationHandle (
  2006. IN HANDLE EnumerationHandle
  2007. ) {
  2008. #define EnumPtr ((PRTM_ENUMERATOR)EnumerationHandle) // To access fields
  2009. // in this routine
  2010. PLIST_ENTRY head;
  2011. PRTM_TABLE Table;
  2012. DWORD ProtocolFamily;
  2013. try {
  2014. ProtocolFamily = EnumPtr->RE_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  2015. Table = &Tables[ProtocolFamily];
  2016. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  2017. && EnterTableAPI (Table))
  2018. NOTHING;
  2019. else
  2020. return ERROR_INVALID_HANDLE;
  2021. }
  2022. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  2023. EXCEPTION_EXECUTE_HANDLER :
  2024. EXCEPTION_CONTINUE_SEARCH) {
  2025. return ERROR_INVALID_HANDLE;
  2026. }
  2027. // Just pull out the enumeration node and dispose of it
  2028. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  2029. ExitTableAPI (Table);
  2030. return ERROR_NO_SYSTEM_RESOURCES;
  2031. }
  2032. head = EnumPtr->RE_Links[EnumPtr->RE_Link].Flink;
  2033. RemoveEntryList (&EnumPtr->RE_Links[EnumPtr->RE_Link]);
  2034. if (IsListEmpty (head)) {
  2035. if (EnumPtr->RE_Link==RTM_INTERFACE_LIST_LINK) {
  2036. PRTM_INTERFACE_NODE intfNode = CONTAINING_RECORD (head,
  2037. RTM_INTERFACE_NODE,
  2038. IN_Head);
  2039. RemoveEntryList (&intfNode->IN_Link);
  2040. GlobalFree (intfNode);
  2041. }
  2042. #if RTM_USE_PROTOCOL_LISTS
  2043. else if (EnumPtr->RE_Link==RTM_PROTOCOL_LIST_LINK) {
  2044. PRTM_PROTOCOL_NODE protNode = CONTAINING_RECORD (head,
  2045. RTM_PROTOCOL_NODE,
  2046. PN_Head);
  2047. RemoveEntryList (&protNode->PN_Link);
  2048. GlobalFree (protNode);
  2049. }
  2050. #endif
  2051. }
  2052. EnumPtr->RE_ProtocolFamily ^= RTM_CLIENT_HANDLE_TAG;
  2053. LeaveSyncList (Table, EnumPtr->RE_Lock);
  2054. GlobalFree (EnumerationHandle);
  2055. ExitTableAPI (Table);
  2056. return NO_ERROR;
  2057. #undef EnumPtr
  2058. }
  2059. // Delete all routes as specified by enumeraion flags (same meaning as in
  2060. // enumeration calls above, but RTM_ONLY_THIS_PROTOCOL is always set and protocol
  2061. // family and protocol values are taken from Client Handle).
  2062. // Returned error codes:
  2063. // NO_ERROR - handle was disposed of ok
  2064. // ERROR_INVALID_PARAMETER - undefined or unsupported enumeration flag
  2065. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  2066. // ERROR_NOT_ENOUGH_MEMORY - not enough memory no perform the operation
  2067. DWORD WINAPI
  2068. RtmBlockDeleteRoutes (
  2069. IN HANDLE ClientHandle, // Protocol family and protocol to
  2070. // which this operation applies
  2071. IN DWORD EnumerationFlags, // limitation flags
  2072. IN PVOID CriteriaRoute // Criteria for limitation flags
  2073. // The following fields shout be set
  2074. // Network of interest if RTM_ONLY_THIS_NETWORK is set
  2075. // Interface of interest if RTM_ONLY_THIS_INTERFACE is set
  2076. ) {
  2077. #define ROUTE ((PRTM_XX_ROUTE)CriteriaRoute)
  2078. #define ClientPtr ((PRTM_CLIENT)ClientHandle) // To access handle fields
  2079. // in this routine
  2080. HANDLE EnumerationHandle;
  2081. #define EnumPtr ((PRTM_ENUMERATOR)EnumerationHandle)
  2082. DWORD status;
  2083. PRTM_TABLE Table;
  2084. DWORD ProtocolFamily;
  2085. try {
  2086. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  2087. Table = &Tables[ProtocolFamily];
  2088. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  2089. && EnterTableAPI (Table))
  2090. NOTHING;
  2091. else
  2092. return ERROR_INVALID_HANDLE;
  2093. }
  2094. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  2095. EXCEPTION_EXECUTE_HANDLER :
  2096. EXCEPTION_CONTINUE_SEARCH) {
  2097. return ERROR_INVALID_HANDLE;
  2098. }
  2099. if (EnumerationFlags & (~(RTM_ONLY_THIS_NETWORK|RTM_ONLY_THIS_INTERFACE))) {
  2100. ExitTableAPI (Table);
  2101. return ERROR_INVALID_PARAMETER;
  2102. }
  2103. ROUTE->XX_PROTOCOL = ClientPtr->RC_RoutingProtocol;
  2104. EnumerationFlags |= RTM_ONLY_THIS_PROTOCOL;
  2105. EnumerationHandle = RtmCreateEnumerationHandle (
  2106. ProtocolFamily,
  2107. EnumerationFlags,
  2108. CriteriaRoute);
  2109. if (EnumerationHandle==NULL) {
  2110. ExitTableAPI (Table);
  2111. return GetLastError ();
  2112. }
  2113. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  2114. RtmCloseEnumerationHandle (EnumerationHandle);
  2115. ExitTableAPI (Table);
  2116. return ERROR_NO_SYSTEM_RESOURCES;
  2117. }
  2118. while ((status=DoEnumerate (Table, EnumPtr, RTM_ANY_ENABLE_STATE))==NO_ERROR) {
  2119. PRTM_ROUTE_NODE theNode = CONTAINING_RECORD (
  2120. EnumPtr->RE_Links[EnumPtr->RE_Link].Flink,
  2121. RTM_ROUTE_NODE,
  2122. RN_Links[EnumPtr->RE_Link]
  2123. );
  2124. if (EnumPtr->RE_Link!=RTM_NET_NUMBER_HASH_LINK)
  2125. LeaveSyncList (Table, EnumPtr->RE_Lock);
  2126. if (IsBest(theNode)) {
  2127. // We'll look back and forward to check all nodes
  2128. // around us with same net number trying to find another best
  2129. // node
  2130. DWORD Flags;
  2131. PRTM_ROUTE_NODE curBestNode=NULL;
  2132. PLIST_ENTRY cur = theNode->RN_Links[RTM_NET_NUMBER_HASH_LINK].Blink;
  2133. while (cur!=&theNode->RN_Hash->RSL_Head) {
  2134. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  2135. cur,
  2136. RTM_ROUTE_NODE,
  2137. RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  2138. if (!IsEnumerator (node1)
  2139. && IsEnabled(node1)) {
  2140. if (NetNumCmp (Table, &theNode->RN_Route,
  2141. &node1->RN_Route)==0) {
  2142. if ((curBestNode==NULL)
  2143. || (MetricCmp (Table,
  2144. &curBestNode->RN_Route,
  2145. &node1->RN_Route)>0))
  2146. // Looking for the node with lowest
  2147. // metric that can replace disabled
  2148. // node
  2149. curBestNode = node1;
  2150. }
  2151. else
  2152. break;
  2153. }
  2154. cur = cur->Blink;
  2155. }
  2156. cur = theNode->RN_Links[RTM_NET_NUMBER_HASH_LINK].Flink;
  2157. while (cur!=&theNode->RN_Hash->RSL_Head) {
  2158. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  2159. cur,
  2160. RTM_ROUTE_NODE,
  2161. RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  2162. if (!IsEnumerator (node1)
  2163. && IsEnabled(node1)) {
  2164. if (NetNumCmp (Table, &theNode->RN_Route,
  2165. &node1->RN_Route)==0) {
  2166. if ((curBestNode==NULL)
  2167. || (MetricCmp (Table,
  2168. &curBestNode->RN_Route,
  2169. &node1->RN_Route)>0))
  2170. curBestNode = node1;
  2171. }
  2172. else
  2173. break;
  2174. }
  2175. cur = cur->Flink;
  2176. }
  2177. if (curBestNode!=NULL) { // There is another best node
  2178. ResetBest (theNode);
  2179. SetBest (curBestNode);
  2180. Flags = RTM_CURRENT_BEST_ROUTE | RTM_PREVIOUS_BEST_ROUTE;
  2181. NotifyClients (Table, ClientHandle, Flags,
  2182. &curBestNode->RN_Route,
  2183. &theNode->RN_Route);
  2184. }
  2185. else { // This one was the only available node
  2186. InterlockedDecrement (&Table->RT_NetworkCount);
  2187. Flags = RTM_PREVIOUS_BEST_ROUTE;
  2188. NotifyClients (Table, ClientHandle, Flags, NULL, &theNode->RN_Route);
  2189. }
  2190. }
  2191. status = RemoveRouteNode (Table, theNode);
  2192. if (status!=NO_ERROR)
  2193. break;
  2194. if (EnumPtr->RE_Link!=RTM_NET_NUMBER_HASH_LINK) {
  2195. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  2196. status = ERROR_NO_SYSTEM_RESOURCES;
  2197. if (EnumPtr->RE_Hash!=NULL)
  2198. LeaveSyncList (Table, EnumPtr->RE_Hash);
  2199. break;
  2200. }
  2201. }
  2202. }
  2203. if (status==ERROR_NO_MORE_ROUTES) {
  2204. if (EnumPtr->RE_Hash!=NULL)
  2205. LeaveSyncList (Table, EnumPtr->RE_Hash);
  2206. LeaveSyncList (Table, EnumPtr->RE_Lock);
  2207. status = NO_ERROR;
  2208. }
  2209. RtmCloseEnumerationHandle (EnumerationHandle);
  2210. ExitTableAPI (Table);
  2211. return status;
  2212. #undef EnumPtr
  2213. #undef ClientPtr
  2214. #undef ROUTE
  2215. }
  2216. // Converts all routes as specified by enumeration flags to routes of
  2217. // static protocol (as defined by ClientHandle)
  2218. // Returned error codes:
  2219. // NO_ERROR - routes were converted ok
  2220. // ERROR_INVALID_PARAMETER - undefined or unsupported enumeration flag
  2221. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  2222. // ERROR_NOT_ENOUGH_MEMORY - not enough memory no perform the operation
  2223. DWORD WINAPI
  2224. RtmBlockConvertRoutesToStatic (
  2225. IN HANDLE ClientHandle, // Handle of client that registered
  2226. // to handle static protocol for
  2227. // specified protocol family
  2228. IN DWORD EnumerationFlags, // limitation flags
  2229. IN PVOID CriteriaRoute // Criteria for limitation flags
  2230. // The following fields shout be set
  2231. // Protocol of interest if RTM_ONLY_THIS_PROTOCOL is set
  2232. // Network of interest if RTM_ONLY_THIS_NETWORK is set
  2233. // Interface of interest if RTM_ONLY_THIS_INTERFACE is set
  2234. ) {
  2235. #define ClientPtr ((PRTM_CLIENT)ClientHandle) // To access handle fields
  2236. // in this routine
  2237. HANDLE EnumerationHandle;
  2238. #define EnumPtr ((PRTM_ENUMERATOR)EnumerationHandle)
  2239. DWORD status;
  2240. PRTM_TABLE Table;
  2241. DWORD ProtocolFamily;
  2242. try {
  2243. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  2244. Table = &Tables[ProtocolFamily];
  2245. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  2246. && EnterTableAPI (Table))
  2247. NOTHING;
  2248. else
  2249. return ERROR_INVALID_HANDLE;
  2250. }
  2251. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  2252. EXCEPTION_EXECUTE_HANDLER :
  2253. EXCEPTION_CONTINUE_SEARCH) {
  2254. return ERROR_INVALID_HANDLE;
  2255. }
  2256. EnumerationHandle = RtmCreateEnumerationHandle (
  2257. ProtocolFamily,
  2258. EnumerationFlags,
  2259. CriteriaRoute);
  2260. if (EnumerationHandle==NULL) {
  2261. ExitTableAPI(Table);
  2262. return GetLastError ();
  2263. }
  2264. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  2265. RtmCloseEnumerationHandle (EnumerationHandle);
  2266. ExitTableAPI(Table);
  2267. return ERROR_NO_SYSTEM_RESOURCES;
  2268. }
  2269. while ((status=DoEnumerate (Table, EnumPtr, RTM_ENABLED_NODE_FLAG))==NO_ERROR) {
  2270. PRTM_ROUTE_NODE theNode;
  2271. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  2272. EnumPtr->RE_Links[EnumPtr->RE_Link].Flink,
  2273. RTM_ROUTE_NODE,
  2274. RN_Links[EnumPtr->RE_Link]
  2275. );
  2276. if (ClientPtr->RC_RoutingProtocol==node->RN_Route.XX_PROTOCOL)
  2277. continue;
  2278. if (EnumPtr->RE_Link!=RTM_NET_NUMBER_HASH_LINK)
  2279. LeaveSyncList (Table, EnumPtr->RE_Lock);
  2280. if (ClientPtr->RC_RoutingProtocol>node->RN_Route.XX_PROTOCOL) {
  2281. PLIST_ENTRY cur = node->RN_Links[RTM_NET_NUMBER_HASH_LINK].Flink;
  2282. while (cur!=&node->RN_Hash->RSL_Head) {
  2283. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  2284. cur,
  2285. RTM_ROUTE_NODE,
  2286. RN_Links[RTM_NET_NUMBER_HASH_LINK]
  2287. );
  2288. if (!IsEnumerator (node1)) {
  2289. INT res = NetNumCmp (Table, &node->RN_Route, &node1->RN_Route);
  2290. if (res==0) {
  2291. if (ClientPtr->RC_RoutingProtocol
  2292. == node1->RN_Route.XX_PROTOCOL) {
  2293. if (node->RN_Route.XX_INTERFACE
  2294. == node1->RN_Route.XX_INTERFACE) {
  2295. res = NextHopCmp (Table, &node->RN_Route, &node1->RN_Route);
  2296. ASSERTMSG ("RtmBlockConvertRoutesToStatic:"
  2297. " Already have same static route ",
  2298. res != 0);
  2299. if (res <= 0)
  2300. break;
  2301. }
  2302. else if (node->RN_Route.XX_INTERFACE
  2303. < node1->RN_Route.XX_INTERFACE)
  2304. break;
  2305. }
  2306. else if (ClientPtr->RC_RoutingProtocol
  2307. < node1->RN_Route.XX_PROTOCOL)
  2308. break;
  2309. }
  2310. else if (res<0)
  2311. break;
  2312. }
  2313. cur = cur->Flink;
  2314. }
  2315. theNode = CreateRouteNode (Table,
  2316. cur,
  2317. &node->RN_Links[RTM_INTERFACE_LIST_LINK],
  2318. FALSE,
  2319. node->RN_Hash,
  2320. &node->RN_Route);
  2321. }
  2322. else {
  2323. PLIST_ENTRY cur = node->RN_Links[RTM_NET_NUMBER_HASH_LINK].Blink;
  2324. while (cur!=&node->RN_Hash->RSL_Head) {
  2325. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  2326. cur,
  2327. RTM_ROUTE_NODE,
  2328. RN_Links[RTM_NET_NUMBER_HASH_LINK]
  2329. );
  2330. if (!IsEnumerator (node1)) {
  2331. INT res = NetNumCmp (Table, &node->RN_Route, &node1->RN_Route);
  2332. if (res==0) {
  2333. if (ClientPtr->RC_RoutingProtocol
  2334. == node1->RN_Route.XX_PROTOCOL) {
  2335. if (node->RN_Route.XX_INTERFACE
  2336. == node1->RN_Route.XX_INTERFACE) {
  2337. res = NextHopCmp (Table, &node->RN_Route, &node1->RN_Route);
  2338. ASSERTMSG ("RtmBlockConvertRoutesToStatic:"
  2339. " Already have same static route ",
  2340. res != 0);
  2341. if (res >= 0)
  2342. break;
  2343. }
  2344. else if (node->RN_Route.XX_INTERFACE
  2345. > node1->RN_Route.XX_INTERFACE)
  2346. break;
  2347. }
  2348. else if (ClientPtr->RC_RoutingProtocol
  2349. > node1->RN_Route.XX_PROTOCOL)
  2350. break;
  2351. }
  2352. else if (res>0)
  2353. break;
  2354. }
  2355. cur = cur->Blink;
  2356. }
  2357. theNode = CreateRouteNode (Table,
  2358. cur->Flink,
  2359. &node->RN_Links[RTM_INTERFACE_LIST_LINK],
  2360. TRUE,
  2361. node->RN_Hash,
  2362. &node->RN_Route);
  2363. }
  2364. if (theNode==NULL) {
  2365. status = GetLastError ();
  2366. if (EnumPtr->RE_Hash!=NULL)
  2367. LeaveSyncList (Table, EnumPtr->RE_Hash);
  2368. break;
  2369. }
  2370. theNode->RN_Route.XX_PROTOCOL = ClientPtr->RC_RoutingProtocol;
  2371. theNode->RN_Flags = node->RN_Flags;
  2372. status = RemoveRouteNode (Table, node);
  2373. if (status!=NO_ERROR)
  2374. break;
  2375. if (EnumPtr->RE_Link!=RTM_NET_NUMBER_HASH_LINK) {
  2376. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  2377. status = ERROR_NO_SYSTEM_RESOURCES;
  2378. if (EnumPtr->RE_Hash!=NULL)
  2379. LeaveSyncList (Table, EnumPtr->RE_Hash);
  2380. break;
  2381. }
  2382. }
  2383. }
  2384. if (status==ERROR_NO_MORE_ROUTES) {
  2385. if (EnumPtr->RE_Hash!=NULL)
  2386. LeaveSyncList (Table, EnumPtr->RE_Hash);
  2387. LeaveSyncList (Table, EnumPtr->RE_Lock);
  2388. status = NO_ERROR;
  2389. }
  2390. RtmCloseEnumerationHandle (EnumerationHandle);
  2391. ExitTableAPI (Table);
  2392. return status;
  2393. #undef EnumPtr
  2394. #undef ClientPtr
  2395. }
  2396. // Disables/reenables all routes as specified by enumeraion flags
  2397. // (same meaning as in enumeration calls above, but RTM_ONLY_THIS_PROTOCOL
  2398. // is always set and protocol family and protocol values are taken from
  2399. // Client Handle).
  2400. // Disables/reenables all routes as specified by enumeraion flags
  2401. // (same meaning as in enumeration calls above, but RTM_ONLY_THIS_PROTOCOL
  2402. // is always set and protocol family and protocol values are taken from
  2403. // Client Handle). Currently the only flag supported is RTN_ONLY_THIS_INTERFACE
  2404. // Disabled routes are invisible, but still maintained by the RTM.
  2405. // E.g.: enumeration methods won't notice them;
  2406. // if disabled route was the best, other route will take its
  2407. // place (if there is one) and all clients will be
  2408. // notified of best route change;
  2409. // however: disabled route can still be deleted or updated using
  2410. // RtmDeleteRoute or RtmAddRoute correspondingly;
  2411. // they can also be aged out by the RTM itself.
  2412. // Returned error codes:
  2413. // NO_ERROR - routes were converted ok
  2414. // ERROR_INVALID_PARAMETER - undefined or unsupported enumeration flag
  2415. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  2416. // ERROR_NOT_ENOUGH_MEMORY - not enough memory no perform the operation
  2417. DWORD WINAPI
  2418. RtmBlockSetRouteEnable (
  2419. IN HANDLE ClientHandle, // Protocol family and protocol to
  2420. // which this operation applies
  2421. IN DWORD EnumerationFlags, // limitation flags
  2422. IN PVOID CriteriaRoute, // Criteria for limitation flags
  2423. // The following fields shout be set
  2424. // Network of interest if RTM_ONLY_THIS_NETWORK is set
  2425. // Interface of interest if RTM_ONLY_THIS_INTERFACE is set
  2426. IN BOOL Enable // FALSE to disable routes, TRUE to
  2427. // reenable them
  2428. ) {
  2429. #define ClientPtr ((PRTM_CLIENT)ClientHandle) // To access handle fields
  2430. // in this routine
  2431. #define ROUTE ((PRTM_XX_ROUTE)CriteriaRoute)
  2432. HANDLE EnumerationHandle;
  2433. #define EnumPtr ((PRTM_ENUMERATOR)EnumerationHandle)
  2434. DWORD status;
  2435. PRTM_TABLE Table;
  2436. DWORD ProtocolFamily;
  2437. DWORD EnableFlag;
  2438. try {
  2439. ProtocolFamily = ClientPtr->RC_ProtocolFamily ^ RTM_CLIENT_HANDLE_TAG;
  2440. Table = &Tables[ProtocolFamily];
  2441. if ((ProtocolFamily<RTM_NUM_OF_PROTOCOL_FAMILIES)
  2442. && EnterTableAPI (Table))
  2443. NOTHING;
  2444. else
  2445. return ERROR_INVALID_HANDLE;
  2446. }
  2447. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  2448. EXCEPTION_EXECUTE_HANDLER :
  2449. EXCEPTION_CONTINUE_SEARCH) {
  2450. return ERROR_INVALID_HANDLE;
  2451. }
  2452. if (EnumerationFlags & (~(RTM_ONLY_THIS_NETWORK|RTM_ONLY_THIS_INTERFACE))) {
  2453. ExitTableAPI (Table);
  2454. return ERROR_INVALID_PARAMETER;
  2455. }
  2456. ROUTE->XX_PROTOCOL = ClientPtr->RC_RoutingProtocol;
  2457. EnableFlag = Enable ? 0 : RTM_ENABLED_NODE_FLAG;
  2458. EnumerationHandle = RtmCreateEnumerationHandle (
  2459. ProtocolFamily,
  2460. EnumerationFlags|RTM_ONLY_THIS_PROTOCOL,
  2461. CriteriaRoute);
  2462. if (EnumerationHandle==NULL) {
  2463. ExitTableAPI (Table);
  2464. return GetLastError ();
  2465. }
  2466. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  2467. RtmCloseEnumerationHandle (EnumerationHandle);
  2468. ExitTableAPI (Table);
  2469. return ERROR_NO_SYSTEM_RESOURCES;
  2470. }
  2471. while ((status=DoEnumerate (Table, EnumPtr, EnableFlag))==NO_ERROR) {
  2472. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  2473. EnumPtr->RE_Links[EnumPtr->RE_Link].Flink,
  2474. RTM_ROUTE_NODE,
  2475. RN_Links[EnumPtr->RE_Link]
  2476. );
  2477. // Update node status
  2478. SetEnable (node, Enable);
  2479. // If we enable this node, we'll have to check if it is the
  2480. // best one, if we disable this node and it was the best we'll
  2481. // try to locate another route. In both cases we'll have to
  2482. // locate and check all nodes to the destination
  2483. if (Enable || IsBest(node)) {
  2484. PRTM_ROUTE_NODE bestNode=NULL;
  2485. PLIST_ENTRY cur1;
  2486. // We'll look back and forward to check all nodes
  2487. // around us with same net number
  2488. cur1 = node->RN_Links[RTM_NET_NUMBER_HASH_LINK].Blink;
  2489. while (cur1!=&node->RN_Hash->RSL_Head) {
  2490. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  2491. cur1,
  2492. RTM_ROUTE_NODE,
  2493. RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  2494. if (!IsEnumerator (node1)
  2495. && IsEnabled(node1)) {
  2496. if (NetNumCmp (Table, &node->RN_Route,
  2497. &node1->RN_Route)==0) {
  2498. if (Enable && IsBest(node1)) {
  2499. // Looking for current best node
  2500. // that we might have to replace
  2501. bestNode = node1;
  2502. break;
  2503. }
  2504. else if (!Enable
  2505. && ((bestNode==NULL)
  2506. || (MetricCmp (Table,
  2507. &bestNode->RN_Route,
  2508. &node1->RN_Route)>0)))
  2509. // Looking for the node with lowest
  2510. // metric that can replace disabled
  2511. // node
  2512. bestNode = node1;
  2513. }
  2514. else
  2515. break;
  2516. }
  2517. cur1 = cur1->Blink;
  2518. }
  2519. // If disabling, we need to check all nodes to find
  2520. // the best one
  2521. // if enabling we continue only if we haven't
  2522. // located the best node yet
  2523. if (!Enable || (bestNode==NULL)) {
  2524. cur1 = node->RN_Links[RTM_NET_NUMBER_HASH_LINK].Flink;
  2525. while (cur1!=&node->RN_Hash->RSL_Head) {
  2526. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  2527. cur1,
  2528. RTM_ROUTE_NODE,
  2529. RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  2530. if (!IsEnumerator (node1)
  2531. && IsEnabled(node1)) {
  2532. // Looking for current best node
  2533. // that we might have to replace
  2534. if (NetNumCmp (Table, &node->RN_Route,
  2535. &node1->RN_Route)==0) {
  2536. if (Enable && IsBest(node1)) {
  2537. bestNode = node1;
  2538. break;
  2539. }
  2540. else if (!Enable
  2541. && ((bestNode==NULL)
  2542. || (MetricCmp (Table,
  2543. &bestNode->RN_Route,
  2544. &node1->RN_Route)>0)))
  2545. // Looking for the node with lowest
  2546. // metric that can replace disabled
  2547. // node
  2548. bestNode = node1;
  2549. }
  2550. else
  2551. break;
  2552. }
  2553. cur1 = cur1->Flink;
  2554. }
  2555. }
  2556. if (!Enable // Disabling: we already know that we're removing
  2557. // the best node (see above), so we'll have
  2558. // to notify clients whether or not we found the
  2559. // replacement
  2560. // Enabling: we'll have to notify only if there
  2561. // is no best route yet or if the route we're
  2562. // enabling is better then current best route
  2563. || (bestNode==NULL)
  2564. || (MetricCmp (Table,
  2565. &node->RN_Route,
  2566. &bestNode->RN_Route)<0)) {
  2567. if (bestNode!=NULL) {
  2568. // There is another route that loses or gains
  2569. // best status as the result of our operation
  2570. if (Enable) {
  2571. ResetBest (bestNode);
  2572. SetBest (node);
  2573. // Enabling: node replaces bestNode
  2574. NotifyClients (Table,
  2575. NULL,
  2576. RTM_CURRENT_BEST_ROUTE|RTM_PREVIOUS_BEST_ROUTE,
  2577. &node->RN_Route,
  2578. &bestNode->RN_Route);
  2579. }
  2580. else {
  2581. ResetBest (node);
  2582. SetBest (bestNode);
  2583. // Disabling: bestNode replaces node
  2584. NotifyClients (Table,
  2585. NULL,
  2586. RTM_CURRENT_BEST_ROUTE|RTM_PREVIOUS_BEST_ROUTE,
  2587. &bestNode->RN_Route,
  2588. &node->RN_Route);
  2589. }
  2590. }
  2591. else /* if (bestNode==NULL) */ {
  2592. // No other node
  2593. if (Enable) {
  2594. SetBest (node);
  2595. // Enabling: our node becomes the best
  2596. NotifyClients (Table,
  2597. NULL,
  2598. RTM_CURRENT_BEST_ROUTE,
  2599. &node->RN_Route,
  2600. NULL);
  2601. }
  2602. else {
  2603. ResetBest (node);
  2604. // Disabling: we removed the only available
  2605. // route
  2606. NotifyClients (Table,
  2607. NULL,
  2608. RTM_PREVIOUS_BEST_ROUTE,
  2609. NULL,
  2610. &node->RN_Route);
  2611. }
  2612. }
  2613. }
  2614. }
  2615. }
  2616. if (status==ERROR_NO_MORE_ROUTES) {
  2617. if (EnumPtr->RE_Hash!=NULL)
  2618. LeaveSyncList (Table, EnumPtr->RE_Hash);
  2619. LeaveSyncList (Table, EnumPtr->RE_Lock);
  2620. status = NO_ERROR;
  2621. }
  2622. RtmCloseEnumerationHandle (EnumerationHandle);
  2623. ExitTableAPI (Table);
  2624. return status;
  2625. #undef EnumPtr
  2626. #undef ClientPtr
  2627. #undef ROUTE
  2628. return NO_ERROR;
  2629. }
  2630. // Slow enumeration that may require traversing up to all the entries in the
  2631. // table if route used to compute the next entry no longer exists.
  2632. // Routes are returned in the increasing net number order
  2633. // Get first route that matches specified criteria
  2634. // Returns:
  2635. // NO_ERROR - if matching route is found
  2636. // ERROR_NO_ROUTES - if no routes available with specified criteria
  2637. // ERROR_INVALID_PARAMETER - if one of the parameters is invalid
  2638. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  2639. DWORD WINAPI
  2640. RtmGetFirstRoute (
  2641. IN DWORD ProtocolFamily,
  2642. IN DWORD EnumerationFlags,// Limiting flags
  2643. IN OUT PVOID Route // On Entry: if any of the EnumerationFlags are set,
  2644. // the corresponding fields of Route will
  2645. // be used to limit the search
  2646. // to the only table entries that have
  2647. // same value in the specified field.
  2648. // On Exit: contains first route in the table that
  2649. // matches specified criteria
  2650. ){
  2651. #define ROUTE ((PRTM_XX_ROUTE)Route)
  2652. PRTM_TABLE Table;
  2653. PLIST_ENTRY cur, head;
  2654. INT res, link;
  2655. PRTM_SYNC_LIST hashBasket;
  2656. DWORD status = ERROR_NO_ROUTES;
  2657. Table = &Tables[ProtocolFamily];
  2658. if ((ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES)
  2659. || !EnterTableAPI (Table)) {
  2660. #if DBG
  2661. Trace2 (ANY,
  2662. "Undefined Protocol Family\n\tat line %ld of %s\n",
  2663. __LINE__, __FILE__);
  2664. #endif
  2665. return ERROR_INVALID_PARAMETER;
  2666. }
  2667. if (EnumerationFlags &
  2668. (~(RTM_ONLY_THIS_NETWORK|RTM_ONLY_THIS_INTERFACE
  2669. |RTM_ONLY_THIS_PROTOCOL|RTM_ONLY_BEST_ROUTES
  2670. |RTM_INCLUDE_DISABLED_ROUTES))) {
  2671. ExitTableAPI (Table);
  2672. return ERROR_INVALID_PARAMETER;
  2673. }
  2674. if (EnumerationFlags & RTM_ONLY_THIS_NETWORK) {
  2675. hashBasket = &Table->RT_NetNumberHash [HashFunction (Table,
  2676. ((char *)ROUTE)
  2677. +sizeof(RTM_XX_ROUTE))];
  2678. link = RTM_NET_NUMBER_HASH_LINK;
  2679. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  2680. ExitTableAPI (Table);
  2681. return ERROR_NO_SYSTEM_RESOURCES;
  2682. }
  2683. head = &hashBasket->RSL_Head;
  2684. }
  2685. else {
  2686. hashBasket = NULL;
  2687. link = RTM_NET_NUMBER_LIST_LINK;
  2688. head = &Table->RT_NetNumberMasterList.RSL_Head;
  2689. if (EnterSyncList (Table, &Table->RT_NetNumberMasterList, FALSE))
  2690. ConsolidateNetNumberLists (Table);
  2691. else if (!EnterSyncList (Table, &Table->RT_NetNumberMasterList, TRUE)) {
  2692. ExitTableAPI (Table);
  2693. return ERROR_NO_SYSTEM_RESOURCES;
  2694. }
  2695. }
  2696. // Go through the list till entry that matches specified
  2697. // criteria is found
  2698. cur = head->Flink;
  2699. while (cur!=head) {
  2700. PRTM_ROUTE_NODE node = CONTAINING_RECORD (cur,
  2701. RTM_ROUTE_NODE,
  2702. RN_Links[link]);
  2703. if (!IsEnumerator (node)
  2704. && ((EnumerationFlags&RTM_INCLUDE_DISABLED_ROUTES)
  2705. || IsEnabled(node))) {
  2706. if (EnumerationFlags & RTM_ONLY_THIS_NETWORK) {
  2707. // Check network number if asked
  2708. res = NetNumCmp (Table, ROUTE, &node->RN_Route);
  2709. if (res > 0) // It may be further ahead
  2710. goto DoNextNode;
  2711. else if (res < 0) // No chance to find it anymore
  2712. break;
  2713. }
  2714. // Check if it is the best route if asked
  2715. if (EnumerationFlags & RTM_ONLY_BEST_ROUTES) {
  2716. // We need to lock the hash list to make sure the
  2717. // best node designation won't change while we are
  2718. // scaning through the list
  2719. if (hashBasket!=node->RN_Hash) {
  2720. if (hashBasket!=NULL)
  2721. LeaveSyncList (Table, hashBasket);
  2722. hashBasket = node->RN_Hash;
  2723. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  2724. hashBasket = NULL;
  2725. status = ERROR_NO_SYSTEM_RESOURCES;
  2726. goto ExitGetFirst;
  2727. }
  2728. }
  2729. if (!IsBest(node))
  2730. goto DoNextNode;
  2731. }
  2732. // Check protocol if asked
  2733. if ((EnumerationFlags & RTM_ONLY_THIS_PROTOCOL)
  2734. && (ROUTE->XX_PROTOCOL
  2735. !=node->RN_Route.XX_PROTOCOL))
  2736. goto DoNextNode;
  2737. // Check interface if asked
  2738. if ((EnumerationFlags & RTM_ONLY_THIS_INTERFACE)
  2739. && (ROUTE->XX_INTERFACE
  2740. !=node->RN_Route.XX_INTERFACE))
  2741. goto DoNextNode;
  2742. // Now we have it
  2743. memcpy (ROUTE, &node->RN_Route, Table->RT_RouteSize);
  2744. status = NO_ERROR;
  2745. break;
  2746. }
  2747. DoNextNode: // Continue searching
  2748. cur = cur->Flink;
  2749. }
  2750. ExitGetFirst:
  2751. if (link==RTM_NET_NUMBER_HASH_LINK)
  2752. LeaveSyncList (Table, hashBasket);
  2753. else {
  2754. if (hashBasket!=NULL)
  2755. LeaveSyncList (Table, hashBasket);
  2756. LeaveSyncList (Table, &Table->RT_NetNumberMasterList);
  2757. }
  2758. ExitTableAPI (Table);
  2759. #undef ROUTE
  2760. return status;
  2761. }
  2762. // Compute and return route next to the input route limiting serach to the routes
  2763. // with specified criteria
  2764. // Returns:
  2765. // NO_ERROR - if matching route is found
  2766. // ERROR_NO_MORE_ROUTES - if no matching route was found while end of
  2767. // the table is reached and no route
  2768. // ERROR_INVALID_PARAMETER - if one of the parameters is invalid
  2769. // ERROR_NO_SYSTEM_RESOURCES - not enough resources to lock table content
  2770. DWORD WINAPI
  2771. RtmGetNextRoute (
  2772. IN DWORD ProtocolFamily,
  2773. IN DWORD EnumerationFlags,// Limiting flags
  2774. IN OUT PVOID Route // On Entry: contains the route from which to start
  2775. // the search.
  2776. // if any of the EnumerationFlags are set,
  2777. // the corresponding fields of Route will
  2778. // be used to limit the search
  2779. // to the only table entries that have
  2780. // same value in the specified field.
  2781. // On Exit: contains first route in the table that
  2782. // matches specified criteria
  2783. ) {
  2784. #define ROUTE ((PRTM_XX_ROUTE)Route)
  2785. PRTM_TABLE Table;
  2786. PLIST_ENTRY cur, posLink = NULL;
  2787. INT res;
  2788. PRTM_SYNC_LIST hashBasket = NULL;
  2789. DWORD status = ERROR_NO_MORE_ROUTES;
  2790. Table = &Tables[ProtocolFamily];
  2791. if ((ProtocolFamily>=RTM_NUM_OF_PROTOCOL_FAMILIES)
  2792. || !EnterTableAPI (Table)) {
  2793. #if DBG
  2794. Trace2 (ANY,
  2795. "Undefined Protocol Family\n\tat line %ld of %s\n",
  2796. __LINE__, __FILE__);
  2797. #endif
  2798. return ERROR_INVALID_PARAMETER;
  2799. }
  2800. if (EnumerationFlags &
  2801. (~(RTM_ONLY_THIS_NETWORK|RTM_ONLY_THIS_INTERFACE
  2802. |RTM_ONLY_THIS_PROTOCOL|RTM_ONLY_BEST_ROUTES
  2803. |RTM_INCLUDE_DISABLED_ROUTES))) {
  2804. ExitTableAPI (Table);
  2805. return ERROR_INVALID_PARAMETER;
  2806. }
  2807. if (EnterSyncList (Table, &Table->RT_NetNumberMasterList, FALSE))
  2808. ConsolidateNetNumberLists (Table);
  2809. else if (!EnterSyncList (Table, &Table->RT_NetNumberMasterList, TRUE)) {
  2810. ExitTableAPI (Table);
  2811. return ERROR_NO_SYSTEM_RESOURCES;
  2812. }
  2813. // First try to locate starting point for the serach
  2814. // using the hash table (should work most of the
  2815. // time unless route was deleted while client was
  2816. // processing it)
  2817. hashBasket = &Table->RT_NetNumberHash [HashFunction (Table,
  2818. ((char *)ROUTE)
  2819. +sizeof(RTM_XX_ROUTE))];
  2820. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  2821. status = ERROR_NO_SYSTEM_RESOURCES;
  2822. goto ExitGetNext;
  2823. }
  2824. cur = hashBasket->RSL_Head.Flink;
  2825. while (cur!=&hashBasket->RSL_Head) {
  2826. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  2827. cur,
  2828. RTM_ROUTE_NODE,
  2829. RN_Links[RTM_NET_NUMBER_HASH_LINK]
  2830. );
  2831. if (!IsEnumerator (node)
  2832. && ((EnumerationFlags&RTM_INCLUDE_DISABLED_ROUTES)
  2833. || IsEnabled(node))) {
  2834. // First check network number
  2835. // (lists are ordered by net number)
  2836. res = NetNumCmp (Table, ROUTE, &node->RN_Route);
  2837. if (res==0) {
  2838. if (ROUTE->XX_PROTOCOL
  2839. == node->RN_Route.XX_PROTOCOL) {
  2840. if (ROUTE->XX_INTERFACE
  2841. == node->RN_Route.XX_INTERFACE) {
  2842. res = NextHopCmp (Table, ROUTE, &node->RN_Route);
  2843. if ((res == 0)
  2844. && IsSorted (node))
  2845. posLink = node->RN_Links[RTM_NET_NUMBER_LIST_LINK].Flink;
  2846. else if (res < 0)
  2847. break;
  2848. }
  2849. else if (ROUTE->XX_INTERFACE
  2850. < node->RN_Route.XX_INTERFACE)
  2851. break;
  2852. }
  2853. else if (ROUTE->XX_PROTOCOL
  2854. < node->RN_Route.XX_PROTOCOL)
  2855. break;
  2856. }
  2857. else if (res < 0)
  2858. break;
  2859. }
  2860. cur = cur->Flink;
  2861. }
  2862. LeaveSyncList (Table, hashBasket);
  2863. hashBasket = NULL;
  2864. if (posLink!=NULL)
  2865. cur = posLink; // Note the place to start with
  2866. else { // If we didn't find the entry in
  2867. // hash table, we'll have to go through
  2868. // the master net number list from the
  2869. // beginning
  2870. cur = Table->RT_NetNumberMasterList.RSL_Head.Flink;
  2871. while (cur!=&Table->RT_NetNumberMasterList.RSL_Head) {
  2872. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  2873. cur,
  2874. RTM_ROUTE_NODE,
  2875. RN_Links[RTM_NET_NUMBER_LIST_LINK]
  2876. );
  2877. if (!IsEnumerator (node)
  2878. && ((EnumerationFlags&RTM_INCLUDE_DISABLED_ROUTES)
  2879. || IsEnabled(node))) {
  2880. // Just do all the necessary comparisons to
  2881. // find the following entry
  2882. res = NetNumCmp (Table, ROUTE, &node->RN_Route);
  2883. if ((res < 0)
  2884. ||((res == 0)
  2885. &&((ROUTE->XX_PROTOCOL
  2886. < node->RN_Route.XX_PROTOCOL)
  2887. ||((ROUTE->XX_PROTOCOL
  2888. ==node->RN_Route.XX_PROTOCOL)
  2889. &&((ROUTE->XX_INTERFACE
  2890. < node->RN_Route.XX_INTERFACE)
  2891. ||((ROUTE->XX_INTERFACE
  2892. ==node->RN_Route.XX_INTERFACE)
  2893. && (NextHopCmp (Table, ROUTE,
  2894. &node->RN_Route)
  2895. < 0)))))))
  2896. break;
  2897. }
  2898. cur = cur->Flink;
  2899. }
  2900. }
  2901. // Now we need to locate first entry that satisfies all criteria
  2902. while (cur!=&Table->RT_NetNumberMasterList.RSL_Head) {
  2903. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  2904. cur,
  2905. RTM_ROUTE_NODE,
  2906. RN_Links[RTM_NET_NUMBER_LIST_LINK]
  2907. );
  2908. if (!IsEnumerator (node)
  2909. && ((EnumerationFlags&RTM_INCLUDE_DISABLED_ROUTES)
  2910. || IsEnabled(node))) {
  2911. if (EnumerationFlags & RTM_ONLY_BEST_ROUTES) {
  2912. // We need to lock the hash list to make sure the
  2913. // best node designation won't change while we are
  2914. // scaning through the list
  2915. if (hashBasket!=node->RN_Hash) {
  2916. if (hashBasket!=NULL)
  2917. LeaveSyncList (Table, hashBasket);
  2918. hashBasket = node->RN_Hash;
  2919. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  2920. status = ERROR_NO_SYSTEM_RESOURCES;
  2921. goto ExitGetNext;
  2922. }
  2923. }
  2924. // For best routes we must check if the route is best
  2925. // and also make sure we do not return same net as in
  2926. // previous call in case the best route was moved
  2927. // while client was processing results of the
  2928. // previous call
  2929. if (!IsBest(node)
  2930. || (NetNumCmp (Table, ROUTE, &node->RN_Route)==0))
  2931. goto DoNextNode;
  2932. }
  2933. if (EnumerationFlags & RTM_ONLY_THIS_NETWORK) {
  2934. // checking net number
  2935. res = NetNumCmp (Table, ROUTE, &node->RN_Route);
  2936. if (res > 0) // It is still ahead
  2937. goto DoNextNode;
  2938. else if (res < 0) // no chance to find it
  2939. break;
  2940. // else (res == 0), found it, continue
  2941. }
  2942. // Check interface if asked
  2943. if ((EnumerationFlags & RTM_ONLY_THIS_INTERFACE)
  2944. && (node->RN_Route.XX_INTERFACE
  2945. !=ROUTE->XX_INTERFACE))
  2946. goto DoNextNode;
  2947. // Check protocol if asked
  2948. if ((EnumerationFlags & RTM_ONLY_THIS_PROTOCOL)
  2949. && (node->RN_Route.XX_PROTOCOL
  2950. !=ROUTE->XX_PROTOCOL))
  2951. goto DoNextNode;
  2952. // Now we can return it
  2953. // Make sure nobody changes the route while we copy
  2954. memcpy (ROUTE, &node->RN_Route, Table->RT_RouteSize);
  2955. status = NO_ERROR;
  2956. break;
  2957. }
  2958. DoNextNode:
  2959. cur = cur->Flink;
  2960. }
  2961. if (hashBasket!=NULL)
  2962. LeaveSyncList (Table, hashBasket);
  2963. ExitGetNext:
  2964. LeaveSyncList (Table, &Table->RT_NetNumberMasterList);
  2965. ExitTableAPI (Table);
  2966. #undef ROUTE
  2967. return status;
  2968. }
  2969. //----------------------------------------------------------------------------
  2970. // RtmLookupIPDestination
  2971. //
  2972. // Given a destination address does a route lookup to get the best route
  2973. // to that destination.
  2974. //----------------------------------------------------------------------------
  2975. BOOL WINAPI
  2976. RtmLookupIPDestination(
  2977. DWORD dwDestAddr,
  2978. PRTM_IP_ROUTE prir
  2979. )
  2980. {
  2981. INT nInd;
  2982. IP_NETWORK ipNet;
  2983. for ( nInd = MAX_MASKS; nInd >= 0; nInd-- )
  2984. {
  2985. if ( g_meMaskTable[ nInd ].dwCount == 0 )
  2986. {
  2987. continue;
  2988. }
  2989. ipNet.N_NetNumber = dwDestAddr & g_meMaskTable[ nInd ].dwMask;
  2990. ipNet.N_NetMask = g_meMaskTable[ nInd ].dwMask;
  2991. if ( RtmIsRoute( RTM_PROTOCOL_FAMILY_IP, &ipNet, prir ) )
  2992. {
  2993. if ( IsRouteLoopback( prir ) )
  2994. {
  2995. continue;
  2996. }
  2997. return TRUE;
  2998. }
  2999. }
  3000. return FALSE;
  3001. }
  3002. //----------------------------------------------------------------------------
  3003. //
  3004. //
  3005. //
  3006. //----------------------------------------------------------------------------
  3007. VOID
  3008. UpdateAPC (
  3009. PVOID Context,
  3010. ULONG TimeLow,
  3011. LONG TimeHigh
  3012. ) {
  3013. #define Table ((PRTM_TABLE)Context)
  3014. if (InterlockedIncrement (&Table->RT_UpdateWorkerPending)==0) {
  3015. DWORD status = RtlQueueWorkItem (ConsolidateNetNumberListsWI, Context, 0);
  3016. if (status!=STATUS_SUCCESS) {
  3017. ASSERTERRMSG ("Can't queue update work item", FALSE);
  3018. ScheduleUpdate (Context);
  3019. }
  3020. }
  3021. #undef Table
  3022. }
  3023. VOID APIENTRY
  3024. ScheduleUpdate (
  3025. PVOID Context
  3026. ) {
  3027. #define Table ((PRTM_TABLE)Context)
  3028. DWORD status;
  3029. static LARGE_INTEGER dueTime = RTM_NET_NUMBER_UPDATE_PERIOD;
  3030. if (InterlockedDecrement (&Table->RT_UpdateWorkerPending)>=0) {
  3031. status = RtlQueueWorkItem (ConsolidateNetNumberListsWI, Context, 0);
  3032. if (status==STATUS_SUCCESS)
  3033. return;
  3034. ASSERTERRMSG ("Can't queue update work item", FALSE);
  3035. InterlockedExchange (&Table->RT_UpdateWorkerPending, -1);
  3036. }
  3037. status = NtSetTimer (Table->RT_UpdateTimer,
  3038. &dueTime,
  3039. UpdateAPC,
  3040. Context,
  3041. FALSE,
  3042. 0,
  3043. NULL);
  3044. ASSERTMSG ("Could not set expiration timer ", NT_SUCCESS (status));
  3045. #undef Table
  3046. }
  3047. VOID
  3048. ConsolidateNetNumberListsWI (
  3049. PVOID Context
  3050. ) {
  3051. #define Table ((PRTM_TABLE)Context)
  3052. DWORD status;
  3053. if (EnterSyncList (Table, &Table->RT_NetNumberMasterList, TRUE)) {
  3054. InterlockedExchange (&Table->RT_UpdateWorkerPending, 0);
  3055. ConsolidateNetNumberLists (Table);
  3056. LeaveSyncList (Table, &Table->RT_NetNumberMasterList);
  3057. }
  3058. status = RtlQueueWorkItem (ScheduleUpdate, Context, WT_EXECUTEINIOTHREAD);
  3059. ASSERTERRMSG ("Can't queue update work item", status==STATUS_SUCCESS);
  3060. #undef Table
  3061. }
  3062. // This procedure merges temporary and master net number lists
  3063. // It also removes and disposes of nodes in the deleted list
  3064. VOID
  3065. ConsolidateNetNumberLists (
  3066. PRTM_TABLE Table // Table for which operation is performed
  3067. ) {
  3068. PLIST_ENTRY curMaster, curTemp;
  3069. LIST_ENTRY tempHead;
  3070. PRTM_ROUTE_NODE tempNode;
  3071. INT res;
  3072. DWORD status;
  3073. #if DBG
  3074. INT curMasterIdx = 0;
  3075. #endif
  3076. // Temp and deleted lists are locked for a very short period
  3077. // of time so that overall performance should not
  3078. // degrade
  3079. if (!EnterSyncList (Table, &Table->RT_NetNumberTempList, TRUE)) {
  3080. return;
  3081. }
  3082. if (!EnterSyncList (Table, &Table->RT_DeletedList, TRUE)) {
  3083. LeaveSyncList (Table, &Table->RT_NetNumberTempList);
  3084. return;
  3085. }
  3086. // Process entries in deleted list
  3087. while (!IsListEmpty (&Table->RT_DeletedList.RSL_Head)) {
  3088. curTemp = RemoveHeadList (&Table->RT_DeletedList.RSL_Head);
  3089. tempNode = CONTAINING_RECORD (curTemp,
  3090. RTM_ROUTE_NODE,
  3091. RN_Links[RTM_DELETED_LIST_LINK]);
  3092. RemoveEntryList (&tempNode->RN_Links[RTM_NET_NUMBER_LIST_LINK]);
  3093. #if DBG
  3094. IF_DEBUG (DISPLAY_TABLE)
  3095. DeleteRouteFromLB (Table, tempNode);
  3096. #endif
  3097. HeapFree (Table->RT_Heap, 0, tempNode);
  3098. }
  3099. // Unlock the list
  3100. Table->RT_DeletedNodesCount = 0;
  3101. LeaveSyncList (Table, &Table->RT_DeletedList);
  3102. // Now, just copy the head of the temp list,
  3103. // so we won't delay others while processing it
  3104. if (!IsListEmpty (&Table->RT_NetNumberTempList.RSL_Head)) {
  3105. curTemp = Table->RT_NetNumberTempList.RSL_Head.Flink;
  3106. RemoveEntryList (&Table->RT_NetNumberTempList.RSL_Head);
  3107. InitializeListHead (&Table->RT_NetNumberTempList.RSL_Head);
  3108. InsertTailList (curTemp, &tempHead);
  3109. }
  3110. else
  3111. InitializeListHead (&tempHead);
  3112. Table->RT_NetNumberTempCount = 0;
  3113. LeaveSyncList (Table, &Table->RT_NetNumberTempList);
  3114. curMaster = Table->RT_NetNumberMasterList.RSL_Head.Flink;
  3115. // Merge master and temp lists (both are ordered by
  3116. // net number.interface.protocol.next hop address)
  3117. while (!IsListEmpty (&tempHead)) {
  3118. // Take the first entry
  3119. curTemp = RemoveHeadList (&tempHead);
  3120. tempNode = CONTAINING_RECORD (curTemp,
  3121. RTM_ROUTE_NODE,
  3122. RN_Links[RTM_NET_NUMBER_LIST_LINK]);
  3123. // Find master list entry that should follow it
  3124. while (curMaster!=&Table->RT_NetNumberMasterList.RSL_Head) {
  3125. PRTM_ROUTE_NODE node = CONTAINING_RECORD (curMaster,
  3126. RTM_ROUTE_NODE,
  3127. RN_Links[RTM_NET_NUMBER_LIST_LINK]);
  3128. if (!IsEnumerator (node)) {
  3129. res = NetNumCmp (Table, &tempNode->RN_Route, &node->RN_Route);
  3130. if ((res < 0)
  3131. ||((res == 0)
  3132. &&((tempNode->RN_Route.XX_PROTOCOL
  3133. < node->RN_Route.XX_PROTOCOL)
  3134. ||((tempNode->RN_Route.XX_PROTOCOL
  3135. ==node->RN_Route.XX_PROTOCOL)
  3136. &&((tempNode->RN_Route.XX_INTERFACE
  3137. < node->RN_Route.XX_INTERFACE)
  3138. ||((tempNode->RN_Route.XX_INTERFACE
  3139. ==node->RN_Route.XX_INTERFACE)
  3140. && (NextHopCmp (Table, &tempNode->RN_Route,
  3141. &node->RN_Route)
  3142. < 0)))))))
  3143. break;
  3144. }
  3145. curMaster = curMaster->Flink;
  3146. #if DBG
  3147. IF_DEBUG (DISPLAY_TABLE)
  3148. curMasterIdx += 1;
  3149. #endif
  3150. }
  3151. // Insert at the located point
  3152. InsertTailList (curMaster, curTemp);
  3153. SetSorted (tempNode);
  3154. #if DBG
  3155. IF_DEBUG (DISPLAY_TABLE) {
  3156. AddRouteToLB (Table, tempNode, curMasterIdx);
  3157. curMasterIdx += 1;
  3158. }
  3159. #endif
  3160. }
  3161. // We are done now
  3162. }
  3163. VOID
  3164. ExpirationAPC (
  3165. PVOID Context,
  3166. ULONG TimeLow,
  3167. LONG TimeHigh
  3168. ) {
  3169. #define Table ((PRTM_TABLE)Context)
  3170. if (InterlockedIncrement (&Table->RT_ExpirationWorkerPending)==0) {
  3171. do {
  3172. ProcessExpirationQueue (Table);
  3173. }
  3174. while (InterlockedDecrement (&Table->RT_ExpirationWorkerPending)>=0);
  3175. }
  3176. #undef Table
  3177. }
  3178. VOID APIENTRY
  3179. ProcessExpirationQueueWI (
  3180. PVOID Context
  3181. ) {
  3182. #define Table ((PRTM_TABLE)Context)
  3183. do {
  3184. ProcessExpirationQueue (Table);
  3185. }
  3186. while (InterlockedDecrement (&Table->RT_ExpirationWorkerPending)>=0);
  3187. #undef Table
  3188. }
  3189. // Checks if any entries in expiration queue have expired and deletes them
  3190. VOID
  3191. ProcessExpirationQueue (
  3192. PRTM_TABLE Table // Affected table
  3193. ) {
  3194. DWORD status;
  3195. ULONG tickCount = GetTickCount ();
  3196. if (!EnterSyncList (Table, &Table->RT_ExpirationQueue, TRUE))
  3197. return;
  3198. // Check all relevant entries
  3199. while (!IsListEmpty (&Table->RT_ExpirationQueue.RSL_Head)) {
  3200. PRTM_SYNC_LIST hashBasket;
  3201. PLIST_ENTRY cur;
  3202. PRTM_ROUTE_NODE node = CONTAINING_RECORD (
  3203. Table->RT_ExpirationQueue.RSL_Head.Flink,
  3204. RTM_ROUTE_NODE,
  3205. RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
  3206. LONGLONG dueTime;
  3207. ULONG timeDiff = TimeDiff (node->RN_ExpirationTime,tickCount);
  3208. InterlockedExchange (&Table->RT_ExpirationWorkerPending, 0);
  3209. if (IsPositiveTimeDiff (timeDiff)) {
  3210. // The first entry in the queue is not due yet, so are
  3211. // the others (queue is ordered by expiration time)
  3212. dueTime = (LONGLONG)timeDiff*(-10000);
  3213. status = NtSetTimer (Table->RT_ExpirationTimer,
  3214. (PLARGE_INTEGER)&dueTime,
  3215. ExpirationAPC,
  3216. Table,
  3217. FALSE,
  3218. 0,
  3219. NULL);
  3220. ASSERTMSG ("Could not set expiration timer ", NT_SUCCESS (status));
  3221. break;
  3222. }
  3223. hashBasket = node->RN_Hash;
  3224. // We need to lock the hash basket to delete the entry
  3225. if (!EnterSyncList (Table, hashBasket, FALSE)) {
  3226. // Can't do it at once, so we first release
  3227. // expiration queue lock (to prevent a deadlock)
  3228. // and then try again)
  3229. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  3230. if (!EnterSyncList (Table, hashBasket, TRUE)) {
  3231. return;
  3232. }
  3233. if (!EnterSyncList (Table, &Table->RT_ExpirationQueue, TRUE)) {
  3234. LeaveSyncList (Table, hashBasket);
  3235. return;
  3236. }
  3237. // Now we have both of them, but is our route still there
  3238. if (node!=CONTAINING_RECORD (
  3239. Table->RT_ExpirationQueue.RSL_Head.Flink,
  3240. RTM_ROUTE_NODE,
  3241. RN_Links[RTM_EXPIRATION_QUEUE_LINK])) {
  3242. // Well, somebody took care of it while we were
  3243. // waiting
  3244. LeaveSyncList (Table, hashBasket);
  3245. // We'll try the next one
  3246. continue;
  3247. }
  3248. // Unlikely, but its due time could have changed
  3249. timeDiff = TimeDiff (node->RN_ExpirationTime,tickCount);
  3250. if (IsPositiveTimeDiff (timeDiff) ) {
  3251. // The first entry in the queue is not due yet, so are
  3252. // the others (queue is ordered by expiration time)
  3253. LeaveSyncList (Table, hashBasket);
  3254. dueTime = (LONGLONG)timeDiff*(-10000);
  3255. // Well, we are done then (this was the first entry
  3256. // in the queue (we just checked), so other are not
  3257. // due as well)
  3258. // Just make sure that updated thread returns soon enough
  3259. // to take care of our first entry
  3260. status = NtSetTimer (Table->RT_ExpirationTimer,
  3261. (PLARGE_INTEGER)&dueTime,
  3262. ExpirationAPC,
  3263. Table,
  3264. FALSE,
  3265. 0,
  3266. NULL);
  3267. ASSERTMSG ("Could not set expiration timer ", NT_SUCCESS (status));
  3268. break;
  3269. }
  3270. }
  3271. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  3272. if (IsBest(node)) {
  3273. // We need to locate the best node after this one is gone
  3274. PRTM_ROUTE_NODE bestNode = NULL;
  3275. cur = node->RN_Links[RTM_NET_NUMBER_HASH_LINK].Blink;
  3276. while (cur!=&hashBasket->RSL_Head) {
  3277. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  3278. cur,
  3279. RTM_ROUTE_NODE,
  3280. RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  3281. if (!IsEnumerator (node1)
  3282. && IsEnabled(node1)) {
  3283. if (NetNumCmp (Table, &node->RN_Route, &node1->RN_Route)==0) {
  3284. if ((bestNode==NULL)
  3285. || (MetricCmp (Table,
  3286. &bestNode->RN_Route,
  3287. &node1->RN_Route)>0))
  3288. bestNode = node1;
  3289. }
  3290. else
  3291. break;
  3292. }
  3293. cur = cur->Blink;
  3294. }
  3295. cur = node->RN_Links[RTM_NET_NUMBER_HASH_LINK].Flink;
  3296. while (cur!=&hashBasket->RSL_Head) {
  3297. PRTM_ROUTE_NODE node1 = CONTAINING_RECORD (
  3298. cur,
  3299. RTM_ROUTE_NODE,
  3300. RN_Links[RTM_NET_NUMBER_HASH_LINK]);
  3301. if (!IsEnumerator (node1)
  3302. && IsEnabled(node1)) {
  3303. if (NetNumCmp (Table, &node->RN_Route, &node1->RN_Route)==0) {
  3304. if ((bestNode==NULL)
  3305. || (MetricCmp (Table,
  3306. &bestNode->RN_Route,
  3307. &node1->RN_Route)>0))
  3308. bestNode = node1;
  3309. }
  3310. else
  3311. break;
  3312. }
  3313. cur = cur->Flink;
  3314. }
  3315. if (bestNode!=NULL) { // We did find another node
  3316. ResetBest (node);
  3317. SetBest (bestNode);
  3318. NotifyClients (Table,
  3319. NULL,
  3320. RTM_CURRENT_BEST_ROUTE|RTM_PREVIOUS_BEST_ROUTE,
  3321. &bestNode->RN_Route,
  3322. &node->RN_Route);
  3323. }
  3324. else {
  3325. InterlockedDecrement (&Table->RT_NetworkCount);
  3326. // No best node anymore
  3327. NotifyClients (Table,
  3328. NULL,
  3329. RTM_PREVIOUS_BEST_ROUTE,
  3330. NULL,
  3331. &node->RN_Route);
  3332. }
  3333. }
  3334. if (RemoveRouteNode (Table, node)!=NO_ERROR) {
  3335. LeaveSyncList (Table, hashBasket);
  3336. return;
  3337. }
  3338. LeaveSyncList (Table, hashBasket);
  3339. // Reenter expiration queue to continue
  3340. if (!EnterSyncList (Table, &Table->RT_ExpirationQueue, TRUE))
  3341. return;
  3342. }
  3343. LeaveSyncList (Table, &Table->RT_ExpirationQueue);
  3344. }
  3345. DWORD
  3346. DoEnumerate (
  3347. PRTM_TABLE Table,
  3348. PRTM_ENUMERATOR EnumPtr,
  3349. DWORD EnableFlag
  3350. ) {
  3351. // Now, we'll go ahead and find an entry that satisfies
  3352. // specified criteria
  3353. while (1) { // This external loop is needed for the case
  3354. // of enumerating through the hash table when
  3355. // reaching the end of the list doesn't mean that process has
  3356. // to be stopped: we need to move the next basket till
  3357. // we've gone through all of them
  3358. PLIST_ENTRY cur = EnumPtr->RE_Links[EnumPtr->RE_Link].Blink;
  3359. while (cur!=EnumPtr->RE_Head) {
  3360. PRTM_ROUTE_NODE node = CONTAINING_RECORD (cur, RTM_ROUTE_NODE,
  3361. RN_Links[EnumPtr->RE_Link]);
  3362. INT res;
  3363. if (!IsEnumerator (node)
  3364. && ((EnableFlag==RTM_ANY_ENABLE_STATE)
  3365. || IsSameEnableState(node,EnableFlag))) {
  3366. if ((EnumPtr->RE_Link!=RTM_NET_NUMBER_HASH_LINK)
  3367. && (EnumPtr->RE_Hash!=node->RN_Hash)) {
  3368. if (EnumPtr->RE_Hash!=NULL)
  3369. LeaveSyncList (Table, EnumPtr->RE_Hash);
  3370. EnumPtr->RE_Hash = node->RN_Hash;
  3371. if (!EnterSyncList (Table, node->RN_Hash, FALSE)) {
  3372. RemoveEntryList (&EnumPtr->RE_Links[EnumPtr->RE_Link]);
  3373. InsertHeadList (cur, &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  3374. LeaveSyncList (Table, EnumPtr->RE_Lock);
  3375. if (!EnterSyncList (Table, EnumPtr->RE_Hash, TRUE)) {
  3376. EnumPtr->RE_Hash = NULL;
  3377. return ERROR_NO_SYSTEM_RESOURCES;
  3378. }
  3379. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  3380. LeaveSyncList (Table, EnumPtr->RE_Hash);
  3381. EnumPtr->RE_Hash = NULL;
  3382. return ERROR_NO_SYSTEM_RESOURCES;
  3383. }
  3384. cur = EnumPtr->RE_Links[EnumPtr->RE_Link].Blink;
  3385. continue;
  3386. }
  3387. }
  3388. switch (EnumPtr->RE_Link) {
  3389. // Using the interface link:
  3390. case RTM_INTERFACE_LIST_LINK:
  3391. #if !RTM_USE_PROTOCOL_LISTS
  3392. case RTM_NET_NUMBER_HASH_LINK:
  3393. #endif
  3394. // Check protocol if necessary
  3395. if ((EnumPtr->RE_EnumerationFlags & RTM_ONLY_THIS_PROTOCOL)
  3396. && (EnumPtr->RE_Route.XX_PROTOCOL
  3397. !=node->RN_Route.XX_PROTOCOL)) {
  3398. // Break out to move ahead if protocol
  3399. // check fails
  3400. break;
  3401. }
  3402. // else Pass through to do other checks
  3403. // Using the protocol link: (thus we don't
  3404. // care about interface or we would have used
  3405. // interface link - see RtmCreateEnumerationHandle).
  3406. #if RTM_USE_PROTOCOL_LISTS
  3407. case RTM_PROTOCOL_LIST_LINK:
  3408. // Using the hash link: (thus we don't
  3409. // care about interface and protocol or we would have
  3410. // used other links - see RtmCreateEnumerationHandle).
  3411. case RTM_NET_NUMBER_HASH_LINK:
  3412. #endif
  3413. // Check the network number if necessary
  3414. if (EnumPtr->RE_EnumerationFlags & RTM_ONLY_THIS_NETWORK) {
  3415. res = NetNumCmp (Table, &EnumPtr->RE_Route,
  3416. &node->RN_Route);
  3417. if (res == 0)
  3418. // Match, continue checks
  3419. ;
  3420. else if ((res > 0)
  3421. && (EnumPtr->RE_Link
  3422. ==RTM_NET_NUMBER_HASH_LINK)) {
  3423. // Hash list are ordered by net
  3424. // number, so if we got network
  3425. // number that is less than ours
  3426. // we don't have search anymore
  3427. // (we are going backwards)
  3428. return ERROR_NO_MORE_ROUTES;
  3429. }
  3430. else // Otherwise break out of switch
  3431. // statement to continue the search
  3432. break;
  3433. }
  3434. // We didn't care about net number,
  3435. // so current entry will do
  3436. if (!(EnumPtr->RE_EnumerationFlags & RTM_ONLY_BEST_ROUTES)
  3437. || IsBest(node)) {
  3438. RemoveEntryList (&EnumPtr->RE_Links[EnumPtr->RE_Link]);
  3439. InsertTailList (cur,
  3440. &EnumPtr->RE_Links[EnumPtr->RE_Link]);
  3441. return NO_ERROR;
  3442. }
  3443. break;
  3444. }
  3445. }
  3446. // Go get next entry
  3447. cur = cur->Blink;
  3448. }
  3449. // If we are not going through hash table or
  3450. // we just interested in one network
  3451. // or we've already been through all baskets
  3452. // call it quits
  3453. if ((EnumPtr->RE_Link!=RTM_NET_NUMBER_HASH_LINK)
  3454. || (EnumPtr->RE_EnumerationFlags & RTM_ONLY_THIS_NETWORK)
  3455. || (EnumPtr->RE_Lock
  3456. ==&Table->RT_NetNumberHash[Table->RT_HashTableSize-1]))
  3457. break;
  3458. // Otherwise, go through the next basket
  3459. RemoveEntryList (&EnumPtr->RE_Links[RTM_NET_NUMBER_HASH_LINK]);
  3460. LeaveSyncList (Table, EnumPtr->RE_Lock);
  3461. EnumPtr->RE_Lock += 1;
  3462. EnumPtr->RE_Head = &EnumPtr->RE_Lock->RSL_Head;
  3463. if (!EnterSyncList (Table, EnumPtr->RE_Lock, TRUE)) {
  3464. InitializeListEntry (&EnumPtr->RE_Links[RTM_NET_NUMBER_HASH_LINK]);
  3465. return ERROR_NO_SYSTEM_RESOURCES;
  3466. }
  3467. InsertTailList (EnumPtr->RE_Head,
  3468. &EnumPtr->RE_Links[RTM_NET_NUMBER_HASH_LINK]);
  3469. }
  3470. return ERROR_NO_MORE_ROUTES;
  3471. }
  3472. //----------------------------------------------------------------------------
  3473. // SetMaskCount
  3474. //
  3475. // Does a binary search of the g_meMaskTable to find the matching
  3476. // mask entry and increments the count for the specified mask
  3477. //
  3478. //----------------------------------------------------------------------------
  3479. VOID
  3480. SetMaskCount(
  3481. PIP_NETWORK pinNet,
  3482. BOOL bAdd
  3483. )
  3484. {
  3485. DWORD dwLower, dwUpper, dwInd, dwMask;
  3486. dwLower = 0;
  3487. dwUpper = MAX_MASKS;
  3488. dwMask = pinNet-> N_NetMask;
  3489. while ( dwLower <= dwUpper )
  3490. {
  3491. dwInd = ( dwLower + dwUpper ) / 2;
  3492. if ( g_meMaskTable[ dwInd ].dwMask < dwMask )
  3493. {
  3494. //
  3495. // Match is to be found in upper half of search region.
  3496. //
  3497. dwLower = dwInd + 1;
  3498. }
  3499. else if ( g_meMaskTable[ dwInd ].dwMask > dwMask )
  3500. {
  3501. //
  3502. // Match is to be found in lower half of search region.
  3503. //
  3504. dwUpper = dwInd - 1;
  3505. }
  3506. else
  3507. {
  3508. //
  3509. // Match found
  3510. //
  3511. if ( bAdd )
  3512. {
  3513. InterlockedIncrement( &g_meMaskTable[ dwInd ].dwCount );
  3514. }
  3515. else
  3516. {
  3517. InterlockedDecrement( &g_meMaskTable[ dwInd ].dwCount );
  3518. }
  3519. break;
  3520. }
  3521. }
  3522. }