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.

1436 lines
45 KiB

  1. //****************************************************************************
  2. //
  3. // Microsoft Windows NT RIP
  4. //
  5. // Copyright 1995-96
  6. //
  7. //
  8. // Revision History
  9. //
  10. //
  11. // 2/26/95 Gurdeep Singh Pall Picked up from JBallard's team
  12. //
  13. //
  14. // Description: RIP Tables Manipulation Functions
  15. //
  16. //****************************************************************************
  17. #include "pchrip.h"
  18. #pragma hdrstop
  19. //-----------------------------------------------------------------------------
  20. // Function: InitializeRouteTable
  21. //
  22. // Initializes hash table
  23. //-----------------------------------------------------------------------------
  24. DWORD InitializeRouteTable() {
  25. LPHASH_TABLE_ENTRY *lplpentry, *lplpend;
  26. lplpend = g_ripcfg.lpRouteTable + HASH_TABLE_SIZE;
  27. for (lplpentry = g_ripcfg.lpRouteTable; lplpentry < lplpend; lplpentry++) {
  28. *lplpentry = NULL;
  29. }
  30. return 0;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Function: GetRouteTableEntry
  34. //
  35. // Looks for an entry with the specified address and mask, learnt using the
  36. // specified interface. If the entry is not found, one is created.
  37. //-----------------------------------------------------------------------------
  38. LPHASH_TABLE_ENTRY GetRouteTableEntry(DWORD dwIndex, DWORD dwAddress,
  39. DWORD dwNetmask) {
  40. INT hashval;
  41. IN_ADDR addr;
  42. LPHASH_TABLE_ENTRY rt_entry;
  43. LPHASH_TABLE_ENTRY prev_rt_entry;
  44. hashval = HASH_VALUE(dwAddress);
  45. ASSERT(hashval < HASH_TABLE_SIZE);
  46. RIP_LOCK_ROUTETABLE();
  47. prev_rt_entry = rt_entry = g_ripcfg.lpRouteTable[hashval];
  48. while (rt_entry != NULL) {
  49. if ((rt_entry->dwDestaddr == dwAddress) &&
  50. (rt_entry->dwNetmask == dwNetmask)) {
  51. break;
  52. }
  53. prev_rt_entry = rt_entry;
  54. rt_entry = rt_entry->next;
  55. }
  56. if (rt_entry == NULL) {
  57. // entry was not found, so allocate a new one
  58. rt_entry = malloc(sizeof(HASH_TABLE_ENTRY));
  59. if (rt_entry == NULL) {
  60. dbgprintf("could not allocate memory for routing-table entry");
  61. }
  62. else {
  63. rt_entry->next = NULL;
  64. rt_entry->dwFlag = NEW_ENTRY;
  65. rt_entry->dwIndex = dwIndex;
  66. rt_entry->dwProtocol = IRE_PROTO_RIP;
  67. rt_entry->dwDestaddr = dwAddress;
  68. if (prev_rt_entry != NULL) {
  69. rt_entry->prev = prev_rt_entry;
  70. prev_rt_entry->next = rt_entry;
  71. }
  72. else {
  73. rt_entry->prev = NULL;
  74. g_ripcfg.lpRouteTable[hashval] = rt_entry;
  75. }
  76. InterlockedIncrement(&g_ripcfg.lpStatsTable->dwRouteCount);
  77. }
  78. }
  79. RIP_UNLOCK_ROUTETABLE();
  80. // check_rt_entries();
  81. return rt_entry;
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Function: RouteTableEntryExists
  85. //
  86. // This function returns TRUE if an entry to the specified address
  87. // exists with the specified index.
  88. //-----------------------------------------------------------------------------
  89. BOOL RouteTableEntryExists(DWORD dwIndex, DWORD dwAddress) {
  90. INT hashval;
  91. LPHASH_TABLE_ENTRY rt_entry;
  92. hashval = HASH_VALUE(dwAddress);
  93. RIP_LOCK_ROUTETABLE();
  94. rt_entry = g_ripcfg.lpRouteTable[hashval];
  95. while (rt_entry != NULL) {
  96. if (rt_entry->dwDestaddr == dwAddress) {
  97. break;
  98. }
  99. rt_entry = rt_entry->next;
  100. }
  101. RIP_UNLOCK_ROUTETABLE();
  102. return (rt_entry == NULL ? FALSE : TRUE);
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Function: AddZombieRouteTableEntry
  106. //
  107. // This function adds a special route-table entry known as a Zombie
  108. // route entry. In the case of border gateways which summarize attached
  109. // subnets and send a single entry for the network, and in the case
  110. // of routers whose interfaces have different subnet masks, the destination
  111. // that RIP will send will be different from the destination in RIP's table.
  112. // This makes it possible for the destination to get bounced back at RIP by
  113. // some other router; RIP would then add an entry for the bogus route, and
  114. // advertise the route back again, and a count to infinity would commence.
  115. //
  116. // Zombie entries exist to prevent this from happening:
  117. // they have metrics of zero, so they will not be replaced
  118. // by RIP-learnt routes (all of which have a metric of at least 1);
  119. // they are excluded from updates sent
  120. // they are excluded from updates written to the system routing table
  121. // they can be timed-out
  122. // The above conditions ensure that zombies do not interfere with the working
  123. // of RIP, EXCEPT in the case where they prevent RIP from adding a normal entry
  124. // for a route which was summarized in a previous update and which is therefore
  125. // not really a RIP route at all.
  126. //-----------------------------------------------------------------------------
  127. DWORD AddZombieRouteTableEntry(LPRIP_ADDRESS lpaddr, DWORD dwNetwork,
  128. DWORD dwNetmask) {
  129. LPHASH_TABLE_ENTRY rt_entry;
  130. rt_entry = GetRouteTableEntry(lpaddr->dwIndex, dwNetwork, dwNetmask);
  131. if (rt_entry == NULL) {
  132. dbgprintf("could not make entry for network in routing table");
  133. return ERROR_NOT_ENOUGH_MEMORY;
  134. }
  135. // don't want to overwrite an existing entry, if there is one
  136. if ((rt_entry->dwFlag & NEW_ENTRY) == 0 &&
  137. (rt_entry->dwFlag & ROUTE_ZOMBIE) == 0) {
  138. return 0;
  139. }
  140. // since the only reason this entry exists is because a
  141. // subnet we are sending is being summarized or truncated, we have to
  142. // set up values to make sure this entry is not considered in
  143. // normal processing; (e.g. metric of 0 to make sure it is not
  144. // replaced by a RIP-learnt route)
  145. // however, we do allow it to be timed out
  146. rt_entry->dwIndex = (DWORD)~0;
  147. rt_entry->dwFlag = (GARBAGE_TIMER | ROUTE_ZOMBIE);
  148. rt_entry->lTimeout = (LONG)DEF_GARBAGETIMEOUT;
  149. rt_entry->dwDestaddr = dwNetwork;
  150. rt_entry->dwNetmask = dwNetmask;
  151. rt_entry->dwNexthop = 0;
  152. rt_entry->dwProtocol = IRE_PROTO_OTHER;
  153. rt_entry->dwMetric = 0;
  154. return 0;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Function: DeleteRouteTableEntry
  158. //
  159. // This function removes a route from the route table. Assumes
  160. // that the route table is already locked
  161. //-----------------------------------------------------------------------------
  162. VOID DeleteRouteTableEntry(int pos, LPHASH_TABLE_ENTRY rt_entry) {
  163. IN_ADDR addr;
  164. CHAR szDest[32] = {0};
  165. CHAR* pszTemp;
  166. if (rt_entry == NULL) { return; }
  167. addr.s_addr = rt_entry->dwDestaddr;
  168. pszTemp = inet_ntoa(addr);
  169. if (pszTemp != NULL) {
  170. strcpy(szDest, pszTemp);
  171. }
  172. dbgprintf("Removing entry %d with destination IP address %s "
  173. "from interface %d in RIP routing table",
  174. pos, szDest, rt_entry->dwIndex);
  175. if (rt_entry->prev != NULL) {
  176. rt_entry->prev->next = rt_entry->next;
  177. if (rt_entry->next != NULL) {
  178. rt_entry->next->prev = rt_entry->prev;
  179. }
  180. }
  181. else {
  182. g_ripcfg.lpRouteTable[pos] = rt_entry->next;
  183. if (rt_entry->next != NULL) {
  184. rt_entry->next->prev = NULL;
  185. }
  186. }
  187. InterlockedDecrement(&g_ripcfg.lpStatsTable->dwRouteCount);
  188. // delete the route from the IP table as well
  189. if ((rt_entry->dwFlag & ROUTE_ZOMBIE) == 0) {
  190. UpdateSystemRouteTable(rt_entry, FALSE);
  191. }
  192. free(rt_entry);
  193. return;
  194. }
  195. void check_rt_entries() {
  196. int pos;
  197. LPHASH_TABLE_ENTRY rt_entry;
  198. LPHASH_TABLE_ENTRY prev_rt_entry = NULL ;
  199. RIP_LOCK_ROUTETABLE();
  200. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  201. rt_entry = g_ripcfg.lpRouteTable[pos];
  202. while (rt_entry != NULL) {
  203. if (rt_entry == rt_entry->next) {
  204. DebugBreak();
  205. }
  206. if (rt_entry == rt_entry->prev) {
  207. DebugBreak();
  208. }
  209. if (rt_entry->prev != NULL) {
  210. if (rt_entry->prev != prev_rt_entry) {
  211. DebugBreak();
  212. }
  213. }
  214. prev_rt_entry = rt_entry;
  215. rt_entry = rt_entry->next;
  216. }
  217. }
  218. RIP_UNLOCK_ROUTETABLE();
  219. return;
  220. }
  221. #if 0
  222. //-----------------------------------------------------------------------------
  223. // Function: DumpRouteTable
  224. //
  225. //-----------------------------------------------------------------------------
  226. VOID DumpRouteTable() {
  227. INT pos;
  228. HANDLE hRoutesDump;
  229. LPVOID lpRoutesDump;
  230. DWORD dwSize, dwCount;
  231. SECURITY_ATTRIBUTES sa;
  232. SECURITY_DESCRIPTOR sd;
  233. LPHASH_TABLE_ENTRY rt_entry, rt_dump;
  234. RIP_LOCK_ADDRTABLE();
  235. // get rid of any previous dump
  236. if (g_ripcfg.hRoutesDump != NULL) {
  237. CloseHandle(g_ripcfg.hRoutesDump);
  238. g_ripcfg.hRoutesDump = NULL;
  239. }
  240. RIP_UNLOCK_ADDRTABLE();
  241. dwCount = 0;
  242. RIP_LOCK_ROUTETABLE();
  243. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  244. rt_entry = g_ripcfg.lpRouteTable[pos];
  245. while (rt_entry != NULL) {
  246. ++dwCount;
  247. rt_entry = rt_entry->next;
  248. }
  249. }
  250. // set the size to be the route table size plus the preceding count
  251. dwSize = sizeof(DWORD) + dwCount * sizeof(HASH_TABLE_ENTRY);
  252. // initialize security for this shared memory
  253. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  254. sa.bInheritHandle = FALSE;
  255. if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
  256. RIP_UNLOCK_ROUTETABLE();
  257. return;
  258. }
  259. if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) {
  260. RIP_UNLOCK_ROUTETABLE();
  261. return;
  262. }
  263. sa.lpSecurityDescriptor = &sd;
  264. // request the shared memory
  265. hRoutesDump = CreateFileMapping(INVALID_HANDLE_VALUE,
  266. &sa, PAGE_READWRITE,
  267. 0, dwSize,
  268. RIP_DUMP_ROUTES_NAME);
  269. if (hRoutesDump == NULL) {
  270. RIP_UNLOCK_ROUTETABLE();
  271. return;
  272. }
  273. // set up a pointer to the memory
  274. lpRoutesDump = MapViewOfFile(hRoutesDump, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  275. if (lpRoutesDump == NULL) {
  276. CloseHandle(hRoutesDump);
  277. RIP_UNLOCK_ROUTETABLE();
  278. return;
  279. }
  280. // skip the first four bytes, which will contain the count
  281. rt_dump = (LPHASH_TABLE_ENTRY)((LPBYTE)lpRoutesDump + sizeof(DWORD));
  282. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  283. rt_entry = g_ripcfg.lpRouteTable[pos];
  284. while (rt_entry != NULL) {
  285. CopyMemory(rt_dump, rt_entry, sizeof(HASH_TABLE_ENTRY));
  286. rt_entry = rt_entry->next;
  287. ++rt_dump;
  288. }
  289. }
  290. // store the count in the first DWORD
  291. *(LPDWORD)lpRoutesDump = dwCount;
  292. RIP_UNLOCK_ROUTETABLE();
  293. // let go of the memory-map
  294. UnmapViewOfFile(lpRoutesDump);
  295. // save the shared-memory handle
  296. RIP_LOCK_ADDRTABLE();
  297. RIP_UNLOCK_ADDRTABLE();
  298. return;
  299. }
  300. #endif
  301. //-----------------------------------------------------------------------------
  302. // Function: ProcessRouteTableChanges
  303. //
  304. // Process the changes, updating metrics for routes. If necessary,
  305. // this function will trigger an update.
  306. // Assumes address table is locked.
  307. //-----------------------------------------------------------------------------
  308. void ProcessRouteTableChanges(BOOL bTriggered) {
  309. int pos;
  310. BOOL bNeedTriggeredUpdate;
  311. LPHASH_TABLE_ENTRY rt_entry;
  312. DWORD dwLastTrigger, dwMsecsTillUpdate;
  313. DWORD dwSystime, dwSilentRIP, dwTrigger, dwTriggerFrequency;
  314. // check_rt_entries();
  315. RIP_LOCK_PARAMS();
  316. dwSilentRIP = g_params.dwSilentRIP;
  317. dwTrigger = g_params.dwTriggeredUpdates;
  318. dwTriggerFrequency = g_params.dwMaxTriggerFrequency;
  319. RIP_UNLOCK_PARAMS();
  320. RIP_LOCK_ROUTETABLE();
  321. bNeedTriggeredUpdate = FALSE;
  322. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  323. rt_entry = g_ripcfg.lpRouteTable[pos];
  324. while (rt_entry != NULL) {
  325. if ((rt_entry->dwFlag & ROUTE_CHANGE) == 0 &&
  326. (rt_entry->dwFlag & ROUTE_UPDATE) == 0) {
  327. rt_entry = rt_entry->next;
  328. continue;
  329. }
  330. if ((rt_entry->dwFlag & ROUTE_CHANGE) != 0) {
  331. bNeedTriggeredUpdate = TRUE;
  332. }
  333. // update if this is a RIP-learnt route
  334. if (rt_entry->dwProtocol == IRE_PROTO_RIP) {
  335. UpdateSystemRouteTable(rt_entry, TRUE);
  336. }
  337. // clear the update flag, now that the route
  338. // has been updated in the system table
  339. rt_entry->dwFlag &= ~ROUTE_UPDATE;
  340. rt_entry = rt_entry->next;
  341. }
  342. }
  343. dwSystime = GetTickCount();
  344. dwLastTrigger = g_ripcfg.dwLastTriggeredUpdate;
  345. dwMsecsTillUpdate = g_ripcfg.dwMillisecsTillFullUpdate;
  346. // adjust the times if the clock has wrapped around past zero
  347. if (dwSystime < dwLastTrigger) {
  348. dwSystime += (DWORD)~0 - dwLastTrigger;
  349. dwLastTrigger = 0;
  350. }
  351. // we generate a triggered update iff:
  352. // 1. this call was made because of a response received
  353. // 2. we are not in silent RIP mode
  354. // 3. triggered updates are not disabled
  355. // 4. the minimum configured interval between triggered updates
  356. // has elapsed
  357. // 5. the time till the next regular update is greater than the
  358. // configured minimum interval between triggered updates
  359. // if the system clock has wrapped around to zero, skip the condition 4;
  360. // we know the clock has wrapped around if dwSystime is less than
  361. // the last triggered update time
  362. if (bTriggered && bNeedTriggeredUpdate &&
  363. dwSilentRIP == 0 &&
  364. dwTrigger != 0 &&
  365. (dwSystime - dwLastTrigger) >= dwTriggerFrequency &&
  366. dwMsecsTillUpdate >= dwTriggerFrequency) {
  367. // update the last triggered update time
  368. InterlockedExchange(&g_ripcfg.dwLastTriggeredUpdate, GetTickCount());
  369. // send out the routing table, but only include changes
  370. BroadcastRouteTableContents(bTriggered, TRUE);
  371. }
  372. ClearChangeFlags();
  373. InterlockedExchange(&g_ripcfg.dwRouteChanged, 0);
  374. RIP_UNLOCK_ROUTETABLE();
  375. return;
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Function: ClearChangeFlags
  379. //
  380. // This function clears all the change flags in the table after an update.
  381. // Assumes that the routing table is locked.
  382. //-----------------------------------------------------------------------------
  383. VOID ClearChangeFlags() {
  384. int pos;
  385. LPHASH_TABLE_ENTRY rt_entry;
  386. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  387. rt_entry = g_ripcfg.lpRouteTable[pos];
  388. while (rt_entry != NULL) {
  389. rt_entry->dwFlag &= ~ROUTE_CHANGE;
  390. rt_entry = rt_entry->next;
  391. }
  392. }
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Function: DoTimedOperations()
  396. //
  397. // This function updates the routing table entries' timers periodically,
  398. // and handles deletion of timed-out routes.
  399. //-----------------------------------------------------------------------------
  400. VOID DoTimedOperations(DWORD dwMillisecsSinceLastCall) {
  401. int pos;
  402. IN_ADDR addr;
  403. DWORD dwGarbageTimeout;
  404. HASH_TABLE_ENTRY *rt_entry;
  405. HASH_TABLE_ENTRY *rt_entry_next;
  406. char szDest[32] = {0};
  407. char szNexthop[32] = {0};
  408. char* pszTemp;
  409. // read the garbage timeout and adjust for number of times
  410. // this routine will be called over the interval
  411. RIP_LOCK_PARAMS();
  412. dwGarbageTimeout = g_params.dwGarbageTimeout;
  413. RIP_UNLOCK_PARAMS();
  414. RIP_LOCK_ROUTETABLE();
  415. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  416. rt_entry = g_ripcfg.lpRouteTable[pos];
  417. while (rt_entry != NULL) {
  418. rt_entry_next = rt_entry->next;
  419. if (rt_entry->lTimeout > (LONG)dwMillisecsSinceLastCall) {
  420. rt_entry->lTimeout -= dwMillisecsSinceLastCall;
  421. }
  422. else {
  423. // timeout is all the way down
  424. addr.s_addr = rt_entry->dwDestaddr;
  425. pszTemp = inet_ntoa(addr);
  426. if (pszTemp != NULL) {
  427. strcpy(szDest, pszTemp);
  428. }
  429. addr.s_addr = rt_entry->dwNexthop;
  430. pszTemp = inet_ntoa(addr);
  431. if (pszTemp != NULL) {
  432. strcpy(szNexthop, pszTemp);
  433. }
  434. if (rt_entry->dwFlag & TIMEOUT_TIMER) {
  435. dbgprintf("Timing out route to %s over netcard %d, "
  436. "with next hop of %s",
  437. szDest, rt_entry->dwIndex, szNexthop);
  438. rt_entry->lTimeout = (LONG)dwGarbageTimeout;
  439. rt_entry->dwFlag &= ~TIMEOUT_TIMER;
  440. rt_entry->dwFlag |= (GARBAGE_TIMER | ROUTE_CHANGE);
  441. rt_entry->dwMetric = METRIC_INFINITE;
  442. InterlockedExchange(&g_ripcfg.dwRouteChanged, 1);
  443. }
  444. else
  445. if (rt_entry->dwFlag & GARBAGE_TIMER) {
  446. // time to delete this
  447. addr.s_addr = rt_entry->dwDestaddr;
  448. pszTemp = inet_ntoa(addr);
  449. if (pszTemp != NULL) {
  450. strcpy(szDest, pszTemp);
  451. }
  452. dbgprintf("Deleting route to %s over netcard %d "
  453. "with next hop of %s",
  454. szDest, rt_entry->dwIndex, szNexthop);
  455. DeleteRouteTableEntry(pos, rt_entry);
  456. }
  457. }
  458. rt_entry = rt_entry_next;
  459. }
  460. }
  461. RIP_UNLOCK_ROUTETABLE();
  462. return;
  463. }
  464. DWORD BroadcastRouteTableRequests() {
  465. INT iErr;
  466. DWORD dwSize;
  467. LPRIP_ENTRY lpentry;
  468. SOCKADDR_IN destaddr;
  469. LPRIP_HEADER lpheader;
  470. BYTE buffer[RIP_MESSAGE_SIZE];
  471. LPRIP_ADDRESS lpaddr, lpend;
  472. RIP_LOCK_ADDRTABLE();
  473. if (g_ripcfg.dwAddrCount > 0) {
  474. destaddr.sin_family = AF_INET;
  475. destaddr.sin_port = htons(RIP_PORT);
  476. lpheader = (LPRIP_HEADER)buffer;
  477. lpheader->chCommand = RIP_REQUEST;
  478. lpheader->wReserved = 0;
  479. lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  480. lpentry->dwAddress = 0;
  481. lpentry->wReserved = 0;
  482. lpentry->wAddrFamily = 0;
  483. lpentry->dwReserved1 = 0;
  484. lpentry->dwReserved2 = 0;
  485. lpentry->dwMetric = htonl(METRIC_INFINITE);
  486. dwSize = sizeof(RIP_HEADER) + sizeof(RIP_ENTRY);
  487. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  488. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  489. // skip disabled interfaces
  490. if (lpaddr->sock == INVALID_SOCKET) {
  491. continue;
  492. }
  493. // send out broadcast requests as RIPv1 packets
  494. lpheader->chVersion = 1;
  495. // set the destination to the broadcast address on this subnet
  496. destaddr.sin_addr.s_addr = (lpaddr->dwAddress |
  497. ~lpaddr->dwNetmask);
  498. iErr = sendto(lpaddr->sock, buffer, dwSize, 0,
  499. (LPSOCKADDR)&destaddr, sizeof(SOCKADDR_IN));
  500. if (iErr == SOCKET_ERROR) {
  501. dbgprintf("error %d occurred broadcasting route table request "
  502. "on netcard %d using IP address %s",
  503. WSAGetLastError(), lpaddr->dwIndex,
  504. inet_ntoa(destaddr.sin_addr));
  505. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  506. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
  507. }
  508. else {
  509. InterlockedIncrement(&lpaddr->lpstats->dwRequestsSent);
  510. }
  511. // send out multicast requests as RIPv2 packets
  512. lpheader->chVersion = 2;
  513. // set the destination to the RIP multicast address on this net
  514. destaddr.sin_addr.s_addr = RIP_MULTIADDR;
  515. iErr = sendto(lpaddr->sock, buffer, dwSize, 0,
  516. (LPSOCKADDR)&destaddr, sizeof(SOCKADDR_IN));
  517. if (iErr == SOCKET_ERROR) {
  518. dbgprintf("error %d occurred multicasting route table request "
  519. "on netcard %d using IP address %s",
  520. WSAGetLastError(), lpaddr->dwIndex,
  521. inet_ntoa(destaddr.sin_addr));
  522. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  523. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
  524. }
  525. else {
  526. InterlockedIncrement(&lpaddr->lpstats->dwRequestsSent);
  527. }
  528. }
  529. }
  530. RIP_UNLOCK_ADDRTABLE();
  531. return 0;
  532. }
  533. VOID InitUpdateBuffer(BYTE buffer[], LPRIP_ENTRY *lplpentry, LPDWORD lpdwSize) {
  534. LPRIP_HEADER lpheader;
  535. lpheader = (LPRIP_HEADER)buffer;
  536. lpheader->chCommand = RIP_RESPONSE;
  537. lpheader->chVersion = 1;
  538. lpheader->wReserved = 0;
  539. *lplpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  540. *lpdwSize= sizeof(RIP_HEADER);
  541. }
  542. VOID AddUpdateEntry(BYTE buffer[], LPRIP_ENTRY *lplpentry, LPDWORD lpdwSize,
  543. LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpdestaddr,
  544. DWORD dwAddress, DWORD dwMetric) {
  545. DWORD length;
  546. LPRIP_ENTRY lpentry;
  547. #ifdef ROUTE_FILTERS
  548. DWORD dwInd = 0;
  549. //
  550. // run the route thru' the announce filters
  551. //
  552. if ( g_prfAnnounceFilters != NULL )
  553. {
  554. for ( dwInd = 0; dwInd < g_prfAnnounceFilters-> dwCount; dwInd++ )
  555. {
  556. if ( g_prfAnnounceFilters-> pdwFilter[ dwInd ] == dwAddress )
  557. {
  558. dbgprintf(
  559. "Skipped route %s with next hop %s because"
  560. "of announce filter",
  561. inet_ntoa( *( (struct in_addr*)
  562. &( g_prfAnnounceFilters-> pdwFilter[ dwInd ] ) ))
  563. );
  564. return;
  565. }
  566. }
  567. }
  568. #endif
  569. if ((*lpdwSize + sizeof(RIP_ENTRY)) > RIP_MESSAGE_SIZE) {
  570. length = sendto(lpaddr->sock, buffer, *lpdwSize, 0,
  571. (LPSOCKADDR)lpdestaddr, sizeof(SOCKADDR_IN));
  572. if (length == SOCKET_ERROR || length < *lpdwSize) {
  573. dbgprintf("error %d sending update", WSAGetLastError());
  574. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  575. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, 0);
  576. }
  577. else {
  578. InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
  579. }
  580. // reinitialize the buffer that was passed in
  581. InitUpdateBuffer(buffer, lplpentry, lpdwSize);
  582. }
  583. lpentry = *lplpentry;
  584. lpentry->wReserved = 0;
  585. lpentry->wAddrFamily = htons(AF_INET);
  586. lpentry->dwAddress = dwAddress;
  587. lpentry->dwReserved1 = 0;
  588. lpentry->dwReserved2 = 0;
  589. lpentry->dwMetric = htonl(dwMetric);
  590. *lpdwSize += sizeof(RIP_ENTRY);
  591. ++(*lplpentry);
  592. }
  593. VOID FinishUpdateBuffer(BYTE buffer[], LPDWORD lpdwSize,
  594. LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpdestaddr) {
  595. DWORD length;
  596. // do nothing if no entries were added
  597. if (*lpdwSize <= sizeof(RIP_HEADER)) {
  598. return;
  599. }
  600. length = sendto(lpaddr->sock, buffer, *lpdwSize, 0,
  601. (LPSOCKADDR)lpdestaddr, sizeof(SOCKADDR_IN));
  602. if (length == SOCKET_ERROR || length < *lpdwSize) {
  603. dbgprintf("error %d sending update", GetLastError());
  604. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  605. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, 0);
  606. }
  607. else {
  608. InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
  609. }
  610. }
  611. //-------------------------------------------------------------------------
  612. // the following struct and three functions are used
  613. // to implement subnet hiding. when a subnet is summarized,
  614. // the network which is its summary is added to a list using the
  615. // function AddToAddressList. When another subnet of the same network
  616. // needs to be summarized, it is first searched for using the function
  617. // IsInAddressList, and if it is found, it is not re-advertised.
  618. // After the update is over, the list is freed.
  619. //-------------------------------------------------------------------------
  620. typedef struct _ADDRESS_LIST {
  621. struct _ADDRESS_LIST *next;
  622. DWORD dwAddress;
  623. DWORD dwNetmask;
  624. } ADDRESS_LIST, *LPADDRESS_LIST;
  625. DWORD AddToAddressList(LPADDRESS_LIST *lplpList, DWORD dwAddress,
  626. DWORD dwNetmask) {
  627. LPADDRESS_LIST lpal;
  628. lpal = HeapAlloc(GetProcessHeap(), 0, sizeof(ADDRESS_LIST));
  629. if (lpal == NULL) { return ERROR_NOT_ENOUGH_MEMORY; }
  630. lpal->dwAddress = dwAddress;
  631. lpal->dwNetmask = dwNetmask;
  632. lpal->next = *lplpList;
  633. *lplpList = lpal;
  634. return 0;
  635. }
  636. BOOL IsInAddressList(LPADDRESS_LIST lpList, DWORD dwAddress) {
  637. LPADDRESS_LIST lpal;
  638. for (lpal = lpList; lpal != NULL; lpal = lpal->next) {
  639. if (lpal->dwAddress == dwAddress) {
  640. return TRUE;
  641. }
  642. }
  643. return FALSE;
  644. }
  645. VOID FreeAddressList(LPADDRESS_LIST lpList) {
  646. LPADDRESS_LIST lpal, lpnext;
  647. for (lpal = lpList; lpal != NULL; lpal = lpnext) {
  648. lpnext = lpal->next;
  649. HeapFree(GetProcessHeap(), 0, lpal);
  650. }
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Function: TransmitRouteTableContents
  654. //
  655. // Sends the route tables contents, either as unicast or broadcast
  656. // depending on the destination address specified. This function assumes
  657. // that the address table is locked.
  658. //-----------------------------------------------------------------------------
  659. VOID TransmitRouteTableContents(LPRIP_ADDRESS lpaddr,
  660. LPSOCKADDR_IN lpdestaddr,
  661. BOOL bChangesOnly) {
  662. INT pos;
  663. DWORD dwSize;
  664. LPADDRESS_LIST lpnet, lpSummaries;
  665. LPRIP_ENTRY lpentry;
  666. LPHASH_TABLE_ENTRY rt_entry;
  667. BYTE buffer[RIP_MESSAGE_SIZE];
  668. DWORD dwNexthopNetaddr, dwDestNetaddr;
  669. DWORD dwSplit, dwPoison, dwHost, dwDefault;
  670. DWORD dwDestNetclassMask, dwEntryNetclassMask;
  671. DWORD dwEntryAddr, dwDestNetclassAddr, dwEntryNetclassAddr;
  672. dwDestNetaddr = (lpdestaddr->sin_addr.s_addr &
  673. SubnetMask(lpdestaddr->sin_addr.s_addr));
  674. dwDestNetclassMask = NetclassMask(lpdestaddr->sin_addr.s_addr);
  675. dwDestNetclassAddr = (lpdestaddr->sin_addr.s_addr & dwDestNetclassMask);
  676. RIP_LOCK_PARAMS();
  677. dwHost = g_params.dwAnnounceHost;
  678. dwSplit = g_params.dwSplitHorizon;
  679. dwPoison = g_params.dwPoisonReverse;
  680. dwDefault = g_params.dwAnnounceDefault;
  681. RIP_UNLOCK_PARAMS();
  682. InitUpdateBuffer(buffer, &lpentry, &dwSize);
  683. // start out with an empty list of summarized networks
  684. lpSummaries = NULL;
  685. RIP_LOCK_ROUTETABLE();
  686. #ifdef ROUTE_FILTERS
  687. RIP_LOCK_ANNOUNCE_FILTERS();
  688. #endif
  689. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  690. rt_entry = g_ripcfg.lpRouteTable[pos];
  691. while (rt_entry != NULL) {
  692. // if we're supposed to only send changes
  693. // and this entry hasn't changed, skip it
  694. if (bChangesOnly &&
  695. (rt_entry->dwFlag & ROUTE_CHANGE) == 0) {
  696. rt_entry = rt_entry->next;
  697. continue;
  698. }
  699. // ignore network summary entries
  700. if ((rt_entry->dwFlag & ROUTE_ZOMBIE) != 0) {
  701. rt_entry = rt_entry->next;
  702. continue;
  703. }
  704. // copy the destination to be advertised
  705. dwEntryAddr = rt_entry->dwDestaddr;
  706. // if this is the route to the network for the outgoing interface
  707. // don't send it
  708. //
  709. if (dwEntryAddr == dwDestNetaddr) {
  710. rt_entry = rt_entry->next;
  711. continue;
  712. }
  713. // if host route announcements are disabled,
  714. // and this is a host route, don't add this entry
  715. if (dwHost == 0 &&
  716. (rt_entry->dwFlag & ROUTE_HOST) != 0) {
  717. rt_entry = rt_entry->next;
  718. continue;
  719. }
  720. // if default route announcements are disabled
  721. // and this is a default route, don't add this entry
  722. if (dwDefault == 0 &&
  723. dwEntryAddr == 0) {
  724. rt_entry = rt_entry->next;
  725. continue;
  726. }
  727. // if this update is being sent to a network different
  728. // from the network of the destination in the route entry,
  729. // or if the destination was truncated due to different
  730. // subnetmask lengths, summarize the route entry's destination,
  731. // also, if the entry is network route, we need
  732. // to remember it so we don't re-advertise it when
  733. // summarizing subnets
  734. dwEntryNetclassMask = NetclassMask(dwEntryAddr);
  735. dwEntryNetclassAddr = (dwEntryAddr & dwEntryNetclassMask);
  736. // special case exception is default route
  737. if (dwEntryAddr != 0 &&
  738. (dwDestNetclassAddr != dwEntryNetclassAddr ||
  739. dwEntryAddr == dwEntryNetclassAddr)) {
  740. // if the network for the entry has already been
  741. // advertised, don't advertise it again
  742. if (IsInAddressList(lpSummaries, dwEntryNetclassAddr)) {
  743. rt_entry = rt_entry->next;
  744. continue;
  745. }
  746. // add an entry for the network to the list
  747. // of networks used as summaries so far
  748. AddToAddressList(&lpSummaries, dwEntryNetclassAddr,
  749. dwEntryNetclassMask);
  750. // now we will advertise the NETWORK, not the original address
  751. dwEntryAddr = dwEntryNetclassAddr;
  752. }
  753. else
  754. if (dwEntryAddr != 0 &&
  755. (rt_entry->dwFlag & ROUTE_HOST) == 0 &&
  756. lpaddr->dwNetmask < rt_entry->dwNetmask) {
  757. // this is neither a host route nor a default route
  758. // and the subnet mask on the outgoing interface
  759. // is shorter than the one for the entry, so the entry
  760. // must be truncated so it is not considered a host route
  761. // by the routers who will receive this update
  762. // the comparison assumes netmasks are in network byte order
  763. dwEntryAddr &= lpaddr->dwNetmask;
  764. // skip the entry if the truncated destination
  765. // turns out to have been advertised already
  766. if (IsInAddressList(lpSummaries, dwEntryAddr)) {
  767. rt_entry = rt_entry->next;
  768. continue;
  769. }
  770. AddToAddressList(&lpSummaries, dwEntryAddr, lpaddr->dwNetmask);
  771. }
  772. // we only do poisoned-reverse/split-horizon on RIP routes
  773. //
  774. if (dwSplit == 0 ||
  775. rt_entry->dwProtocol != IRE_PROTO_RIP) {
  776. // always add the entry in this case;
  777. // we increment the metric for a static route
  778. // when sending it on interfaces other than
  779. // the interface to which the route is attached
  780. if (lpaddr->dwIndex == rt_entry->dwIndex) {
  781. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  782. lpdestaddr, dwEntryAddr,
  783. rt_entry->dwMetric);
  784. }
  785. else {
  786. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  787. lpdestaddr, dwEntryAddr,
  788. rt_entry->dwMetric + 1);
  789. }
  790. }
  791. else
  792. if (dwSplit != 0 && dwPoison == 0) {
  793. // don't advertise the route if this update is
  794. // being sent to the network from which we learnt
  795. // the route; we can tell by looking at the nexthop,
  796. // and comparing its subnet number to the subnet number
  797. // of the destination network
  798. dwNexthopNetaddr = (rt_entry->dwNexthop &
  799. SubnetMask(rt_entry->dwNexthop));
  800. if (dwNexthopNetaddr != dwDestNetaddr) {
  801. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  802. lpdestaddr, dwEntryAddr,
  803. rt_entry->dwMetric);
  804. }
  805. }
  806. else
  807. if (dwSplit != 0 && dwPoison != 0) {
  808. // if the update is being sent to the network from which
  809. // the route was learnt to begin with, poison any routing loops
  810. // by saying the metric is infinite
  811. dwNexthopNetaddr = (rt_entry->dwNexthop &
  812. SubnetMask(rt_entry->dwNexthop));
  813. if (dwNexthopNetaddr == dwDestNetaddr) {
  814. // this is the case which calls for poison reverse
  815. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  816. lpdestaddr, dwEntryAddr,
  817. METRIC_INFINITE);
  818. }
  819. else {
  820. AddUpdateEntry(buffer, &lpentry, &dwSize, lpaddr,
  821. lpdestaddr, dwEntryAddr,
  822. rt_entry->dwMetric);
  823. }
  824. }
  825. rt_entry = rt_entry->next;
  826. }
  827. }
  828. // remember the summarized networks in case some router
  829. // broadcasts them back at us
  830. for (lpnet = lpSummaries; lpnet != NULL; lpnet = lpnet->next) {
  831. AddZombieRouteTableEntry(lpaddr, lpnet->dwAddress, lpnet->dwNetmask);
  832. }
  833. #ifdef ROUTE_FILTERS
  834. RIP_UNLOCK_ANNOUNCE_FILTERS();
  835. #endif
  836. RIP_UNLOCK_ROUTETABLE();
  837. // done with the list of summarized networks
  838. FreeAddressList(lpSummaries);
  839. FinishUpdateBuffer(buffer, &dwSize, lpaddr, lpdestaddr);
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Function: BroadcastRouteTableContents
  843. //
  844. // This function handles both triggered updates and regular updates.
  845. // Depending on the value of bChangesOnly, it may exclude unchanged routes
  846. // from the update.
  847. // Assumes the address table is locked.
  848. //-----------------------------------------------------------------------------
  849. DWORD BroadcastRouteTableContents(BOOL bTriggered, BOOL bChangesOnly) {
  850. SOCKADDR_IN destaddr;
  851. LPRIP_ADDRESS lpaddr, lpend;
  852. destaddr.sin_family = AF_INET;
  853. destaddr.sin_port = htons(RIP_PORT);
  854. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  855. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  856. if (lpaddr->sock == INVALID_SOCKET) {
  857. continue;
  858. }
  859. destaddr.sin_addr.s_addr = (lpaddr->dwAddress | ~lpaddr->dwNetmask);
  860. TransmitRouteTableContents(lpaddr, &destaddr, bChangesOnly);
  861. if (bTriggered) {
  862. InterlockedIncrement(&lpaddr->lpstats->dwTriggeredUpdatesSent);
  863. }
  864. }
  865. return 0;
  866. }
  867. #ifndef CHICAGO
  868. #define POS_REGEVENT 0
  869. #define POS_TRIGEVENT 1
  870. #define POS_STOPEVENT 2
  871. #define POS_LASTEVENT 3
  872. #else
  873. #define POS_TRIGEVENT 0
  874. #define POS_STOPEVENT 1
  875. #define POS_LASTEVENT 2
  876. #endif
  877. #define DEF_TIMEOUT (10 * 1000)
  878. DWORD UpdateThread(LPVOID Param) {
  879. DWORD dwErr;
  880. HKEY hkeyParams;
  881. HANDLE hEvents[POS_LASTEVENT];
  882. LONG lMillisecsTillFullUpdate, lMillisecsTillRouteRefresh;
  883. DWORD dwWaitTimeout, dwGlobalTimeout;
  884. DWORD dwTickCount, dwTickCountBeforeWait, dwTickCountAfterWait;
  885. DWORD dwUpdateFrequency, dwSilentRIP, dwMillisecsSinceTimedOpsDone;
  886. #ifndef CHICAGO
  887. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_RIP_PARAMS, &hkeyParams);
  888. if (dwErr == ERROR_SUCCESS) {
  889. hEvents[POS_REGEVENT] = CreateEvent(NULL,FALSE,FALSE,NULL);
  890. if (hEvents[POS_REGEVENT] != NULL) {
  891. dwErr = RegNotifyChangeKeyValue(hkeyParams, FALSE,
  892. REG_NOTIFY_CHANGE_LAST_SET |
  893. REG_NOTIFY_CHANGE_ATTRIBUTES |
  894. REG_NOTIFY_CHANGE_NAME,
  895. hEvents[POS_REGEVENT], TRUE);
  896. }
  897. }
  898. #endif
  899. hEvents[POS_STOPEVENT] = g_stopEvent;
  900. hEvents[POS_TRIGEVENT] = g_triggerEvent;
  901. // get the update frequency, in seconds
  902. RIP_LOCK_PARAMS();
  903. dwSilentRIP = g_params.dwSilentRIP;
  904. dwUpdateFrequency = g_params.dwUpdateFrequency;
  905. dwGlobalTimeout = g_params.dwMaxTimedOpsInterval;
  906. RIP_UNLOCK_PARAMS();
  907. lMillisecsTillFullUpdate = (LONG)dwUpdateFrequency;
  908. lMillisecsTillRouteRefresh = DEF_GETROUTEFREQUENCY;
  909. dwMillisecsSinceTimedOpsDone = 0;
  910. while (1) {
  911. // set the time till the next full update
  912. InterlockedExchange(&g_ripcfg.dwMillisecsTillFullUpdate,
  913. (DWORD)lMillisecsTillFullUpdate);
  914. // set the time we need the next wait to last;
  915. // it has to be the minimum of the times till there is work to do;
  916. // uses a two-comparison sort to find the smallest of three items
  917. dwWaitTimeout = dwGlobalTimeout;
  918. if (dwWaitTimeout > (DWORD)lMillisecsTillFullUpdate) {
  919. dwWaitTimeout = lMillisecsTillFullUpdate;
  920. }
  921. if (dwWaitTimeout > (DWORD)lMillisecsTillRouteRefresh) {
  922. dwWaitTimeout = lMillisecsTillRouteRefresh;
  923. }
  924. // get the time before entering the wait
  925. dwTickCountBeforeWait = GetTickCount();
  926. // enter the wait
  927. //---------------
  928. dwErr = WaitForMultipleObjects(POS_LASTEVENT, hEvents, FALSE,
  929. dwWaitTimeout) ;
  930. dwTickCountAfterWait = GetTickCount();
  931. // we have to find out how long the wait lasted, taking care
  932. // in case the system timer wrapped around to zero
  933. if (dwTickCountAfterWait < dwTickCountBeforeWait) {
  934. dwTickCountAfterWait += (DWORD)~0 - dwTickCountBeforeWait;
  935. dwTickCountBeforeWait = 0;
  936. }
  937. dwTickCount = dwTickCountAfterWait - dwTickCountBeforeWait;
  938. dwMillisecsSinceTimedOpsDone += dwTickCount;
  939. // wait returned, now see why
  940. //---------------------------
  941. if (dwErr == WAIT_TIMEOUT) {
  942. // every minute we read local routes again -
  943. // this is to deal with somebody adding
  944. // static routes. note that deleted static routes
  945. // get deleted every 90 seconds.
  946. lMillisecsTillRouteRefresh -= dwWaitTimeout;
  947. if (lMillisecsTillRouteRefresh <= 0) {
  948. lMillisecsTillRouteRefresh = DEF_GETROUTEFREQUENCY;
  949. }
  950. // ProcessRouteTableChanges and BroadcastRouteTableContents
  951. // both assume the address table is locked; lock it before
  952. // doing timed operations, too, for good measure
  953. RIP_LOCK_ADDRTABLE();
  954. // update timers, passing the number of milliseconds
  955. // since we last called DoTimedOperations
  956. DoTimedOperations(dwMillisecsSinceTimedOpsDone);
  957. dwMillisecsSinceTimedOpsDone = 0;
  958. // if anything changed, process the changes
  959. // but tell the function not to send update packets
  960. if (g_ripcfg.dwRouteChanged != 0) {
  961. ProcessRouteTableChanges(FALSE);
  962. }
  963. // update the time till the next update,
  964. // and send the update if it is due
  965. lMillisecsTillFullUpdate -= dwWaitTimeout;
  966. if (lMillisecsTillFullUpdate <= 0) {
  967. lMillisecsTillFullUpdate = dwUpdateFrequency;
  968. // send out the periodic update
  969. if (dwSilentRIP == 0) {
  970. // this is not triggered, and we need to broadcast
  971. // the entire table, instead of just the changes
  972. BroadcastRouteTableContents(FALSE, FALSE);
  973. }
  974. }
  975. RIP_UNLOCK_ADDRTABLE();
  976. // this continue is here because there is some processing
  977. // done below for the cases where the wait is interrupted
  978. // before it could timeout; this skips that code
  979. //----------------------------------------------
  980. continue;
  981. }
  982. else
  983. #ifndef CHICAGO
  984. if (dwErr == WAIT_OBJECT_0 + POS_REGEVENT) {
  985. // registry was changed
  986. LoadParameters();
  987. // get the update frequency, converted to milliseconds
  988. RIP_LOCK_PARAMS();
  989. dwSilentRIP = g_params.dwSilentRIP;
  990. dwUpdateFrequency = g_params.dwUpdateFrequency;
  991. dwGlobalTimeout = g_params.dwMaxTimedOpsInterval;
  992. RIP_UNLOCK_PARAMS();
  993. RegNotifyChangeKeyValue(hkeyParams, FALSE,
  994. REG_NOTIFY_CHANGE_LAST_SET |
  995. REG_NOTIFY_CHANGE_ATTRIBUTES |
  996. REG_NOTIFY_CHANGE_NAME,
  997. hEvents[POS_REGEVENT], TRUE);
  998. }
  999. else
  1000. #endif
  1001. if (dwErr == WAIT_OBJECT_0 + POS_TRIGEVENT) {
  1002. RIP_LOCK_ADDRTABLE();
  1003. ProcessRouteTableChanges(TRUE);
  1004. RIP_UNLOCK_ADDRTABLE();
  1005. }
  1006. else
  1007. if (dwErr == WAIT_OBJECT_0 + POS_STOPEVENT) {
  1008. // perform graceful shutdown
  1009. //
  1010. // first, set all metrics to METRIC_INFINITE - 1
  1011. // next, send out four full updates at intervals
  1012. // of between 2 and 4 seconds
  1013. int pos;
  1014. LPHASH_TABLE_ENTRY rt_entry;
  1015. RIP_LOCK_ADDRTABLE();
  1016. RIP_LOCK_ROUTETABLE();
  1017. dbgprintf("sending out final updates.");
  1018. // setting metrics to 15
  1019. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  1020. rt_entry = g_ripcfg.lpRouteTable[pos];
  1021. while (rt_entry != NULL) {
  1022. if (rt_entry->dwMetric != METRIC_INFINITE) {
  1023. rt_entry->dwMetric = METRIC_INFINITE - 1;
  1024. }
  1025. rt_entry = rt_entry->next;
  1026. }
  1027. }
  1028. // sending out final full updates
  1029. if (dwSilentRIP == 0) {
  1030. srand((unsigned)time(NULL));
  1031. for (pos = 0; pos < 4; pos++) {
  1032. BroadcastRouteTableContents(FALSE, FALSE);
  1033. Sleep(2000 + (int)((double)rand() / RAND_MAX * 2000.0));
  1034. }
  1035. }
  1036. RIP_UNLOCK_ROUTETABLE();
  1037. RIP_UNLOCK_ADDRTABLE();
  1038. // break out of the infinite loop
  1039. #ifndef CHICAGO
  1040. CloseHandle(hEvents[POS_REGEVENT]);
  1041. #endif
  1042. break;
  1043. }
  1044. // these are only executed if the wait ended
  1045. // for some reason other than a timeout;
  1046. //--------------------------------------
  1047. lMillisecsTillFullUpdate -= min(lMillisecsTillFullUpdate,
  1048. (LONG)dwTickCount);
  1049. lMillisecsTillRouteRefresh -= min(lMillisecsTillRouteRefresh,
  1050. (LONG)dwTickCount);
  1051. //
  1052. // Make sure DoTimedOperations() runs at least every
  1053. // MaxTimedOpsInterval seconds.
  1054. // We grab the address table lock for good measure.
  1055. //
  1056. if (dwMillisecsSinceTimedOpsDone >= g_params.dwMaxTimedOpsInterval) {
  1057. RIP_LOCK_ADDRTABLE();
  1058. DoTimedOperations(dwMillisecsSinceTimedOpsDone);
  1059. dwMillisecsSinceTimedOpsDone = 0;
  1060. // if anything changed, process the changes
  1061. // but tell the function not to send update packets
  1062. if (g_ripcfg.dwRouteChanged != 0) {
  1063. ProcessRouteTableChanges(FALSE);
  1064. }
  1065. RIP_UNLOCK_ADDRTABLE();
  1066. }
  1067. }
  1068. dbgprintf("update thread stopping.");
  1069. SetEvent(g_updateDoneEvent);
  1070. #ifndef CHICAGO
  1071. FreeLibraryAndExitThread(g_hmodule, 0);
  1072. #endif
  1073. return(0);
  1074. }
  1075. //-----------------------------------------------------------------------------
  1076. // Function: CleanupRouteTable
  1077. //
  1078. // Called at shutdown time - runs through all the routes in the route table
  1079. // deleting from the system the routes that were learnt through RIP.
  1080. //-----------------------------------------------------------------------------
  1081. VOID CleanupRouteTable() {
  1082. INT pos;
  1083. LPHASH_TABLE_ENTRY rt_entry, prev_rt_entry;
  1084. RIP_LOCK_ROUTETABLE();
  1085. // Walk the whole hash table - deleting all RIP added routes
  1086. // from each bucket
  1087. dbgprintf("deleting RIP routes from system table.");
  1088. for (pos = 0; pos < HASH_TABLE_SIZE; pos++) {
  1089. prev_rt_entry = rt_entry = g_ripcfg.lpRouteTable[pos];
  1090. while (rt_entry != NULL) {
  1091. prev_rt_entry = rt_entry;
  1092. rt_entry = rt_entry->next;
  1093. if (prev_rt_entry->dwProtocol == IRE_PROTO_RIP) {
  1094. // remove the route from IP's routing table
  1095. UpdateSystemRouteTable(prev_rt_entry, FALSE);
  1096. }
  1097. free(prev_rt_entry);
  1098. }
  1099. g_ripcfg.lpRouteTable[pos] = NULL;
  1100. }
  1101. RIP_UNLOCK_ROUTETABLE();
  1102. // if a route dump was made to shared memory, close the handle
  1103. RIP_LOCK_ADDRTABLE();
  1104. RIP_UNLOCK_ADDRTABLE();
  1105. }