Source code of Windows XP (NT5)
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.

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