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.

7472 lines
193 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: work.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin Aug-8-1995 Created.
  8. //
  9. // worker function implementations
  10. //============================================================================
  11. #include "pchrip.h"
  12. #pragma hdrstop
  13. VOID
  14. ProcessSocket(
  15. DWORD dwAddrIndex,
  16. PIF_TABLE_ENTRY pite,
  17. PIF_TABLE pTable
  18. );
  19. VOID
  20. EnqueueStartFullUpdate(
  21. PIF_TABLE_ENTRY pite,
  22. LARGE_INTEGER qwLastFullUpdateTime
  23. );
  24. DWORD
  25. EnqueueDemandUpdateCheck(
  26. PUPDATE_CONTEXT pwc
  27. );
  28. VOID
  29. EnqueueDemandUpdateMessage(
  30. DWORD dwInterfaceIndex,
  31. DWORD dwError
  32. );
  33. DWORD
  34. CountInterfaceRoutes(
  35. DWORD dwInterfaceIndex
  36. );
  37. BOOL
  38. ProcessResponseEntry(
  39. PIF_TABLE_ENTRY pITE,
  40. DWORD dwAddrIndex,
  41. DWORD dwSource,
  42. PIPRIP_ENTRY pIE,
  43. PIPRIP_PEER_STATS pPS
  44. );
  45. DWORD
  46. SendRouteOnIfList(
  47. UPDATE_BUFFER pBufList[],
  48. DWORD dwBufCount,
  49. DWORD dwSendMode,
  50. PROUTE_TABLE pSummaryTable,
  51. PRIP_IP_ROUTE pRoute
  52. );
  53. //----------------------------------------------------------------------------
  54. // Macro: RTM_ROUTE_FROM_IPRIP_ENTRY
  55. // Macro: IPRIP_ENTRY_FROM_RTM_ROUTE
  56. //
  57. // These two macros are used to transfer data from an RTM route struct
  58. // to an IPRIPv2 packet route entry, and vice versa.
  59. // The first two bytes of an RTM route's ProtocolSpecificData array are used
  60. // to store the route tag contained in the IPRIP packet route-entry
  61. //----------------------------------------------------------------------------
  62. #define RTM_ROUTE_FROM_IPRIP_ENTRY(r,i) \
  63. (r)->RR_RoutingProtocol = PROTO_IP_RIP; \
  64. SETROUTEMETRIC((r), ntohl((i)->IE_Metric)); \
  65. (r)->RR_Network.N_NetNumber = (i)->IE_Destination; \
  66. (r)->RR_Network.N_NetMask = (i)->IE_SubnetMask; \
  67. (r)->RR_NextHopAddress.N_NetNumber = (i)->IE_Nexthop; \
  68. (r)->RR_NextHopAddress.N_NetMask = (i)->IE_SubnetMask; \
  69. SETROUTETAG((r), ntohs((i)->IE_RouteTag))
  70. #define IPRIP_ENTRY_FROM_RTM_ROUTE(i,r) \
  71. (i)->IE_AddrFamily = htons(AF_INET); \
  72. (i)->IE_Metric = htonl(GETROUTEMETRIC(r)); \
  73. (i)->IE_Destination = (r)->RR_Network.N_NetNumber; \
  74. (i)->IE_SubnetMask = (r)->RR_Network.N_NetMask; \
  75. (i)->IE_Nexthop = (r)->RR_NextHopAddress.N_NetNumber
  76. //----------------------------------------------------------------------------
  77. // Macro: IS_ROUTE_IN_ACCEPT_FILTER
  78. // Macro: IS_ROUTE_IN_ANNOUNCE_FILTER
  79. //
  80. // The following three macros are used to search for a route
  81. // in the accept filters and announce filters configured for an interface
  82. // The last two macros invoke the first macro which executes the inner loop,
  83. // since the inner loop is identical in both cases.
  84. //----------------------------------------------------------------------------
  85. #define IS_ROUTE_IN_FILTER(route,ret) \
  86. (ret) = 0; \
  87. for ( ; _pfilt < _pfiltend; _pfilt++) { \
  88. _filt = _pfilt->RF_LoAddress; \
  89. if (INET_CMP(route, _filt, _cmp) == 0) { (ret) = 1; break; } \
  90. else if (_cmp > 0) { \
  91. _filt = _pfilt->RF_HiAddress; \
  92. if (INET_CMP(route, _filt, _cmp) <= 0) { (ret) = 1; break; }\
  93. } \
  94. }
  95. #define IS_ROUTE_IN_ACCEPT_FILTER(ic,route,ret) { \
  96. INT _cmp; \
  97. DWORD _filt; \
  98. PIPRIP_ROUTE_FILTER _pfilt, _pfiltend; \
  99. _pfilt = IPRIP_IF_ACCEPT_FILTER_TABLE(ic); \
  100. _pfiltend = _pfilt + (ic)->IC_AcceptFilterCount; \
  101. IS_ROUTE_IN_FILTER(route,ret); \
  102. }
  103. #define IS_ROUTE_IN_ANNOUNCE_FILTER(ic,route,ret) { \
  104. INT _cmp; \
  105. DWORD _filt; \
  106. PIPRIP_ROUTE_FILTER _pfilt, _pfiltend; \
  107. _pfilt = IPRIP_IF_ANNOUNCE_FILTER_TABLE(ic); \
  108. _pfiltend = _pfilt + (ic)->IC_AnnounceFilterCount; \
  109. IS_ROUTE_IN_FILTER(route,ret); \
  110. }
  111. //----------------------------------------------------------------------------
  112. // Macro: IS_PEER_IN_FILTER
  113. //
  114. // macro used to search the peer filters
  115. //----------------------------------------------------------------------------
  116. #define IS_PEER_IN_FILTER(gc,peer,ret) { \
  117. PDWORD _pdwPeer, _pdwPeerEnd; \
  118. (ret) = 0; \
  119. _pdwPeer = IPRIP_GLOBAL_PEER_FILTER_TABLE(gc); \
  120. _pdwPeerEnd = _pdwPeer + (gc)->GC_PeerFilterCount; \
  121. for ( ; _pdwPeer < _pdwPeerEnd; _pdwPeer++) { \
  122. if (*_pdwPeer == (peer)) { (ret) = 1; break; } \
  123. } \
  124. }
  125. //----------------------------------------------------------------------------
  126. // UPDATE BUFFER MANAGEMENT
  127. //
  128. // The following types and functions are used to simplify
  129. // the transmission of routes. The system consists of the struct
  130. // UPDATE_BUFFER, which includes a function table and a byte buffer,
  131. // and a number of three-function update buffer routine sets.
  132. // The sets each contain a routine to start an update buffer,
  133. // to add a route to an update buffer, and to finish an update buffer.
  134. //
  135. // There are separate versions for RIPv1 mode and RIPv2 mode. The function
  136. // InitializeUpdateBuffer sets up the function table in an update buffer
  137. // depending on the configuration for the interface with which the buffer
  138. // is associated. This set-up eliminates the need to check the interface
  139. // configuration every time an entry must be added; instead, the config
  140. // is checked a single time to set up the function table, and afterward
  141. // the function generating the update merely calls the functions in the table.
  142. //
  143. // The setup also depends on the mode in which the information is being sent.
  144. // The address to which the information is being sent is stored in the
  145. // update buffer, since this will be required every time a route is added.
  146. // However, when a full-update is being generated on an interface operating
  147. // in RIPv2 mode, the destination address stored is 224.0.0.9, but the
  148. // actual destination network is the network of the out-going interface.
  149. // Therefore, this address is also stored since it will be needed for
  150. // split-horizon/poison-reverse/subnet-summary processing
  151. //----------------------------------------------------------------------------
  152. //
  153. // these are the modes in which routes may be transmitted
  154. //
  155. #define SENDMODE_FULL_UPDATE 0
  156. #define SENDMODE_TRIGGERED_UPDATE 1
  157. #define SENDMODE_SHUTDOWN_UPDATE 2
  158. #define SENDMODE_GENERAL_REQUEST 3
  159. #define SENDMODE_GENERAL_RESPONSE1 4
  160. #define SENDMODE_GENERAL_RESPONSE2 5
  161. #define SENDMODE_SPECIFIC_RESPONSE1 6
  162. #define SENDMODE_SPECIFIC_RESPONSE2 7
  163. //
  164. // this function set is for interfaces with announcements disabled
  165. //
  166. DWORD
  167. StartBufferNull(
  168. PUPDATE_BUFFER pUB
  169. ) { return NO_ERROR; }
  170. DWORD
  171. AddEntryNull(
  172. PUPDATE_BUFFER pUB,
  173. PRIP_IP_ROUTE pRIR
  174. ) { return NO_ERROR; }
  175. DWORD
  176. FinishBufferNull(
  177. PUPDATE_BUFFER pUB
  178. ) { return NO_ERROR; }
  179. //
  180. // this function-set is for RIPv1 interfaces
  181. //
  182. DWORD
  183. StartBufferVersion1(
  184. PUPDATE_BUFFER pUB
  185. );
  186. DWORD
  187. AddEntryVersion1(
  188. PUPDATE_BUFFER pUB,
  189. PRIP_IP_ROUTE pRIR
  190. );
  191. DWORD
  192. FinishBufferVersion1(
  193. PUPDATE_BUFFER pUB
  194. );
  195. //
  196. // this function-set is for RIPv2 interfaces
  197. //
  198. DWORD
  199. StartBufferVersion2(
  200. PUPDATE_BUFFER pUB
  201. );
  202. DWORD
  203. AddEntryVersion2(
  204. PUPDATE_BUFFER pUB,
  205. PRIP_IP_ROUTE pRIR
  206. );
  207. DWORD
  208. FinishBufferVersion2(
  209. PUPDATE_BUFFER pUB
  210. );
  211. //----------------------------------------------------------------------------
  212. // Function: InitializeUpdateBuffer
  213. //
  214. // this function sets up the update-buffer, writing in the functions to use
  215. // for restarting the buffer, adding entries, and finishing the buffer.
  216. // It also stores the destination address to which the packet is being sent,
  217. // as well as the network and netmask for the destination
  218. // This assumes the binding table is locked.
  219. //----------------------------------------------------------------------------
  220. DWORD
  221. InitializeUpdateBuffer(
  222. PIF_TABLE_ENTRY pITE,
  223. DWORD dwAddrIndex,
  224. PUPDATE_BUFFER pUB,
  225. DWORD dwSendMode,
  226. DWORD dwDestination,
  227. DWORD dwCommand
  228. ) {
  229. DWORD dwAnnounceMode;
  230. PIPRIP_IP_ADDRESS paddr;
  231. pUB->UB_Length = 0;
  232. //
  233. // save the pointer to the interface
  234. //
  235. pUB->UB_ITE = pITE;
  236. pUB->UB_AddrIndex = dwAddrIndex;
  237. paddr = IPRIP_IF_ADDRESS_TABLE(pITE->ITE_Binding) + dwAddrIndex;
  238. pUB->UB_Socket = pITE->ITE_Sockets[dwAddrIndex];
  239. pUB->UB_Address = paddr->IA_Address;
  240. pUB->UB_Netmask = paddr->IA_Netmask;
  241. //
  242. // save the command
  243. //
  244. pUB->UB_Command = dwCommand;
  245. //
  246. // store the absolute address to which this packet is destined,
  247. // which may differ from the address passed to sendto()
  248. // e.g. RIPv2 packets are destined for the interface's network,
  249. // but the address passed to sendto() is 224.0.0.9
  250. // if the destination passed in is 0, use the broadcast address
  251. // on the outgoing interface as the destination
  252. //
  253. if (dwDestination == 0) {
  254. if(paddr->IA_Netmask == 0xffffffff)
  255. {
  256. TRACE0(SEND,"MASK ALL ONES");
  257. pUB->UB_DestAddress = (paddr->IA_Address | ~(NETCLASS_MASK(paddr->IA_Address)));
  258. }
  259. else
  260. {
  261. pUB->UB_DestAddress = (paddr->IA_Address | ~paddr->IA_Netmask);
  262. }
  263. pUB->UB_DestNetmask = paddr->IA_Netmask;
  264. }
  265. else {
  266. pUB->UB_DestAddress = dwDestination;
  267. pUB->UB_DestNetmask = GuessSubnetMask(pUB->UB_DestAddress, NULL);
  268. }
  269. //
  270. // decide on the announce mode;
  271. // if the mode is DISABLED, we still send responses to SPECIFIC requests
  272. // on the interface, so set the mode to RIPv1/v2 if sending a specific
  273. // response on a disabled interface
  274. //
  275. dwAnnounceMode = pITE->ITE_Config->IC_AnnounceMode;
  276. if (dwAnnounceMode == IPRIP_ANNOUNCE_DISABLED) {
  277. if (dwSendMode == SENDMODE_SPECIFIC_RESPONSE1) {
  278. dwAnnounceMode = IPRIP_ANNOUNCE_RIP1;
  279. }
  280. else
  281. if (dwSendMode == SENDMODE_SPECIFIC_RESPONSE2) {
  282. dwAnnounceMode = IPRIP_ANNOUNCE_RIP2;
  283. }
  284. }
  285. //
  286. // set up the function table and destination address, which
  287. // depend on the announce-mode of the interface and on the sort
  288. // of information being transmitted
  289. //
  290. switch (dwAnnounceMode) {
  291. //
  292. // in RIP1 mode, packets are RIP1, broadcast
  293. //
  294. case IPRIP_ANNOUNCE_RIP1:
  295. pUB->UB_AddRoutine = AddEntryVersion1;
  296. pUB->UB_StartRoutine = StartBufferVersion1;
  297. pUB->UB_FinishRoutine = FinishBufferVersion1;
  298. pUB->UB_Destination.sin_port = htons(IPRIP_PORT);
  299. pUB->UB_Destination.sin_family = AF_INET;
  300. pUB->UB_Destination.sin_addr.s_addr = pUB->UB_DestAddress;
  301. break;
  302. //
  303. // in RIP1-compatible mode, packets are RIP2, broadcast,
  304. // except in the case of a general response to a RIP1 router,
  305. // in which case the packets are RIP1, unicast
  306. //
  307. case IPRIP_ANNOUNCE_RIP1_COMPAT:
  308. if (dwSendMode == SENDMODE_GENERAL_RESPONSE1) {
  309. pUB->UB_AddRoutine = AddEntryVersion1;
  310. pUB->UB_StartRoutine = StartBufferVersion1;
  311. pUB->UB_FinishRoutine = FinishBufferVersion1;
  312. }
  313. else {
  314. pUB->UB_AddRoutine = AddEntryVersion2;
  315. pUB->UB_StartRoutine = StartBufferVersion2;
  316. pUB->UB_FinishRoutine = FinishBufferVersion2;
  317. }
  318. pUB->UB_Destination.sin_port = htons(IPRIP_PORT);
  319. pUB->UB_Destination.sin_family = AF_INET;
  320. pUB->UB_Destination.sin_addr.s_addr = pUB->UB_DestAddress;
  321. break;
  322. //
  323. // in RIP2 mode, packets are RIP2, multicast, except in the case
  324. // of a general/specific responses, in which cases messages are unicast;
  325. // note that a RIP2-only router never sends a general response to
  326. // a request from a RIP1 router.
  327. //
  328. case IPRIP_ANNOUNCE_RIP2:
  329. pUB->UB_AddRoutine = AddEntryVersion2;
  330. pUB->UB_StartRoutine = StartBufferVersion2;
  331. pUB->UB_FinishRoutine = FinishBufferVersion2;
  332. pUB->UB_Destination.sin_port = htons(IPRIP_PORT);
  333. pUB->UB_Destination.sin_family = AF_INET;
  334. //
  335. // if sending to a specific destination, as a reponse
  336. // to a request or as a full update to a unicast peer,
  337. // set the IP address of the destination.
  338. // Else send to multicast address.
  339. //
  340. if ( dwDestination != 0 ) {
  341. pUB->UB_Destination.sin_addr.s_addr = pUB->UB_DestAddress;
  342. }
  343. else {
  344. pUB->UB_Destination.sin_addr.s_addr = IPRIP_MULTIADDR;
  345. }
  346. break;
  347. default:
  348. TRACE2(
  349. IF, "invalid announce mode on interface %d (%s)",
  350. pITE->ITE_Index, INET_NTOA(paddr->IA_Address)
  351. );
  352. pUB->UB_AddRoutine = AddEntryNull;
  353. pUB->UB_StartRoutine = StartBufferNull;
  354. pUB->UB_FinishRoutine = FinishBufferNull;
  355. return ERROR_INVALID_PARAMETER;
  356. }
  357. return NO_ERROR;
  358. }
  359. //----------------------------------------------------------------------------
  360. // Function: SendUpdateBuffer
  361. //
  362. // This function is invoked by the add-entry and finsih-buffer functions
  363. // to send the contents of an update-buffer.
  364. //----------------------------------------------------------------------------
  365. DWORD
  366. SendUpdateBuffer(
  367. PUPDATE_BUFFER pbuf
  368. ) {
  369. INT iLength;
  370. DWORD dwErr;
  371. TRACE1(SEND,"SENDING TO %s",INET_NTOA(pbuf->UB_Destination.sin_addr.s_addr));
  372. iLength = sendto(
  373. pbuf->UB_Socket, pbuf->UB_Buffer, pbuf->UB_Length, 0,
  374. (PSOCKADDR)&pbuf->UB_Destination, sizeof(SOCKADDR_IN)
  375. );
  376. if (iLength == SOCKET_ERROR || (DWORD)iLength < pbuf->UB_Length) {
  377. //
  378. // an error occurred
  379. //
  380. CHAR szDest[20], *lpszAddr;
  381. dwErr = WSAGetLastError();
  382. lstrcpy(szDest, INET_NTOA(pbuf->UB_Destination.sin_addr));
  383. lpszAddr = INET_NTOA(pbuf->UB_Address);
  384. TRACE4(
  385. SEND, "error %d sending update to %s on interface %d (%s)",
  386. dwErr, szDest, pbuf->UB_ITE->ITE_Index, lpszAddr
  387. );
  388. LOGWARN2(SENDTO_FAILED, lpszAddr, szDest, dwErr);
  389. InterlockedIncrement(&pbuf->UB_ITE->ITE_Stats.IS_SendFailures);
  390. }
  391. else {
  392. if (pbuf->UB_Command == IPRIP_REQUEST) {
  393. InterlockedIncrement(&pbuf->UB_ITE->ITE_Stats.IS_RequestsSent);
  394. }
  395. else {
  396. InterlockedIncrement(&pbuf->UB_ITE->ITE_Stats.IS_ResponsesSent);
  397. }
  398. dwErr = NO_ERROR;
  399. }
  400. return dwErr;
  401. }
  402. //----------------------------------------------------------------------------
  403. // Function: StartBufferVersion1
  404. //
  405. // This starts a RIPv1 update-buffer, zeroing reserved fields,
  406. // setting the version, and setting the command field
  407. //----------------------------------------------------------------------------
  408. DWORD
  409. StartBufferVersion1(
  410. PUPDATE_BUFFER pUB
  411. ) {
  412. PIPRIP_HEADER pHdr;
  413. //
  414. // set up the header
  415. //
  416. pHdr = (PIPRIP_HEADER)pUB->UB_Buffer;
  417. pHdr->IH_Version = 1;
  418. pHdr->IH_Command = (BYTE)pUB->UB_Command;
  419. pHdr->IH_Reserved = 0;
  420. pUB->UB_Length = sizeof(IPRIP_HEADER);
  421. return NO_ERROR;
  422. }
  423. //----------------------------------------------------------------------------
  424. // Function: AddEntryVersion1
  425. //
  426. // This adds an entry to a RIPv1 buffer, first sending the buffer if it is full
  427. //----------------------------------------------------------------------------
  428. DWORD
  429. AddEntryVersion1(
  430. PUPDATE_BUFFER pUB,
  431. PRIP_IP_ROUTE pRIR
  432. ) {
  433. PIPRIP_ENTRY pie;
  434. //
  435. // if the buffer is full, transmit its contents and restart it
  436. //
  437. if ((pUB->UB_Length + sizeof(IPRIP_ENTRY)) > MAX_PACKET_SIZE) {
  438. SendUpdateBuffer(pUB);
  439. StartBufferVersion1(pUB);
  440. }
  441. //
  442. // point to the end of the buffer
  443. //
  444. pie = (PIPRIP_ENTRY)(pUB->UB_Buffer + pUB->UB_Length);
  445. IPRIP_ENTRY_FROM_RTM_ROUTE(pie, pRIR);
  446. //
  447. // zero out fields which are reserved in RIP1
  448. //
  449. pie->IE_SubnetMask = 0;
  450. pie->IE_RouteTag = 0;
  451. pie->IE_Nexthop = 0;
  452. pUB->UB_Length += sizeof(IPRIP_ENTRY);
  453. return NO_ERROR;
  454. }
  455. //----------------------------------------------------------------------------
  456. // Function: FinishBufferVersion1
  457. //
  458. // this sends the contents of a RIPv1 buffer, if any
  459. //----------------------------------------------------------------------------
  460. DWORD
  461. FinishBufferVersion1(
  462. PUPDATE_BUFFER pUB
  463. ) {
  464. //
  465. // send the buffer if it contains any entries
  466. //
  467. if (pUB->UB_Length > sizeof(IPRIP_HEADER)) {
  468. SendUpdateBuffer(pUB);
  469. }
  470. return NO_ERROR;
  471. }
  472. //----------------------------------------------------------------------------
  473. // Function: StartBufferVersion2
  474. //
  475. // this starts a RIPv2 buffer
  476. //----------------------------------------------------------------------------
  477. DWORD
  478. StartBufferVersion2(
  479. PUPDATE_BUFFER pUB
  480. ) {
  481. PIPRIP_HEADER pHdr;
  482. PIPRIP_IF_CONFIG pic;
  483. PIPRIP_AUTHENT_ENTRY pae;
  484. //
  485. // setup header
  486. //
  487. pHdr = (PIPRIP_HEADER)pUB->UB_Buffer;
  488. pHdr->IH_Version = 2;
  489. pHdr->IH_Command = (BYTE)pUB->UB_Command;
  490. pHdr->IH_Reserved = 0;
  491. pUB->UB_Length = sizeof(IPRIP_HEADER);
  492. //
  493. // see if we need to set up the authentication entry
  494. //
  495. pic = pUB->UB_ITE->ITE_Config;
  496. if (pic->IC_AuthenticationType == IPRIP_AUTHTYPE_SIMPLE_PASSWORD) {
  497. pae = (PIPRIP_AUTHENT_ENTRY)(pUB->UB_Buffer + sizeof(IPRIP_HEADER));
  498. pae->IAE_AddrFamily = htons(ADDRFAMILY_AUTHENT);
  499. pae->IAE_AuthType = htons((WORD)pic->IC_AuthenticationType);
  500. CopyMemory(
  501. pae->IAE_AuthKey,
  502. pic->IC_AuthenticationKey,
  503. IPRIP_MAX_AUTHKEY_SIZE
  504. );
  505. pUB->UB_Length += sizeof(IPRIP_AUTHENT_ENTRY);
  506. }
  507. return NO_ERROR;
  508. }
  509. //----------------------------------------------------------------------------
  510. // Function: AddEntryVersion2
  511. //
  512. // this adds an entry to RIPv2 buffer, first sending the buffer if it is full
  513. //----------------------------------------------------------------------------
  514. DWORD
  515. AddEntryVersion2(
  516. PUPDATE_BUFFER pUB,
  517. PRIP_IP_ROUTE pRIR
  518. ) {
  519. PIPRIP_ENTRY pie;
  520. //
  521. // send the contents if the buffer is full
  522. //
  523. if (pUB->UB_Length + sizeof(IPRIP_ENTRY) > MAX_PACKET_SIZE) {
  524. SendUpdateBuffer(pUB);
  525. StartBufferVersion2(pUB);
  526. }
  527. pie = (PIPRIP_ENTRY)(pUB->UB_Buffer + pUB->UB_Length);
  528. IPRIP_ENTRY_FROM_RTM_ROUTE(pie, pRIR);
  529. //
  530. // for RIP routes, we assume that the route tag will be set
  531. // in the RTM route struct already;
  532. // for non-RIP routes, we write the route tag
  533. // for the outgoing interface in the packet entry
  534. //
  535. if (pRIR->RR_RoutingProtocol == PROTO_IP_RIP) {
  536. pie->IE_RouteTag = htons(GETROUTETAG(pRIR));
  537. }
  538. else {
  539. pie->IE_RouteTag = htons(pUB->UB_ITE->ITE_Config->IC_RouteTag);
  540. }
  541. pUB->UB_Length += sizeof(IPRIP_ENTRY);
  542. return NO_ERROR;
  543. }
  544. //----------------------------------------------------------------------------
  545. // Function: FinishBufferVersion2
  546. //
  547. // this sends the contents of a RIPv2 buffer, if any
  548. //----------------------------------------------------------------------------
  549. DWORD
  550. FinishBufferVersion2(
  551. PUPDATE_BUFFER pUB
  552. ) {
  553. //
  554. // the size above which we send depends on whether or not there
  555. // is an authentication entry
  556. //
  557. if (pUB->UB_ITE->ITE_Config->IC_AuthenticationType == IPRIP_AUTHTYPE_NONE) {
  558. if (pUB->UB_Length > sizeof(IPRIP_HEADER)) {
  559. SendUpdateBuffer(pUB);
  560. }
  561. }
  562. else {
  563. //
  564. // there is an authentication entry, so unless there
  565. // is also a route entry, we will not send this last buffer
  566. //
  567. if (pUB->UB_Length > (sizeof(IPRIP_HEADER) +
  568. sizeof(IPRIP_AUTHENT_ENTRY))) {
  569. SendUpdateBuffer(pUB);
  570. }
  571. }
  572. return NO_ERROR;
  573. }
  574. //----------------------------------------------------------------------------
  575. // ROUTE ENUMERATION ROUTINES
  576. //
  577. // The following definitions simplify the enumeration of routes
  578. // when routing information is being sent from a single source on multiple
  579. // interfaces, for instance when a triggered update is going out on all
  580. // interfaces, or when a full-update is being sent, or when a number
  581. // of interfaces are being shutdown. the function InitializeGetRoute looks at
  582. // the mode in which it is supposed to send routes, and based on that
  583. // builds a table of functions which will be used to enumerate the routes.
  584. // In the case of a full-update, the enumeration functions would
  585. // go to RTM to get the information; in the case of a triggered-update, they
  586. // would dequeue routes from the send-queue.
  587. //----------------------------------------------------------------------------
  588. // the following are the type definitions of the functions
  589. // in each get-route function group
  590. typedef DWORD (*PGETROUTE_START)(PVOID *);
  591. typedef DWORD (*PGETROUTE_NEXT)(PVOID *, PRIP_IP_ROUTE);
  592. typedef DWORD (*PGETROUTE_FINISH)(PVOID *);
  593. // The following three functions handle RTM route enumeration
  594. DWORD
  595. RtmGetRouteStart(
  596. PRTM_ENUM_HANDLE phEnumHandle
  597. );
  598. DWORD
  599. RtmGetRouteNext(
  600. RTM_ENUM_HANDLE hEnumHandle,
  601. PRIP_IP_ROUTE pRoute
  602. );
  603. DWORD
  604. RtmGetRouteFinish(
  605. RTM_ENUM_HANDLE hEnumHandle
  606. );
  607. // The following three functions handle full-update route enumeration
  608. // (a full-update enumerates routes from RTM)
  609. #define FullUpdateGetRouteStart RtmGetRouteStart
  610. #define FullUpdateGetRouteNext RtmGetRouteNext
  611. #define FullUpdateGetRouteFinish RtmGetRouteFinish
  612. // The following three functions handle triggered-update route enumeration
  613. // (a triggered-update enumerates routes from the send-queue)
  614. DWORD
  615. TriggeredUpdateGetRouteStart(
  616. PRTM_ENUM_HANDLE phEnumHandle
  617. );
  618. DWORD
  619. TriggeredUpdateGetRouteNext(
  620. RTM_ENUM_HANDLE hEnumHandle,
  621. PRIP_IP_ROUTE pRoute
  622. );
  623. DWORD
  624. TriggeredUpdateGetRouteFinish(
  625. RTM_ENUM_HANDLE hEnumHandle
  626. );
  627. // The following three functions handle shutdown-update route enumeration.
  628. // On shutdown, routes are enumerated from RTM, but their metrics
  629. // are set to IPRIP_INFINITE-1 before being returned
  630. #define ShutdownUpdateGetRouteStart RtmGetRouteStart
  631. DWORD ShutdownUpdateGetRouteNext(RTM_ENUM_HANDLE hEnumHandle, PRIP_IP_ROUTE pRoute);
  632. #define ShutdownUpdateGetRouteFinish RtmGetRouteFinish
  633. // The following three functions handle general-response route enumeration
  634. // a general response enumerates routes from RTM
  635. #define GeneralResponseGetRouteStart RtmGetRouteStart
  636. #define GeneralResponseGetRouteNext RtmGetRouteNext
  637. #define GeneralResponseGetRouteFinish RtmGetRouteFinish
  638. //----------------------------------------------------------------------------
  639. // Function: InitializeGetRoute
  640. //
  641. // This functions sets up a get-route function group given the send-mode
  642. //----------------------------------------------------------------------------
  643. DWORD
  644. InitializeGetRoute(
  645. DWORD dwSendMode,
  646. PGETROUTE_START *ppGS,
  647. PGETROUTE_NEXT *ppGN,
  648. PGETROUTE_FINISH *ppGF
  649. ) {
  650. switch (dwSendMode) {
  651. case SENDMODE_FULL_UPDATE:
  652. *ppGS = FullUpdateGetRouteStart;
  653. *ppGN = FullUpdateGetRouteNext;
  654. *ppGF = FullUpdateGetRouteFinish;
  655. break;
  656. case SENDMODE_TRIGGERED_UPDATE:
  657. *ppGS = TriggeredUpdateGetRouteStart;
  658. *ppGN = TriggeredUpdateGetRouteNext;
  659. *ppGF = TriggeredUpdateGetRouteFinish;
  660. break;
  661. case SENDMODE_SHUTDOWN_UPDATE:
  662. *ppGS = ShutdownUpdateGetRouteStart;
  663. *ppGN = ShutdownUpdateGetRouteNext;
  664. *ppGF = ShutdownUpdateGetRouteFinish;
  665. break;
  666. case SENDMODE_GENERAL_RESPONSE1:
  667. case SENDMODE_GENERAL_RESPONSE2:
  668. *ppGS = GeneralResponseGetRouteStart;
  669. *ppGN = GeneralResponseGetRouteNext;
  670. *ppGF = GeneralResponseGetRouteFinish;
  671. break;
  672. default:
  673. return ERROR_INVALID_PARAMETER;
  674. break;
  675. }
  676. return NO_ERROR;
  677. }
  678. //----------------------------------------------------------------------------
  679. // Function: RtmGetRouteStart
  680. //
  681. // starts an enumeration of RTM routes; includes only and all best routes
  682. // the enumeration handle is written into ppEnumerator
  683. //----------------------------------------------------------------------------
  684. DWORD
  685. RtmGetRouteStart(
  686. PRTM_ENUM_HANDLE phEnumHandle
  687. ) {
  688. DWORD dwErr;
  689. RTM_NET_ADDRESS rna;
  690. RTM_IPV4_MAKE_NET_ADDRESS( &rna, 0 , 0 );
  691. dwErr = RtmCreateDestEnum(
  692. ig.IG_RtmHandle, RTM_VIEW_MASK_ANY,
  693. RTM_ENUM_START | RTM_ENUM_ALL_DESTS, &rna,
  694. RTM_BEST_PROTOCOL, phEnumHandle
  695. );
  696. if (dwErr != NO_ERROR) {
  697. TRACE1( ROUTE, "error %d when creating enumeration handle", dwErr );
  698. }
  699. return dwErr;
  700. }
  701. //----------------------------------------------------------------------------
  702. // Function: RtmGetRouteNext
  703. //
  704. // continues an enumeration of RTM routes
  705. //----------------------------------------------------------------------------
  706. DWORD
  707. RtmGetRouteNext(
  708. RTM_ENUM_HANDLE hEnumHandle,
  709. PRIP_IP_ROUTE pRoute
  710. ) {
  711. BOOL bRelDest = FALSE, bRelUcast = FALSE;
  712. DWORD dwErr, dwNumDests = 1;
  713. RTM_DEST_INFO rdi, rdiTemp;
  714. char szNetwork[20], szNextHop[20];
  715. do {
  716. //
  717. // Get next route
  718. //
  719. do {
  720. dwErr = RtmGetEnumDests(
  721. ig.IG_RtmHandle, hEnumHandle, &dwNumDests, &rdiTemp
  722. );
  723. if (dwErr == ERROR_NO_MORE_ITEMS) {
  724. if (dwNumDests < 1) {
  725. break;
  726. }
  727. dwErr = NO_ERROR;
  728. }
  729. else if (dwErr != NO_ERROR) {
  730. TRACE1(ANY, "error %d enumeratings dests", dwErr);
  731. break;
  732. }
  733. bRelDest = TRUE;
  734. //
  735. // Get route info for unicast view only
  736. //
  737. dwErr = RtmGetDestInfo(
  738. ig.IG_RtmHandle, rdiTemp.DestHandle, RTM_BEST_PROTOCOL,
  739. RTM_VIEW_MASK_UCAST, &rdi
  740. );
  741. if (dwErr != NO_ERROR) {
  742. TRACE1(ANY, "error %d getting ucast info dests", dwErr);
  743. break;
  744. }
  745. bRelUcast = TRUE;
  746. //
  747. // Check if any route info is present in the UCAST view
  748. //
  749. if ( ( rdi.ViewInfo[0].HoldRoute == NULL ) &&
  750. ( rdi.ViewInfo[0].Route == NULL ) )
  751. {
  752. //
  753. // This destination has no info in the UCAST view
  754. // Release all handles and get next route
  755. //
  756. dwErr = RtmReleaseDests(ig.IG_RtmHandle, 1, &rdi);
  757. if (dwErr != NO_ERROR) {
  758. TRACE3(
  759. ANY, "error %d releasing UCAST dest %s/%d", dwErr,
  760. szNetwork, rdi.DestAddress.NumBits
  761. );
  762. }
  763. dwErr = RtmReleaseDests(ig.IG_RtmHandle, 1, &rdiTemp);
  764. if (dwErr != NO_ERROR) {
  765. TRACE3(
  766. ANY, "error %d releasing dest %s/%d", dwErr,
  767. szNetwork, rdi.DestAddress.NumBits
  768. );
  769. }
  770. bRelDest = bRelUcast = FALSE;
  771. continue;
  772. }
  773. //
  774. // convert to RIP internal representation, if hold down route present
  775. // use it as opposed to the best route.
  776. //
  777. dwErr = GetRouteInfo(
  778. rdi.ViewInfo[0].HoldRoute ? rdi.ViewInfo[0].HoldRoute :
  779. rdi.ViewInfo[0].Route,
  780. NULL, &rdi, pRoute
  781. );
  782. } while (FALSE);
  783. if (dwErr != NO_ERROR) {
  784. break;
  785. }
  786. lstrcpy(szNetwork, INET_NTOA(pRoute->RR_Network.N_NetNumber));
  787. lstrcpy(szNextHop, INET_NTOA(pRoute->RR_NextHopAddress.N_NetNumber));
  788. //
  789. // set metrics as appropriate
  790. //
  791. if ( rdi.ViewInfo[0].HoldRoute != NULL ) {
  792. //
  793. // help down routes are always advertized with
  794. // metric 16
  795. //
  796. #if ROUTE_DBG
  797. TRACE2(
  798. ROUTE, "Holddown route %s/%d", szNetwork,
  799. rdi.DestAddress.NumBits
  800. );
  801. #endif
  802. SETROUTEMETRIC(pRoute, IPRIP_INFINITE);
  803. }
  804. else if (pRoute-> RR_RoutingProtocol != PROTO_IP_RIP) {
  805. //
  806. // non-RIP routes are advertised with metric 2
  807. // TBD: This will need to be re-evaluated if/when we
  808. // have a route redistribution policy
  809. //
  810. SETROUTEMETRIC(pRoute, 2);
  811. }
  812. } while ( FALSE );
  813. //
  814. // release handles as appropriate
  815. //
  816. if (bRelUcast) {
  817. DWORD dwErrTemp;
  818. dwErrTemp = RtmReleaseDests(ig.IG_RtmHandle, 1, &rdi);
  819. if (dwErrTemp != NO_ERROR) {
  820. TRACE3(
  821. ANY, "error %d releasing UCAST dest %s/%d", dwErrTemp,
  822. szNetwork, rdi.DestAddress.NumBits
  823. );
  824. }
  825. }
  826. if (bRelDest) {
  827. DWORD dwErrTemp;
  828. dwErrTemp = RtmReleaseDests(ig.IG_RtmHandle, 1, &rdiTemp);
  829. if (dwErrTemp != NO_ERROR) {
  830. TRACE3(
  831. ANY, "error %d releasing dest %s/%d", dwErrTemp,
  832. szNetwork, rdi.DestAddress.NumBits
  833. );
  834. }
  835. }
  836. #if ROUTE_DBG
  837. if (dwErr == NO_ERROR) {
  838. TRACE4(
  839. ROUTE, "Enumerated route %s/%d via %s with metric %d",
  840. szNetwork, rdi.DestAddress.NumBits,
  841. szNextHop, GETROUTEMETRIC(pRoute)
  842. );
  843. }
  844. #endif
  845. return dwErr;
  846. }
  847. //----------------------------------------------------------------------------
  848. // Function: RtmGetRouteFinish
  849. //
  850. // terminates an enumeration of RTM routes
  851. //----------------------------------------------------------------------------
  852. DWORD
  853. RtmGetRouteFinish(
  854. RTM_ENUM_HANDLE EnumHandle
  855. ) {
  856. DWORD dwErr;
  857. dwErr = RtmDeleteEnumHandle( ig.IG_RtmHandle, EnumHandle );
  858. if (dwErr != NO_ERROR) {
  859. TRACE1( ANY, "error %d closing enumeration handle", dwErr );
  860. }
  861. return dwErr;
  862. }
  863. //----------------------------------------------------------------------------
  864. // Function: ShutdownUpdateGetRouteNext
  865. //
  866. // continues an enumeration of RTM routes for a shutdown-update.
  867. // same as RtmGetRouteNext, except that metrics are set to IPRIP_INFINITE - 1
  868. //----------------------------------------------------------------------------
  869. DWORD
  870. ShutdownUpdateGetRouteNext(
  871. RTM_ENUM_HANDLE hEnumHandle,
  872. PRIP_IP_ROUTE pRoute
  873. ) {
  874. DWORD dwErr;
  875. //
  876. // during a shutdown, all non-infinite metrics are set to 15
  877. //
  878. dwErr = RtmGetRouteNext(hEnumHandle, pRoute);
  879. if (dwErr == NO_ERROR && GETROUTEMETRIC(pRoute) != IPRIP_INFINITE) {
  880. SETROUTEMETRIC(pRoute, IPRIP_INFINITE - 1);
  881. }
  882. return dwErr;
  883. }
  884. //----------------------------------------------------------------------------
  885. // Function: TriggeredUpdateGetRouteStart
  886. //
  887. // starts an enumeration of routes from the send queue
  888. // for a triggered update. nothing to do, since the caller
  889. // of SendRoutes should have locked the send queue already
  890. //----------------------------------------------------------------------------
  891. DWORD
  892. TriggeredUpdateGetRouteStart(
  893. PRTM_ENUM_HANDLE pEnumHandle
  894. ) {
  895. return NO_ERROR;
  896. }
  897. //----------------------------------------------------------------------------
  898. // Function: TriggeredUpdateGetRouteNext
  899. //
  900. // continues an enumeration of routes from the send-queue
  901. //----------------------------------------------------------------------------
  902. DWORD
  903. TriggeredUpdateGetRouteNext(
  904. RTM_ENUM_HANDLE EnumHandle,
  905. PRIP_IP_ROUTE pRoute
  906. ) {
  907. DWORD dwErr;
  908. dwErr = DequeueSendEntry(ig.IG_SendQueue, pRoute);
  909. if (dwErr == NO_ERROR && pRoute->RR_RoutingProtocol != PROTO_IP_RIP) {
  910. //
  911. // non-RIP routes are advertised with metric 2
  912. // TBD: This will need to be re-evaluated if/when we
  913. // have a route redistribution policy
  914. //
  915. SETROUTEMETRIC(pRoute, 2);
  916. }
  917. return dwErr;
  918. }
  919. //----------------------------------------------------------------------------
  920. // Function: TriggeredUpdateGetRouteFinish
  921. //
  922. // terminates an enumeration of routes from the send-queue
  923. //----------------------------------------------------------------------------
  924. DWORD
  925. TriggeredUpdateGetRouteFinish(
  926. RTM_ENUM_HANDLE EnumHandle
  927. ) {
  928. return NO_ERROR;
  929. }
  930. //----------------------------------------------------------------------------
  931. // Function: SendRoutes
  932. //
  933. // This function sends triggered updates, full-updates, shutdown-updates, and
  934. // responses to general requests; the processing for all such output is the
  935. // same. The source of routing information is different, however, and this
  936. // difference is abstracted away using the route enumeration function groups
  937. // described above.
  938. // In the case of sending a response to a general or specific request,
  939. // the response should be sent on a single interface using a single IP address,
  940. // using a particular type of RIP packet; the caller can specify which
  941. // IP address to use by setting the argument dwAddrIndex to the index of the
  942. // desired address in the interface's IP address table, and the caller can
  943. // specify the type of packet to use by setting the argument dwAnnounceMode
  944. // to the corresponding IPRIP_ANNOUNCE_* constant. These arguments are only
  945. // used for responses to requests.
  946. //
  947. // assumes the interface table is locked
  948. //----------------------------------------------------------------------------
  949. DWORD
  950. SendRoutes(
  951. PIF_TABLE_ENTRY pIfList[],
  952. DWORD dwIfCount,
  953. DWORD dwSendMode,
  954. DWORD dwDestination,
  955. DWORD dwAddrIndex
  956. ) {
  957. RTM_ENUM_HANDLE Enumerator;
  958. RIP_IP_ROUTE route;
  959. PIPRIP_IF_CONFIG pic;
  960. PIPRIP_IF_BINDING pib;
  961. PIPRIP_IP_ADDRESS paddr;
  962. DWORD i, dwErr, dwBufCount;
  963. PDWORD pdwPeer, pdwPeerEnd;
  964. PIF_TABLE_ENTRY *ppite, *ppitend = NULL;
  965. PUPDATE_BUFFER pbuf, pbufend, pBufList;
  966. PROUTE_TABLE_ENTRY prte;
  967. ROUTE_TABLE summaryTable;
  968. PGETROUTE_START pfnGetRouteStart;
  969. PGETROUTE_NEXT pfnGetRouteNext;
  970. PGETROUTE_FINISH pfnGetRouteFinish;
  971. PLIST_ENTRY plstart, plend, phead, ple;
  972. //
  973. // if no interfaces, go no further
  974. //
  975. if (dwIfCount == 0) { return ERROR_NO_DATA; }
  976. //
  977. // initialize the route enumeration function table
  978. //
  979. dwErr = InitializeGetRoute(
  980. dwSendMode,
  981. &pfnGetRouteStart,
  982. &pfnGetRouteNext,
  983. &pfnGetRouteFinish
  984. );
  985. if (dwErr != NO_ERROR) { return ERROR_INVALID_PARAMETER; }
  986. dwErr = NO_ERROR;
  987. Enumerator = NULL;
  988. //
  989. // create table for summary routes
  990. //
  991. dwErr = CreateRouteTable(&summaryTable);
  992. if (dwErr != 0) {
  993. TRACE1(SEND, "error %d initializing summary table", dwErr);
  994. return dwErr;
  995. }
  996. dwErr = NO_ERROR;
  997. pBufList = NULL;
  998. do { // breakout loop
  999. //
  1000. // the following discussion does not apply when sending routes
  1001. // to specific destinations:
  1002. // since unicast peers may be configured on some interfaces,
  1003. // we need to allocate update buffers for those peers as well.
  1004. //
  1005. // also, we will not allocate update buffers for RIPv1 interfaces
  1006. // on which broadcast is disabled (such interfaces should have
  1007. // at least one unicast peer configured instead.)
  1008. //
  1009. // Thus, the number of update buffers may not be equal to
  1010. // the number of interfaces, and in the worst case (i.e. where
  1011. // all interfaces are RIPv1 and have broadcast disabled and have
  1012. // no unicast peers configured) there may be no update buffers at all.
  1013. //
  1014. if (dwDestination != 0) {
  1015. //
  1016. // sending to a specific destination; this only happens when
  1017. // there is a single interface in the list, for instance when
  1018. // sending a response to a general request
  1019. //
  1020. dwBufCount = dwIfCount;
  1021. }
  1022. else {
  1023. //
  1024. // we are sending a full-update, triggered-update, or
  1025. // a shutdown-update, and thus routes may be sent by
  1026. // broadcast/multicast as well as to unicast peers
  1027. //
  1028. dwBufCount = 0;
  1029. ppitend = pIfList + dwIfCount;
  1030. for (ppite = pIfList; ppite < ppitend; ppite++) {
  1031. pic = (*ppite)->ITE_Config;
  1032. pib = (*ppite)->ITE_Binding;
  1033. if (pic->IC_UnicastPeerMode != IPRIP_PEER_ONLY) {
  1034. dwBufCount += pib->IB_AddrCount;
  1035. }
  1036. if (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED) {
  1037. dwBufCount += pic->IC_UnicastPeerCount;
  1038. }
  1039. }
  1040. }
  1041. if (dwBufCount == 0) { break; }
  1042. //
  1043. // allocate the update buffers for all interfaces
  1044. //
  1045. pBufList = RIP_ALLOC(dwBufCount * sizeof(UPDATE_BUFFER));
  1046. if (pBufList == NULL) {
  1047. dwErr = GetLastError();
  1048. TRACE2(
  1049. SEND, "error %d allocating %d bytes for update buffers",
  1050. dwErr, dwBufCount * sizeof(UPDATE_BUFFER)
  1051. );
  1052. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1053. break;
  1054. }
  1055. //
  1056. // initialize the update buffers allocated; in the case of
  1057. // sending to a specific destination, initialize a buffer
  1058. // for each interface; in the case of sending updates, also
  1059. // initialize buffers for unicast peers.
  1060. //
  1061. pbuf = pBufList;
  1062. pbufend = pBufList + dwBufCount;
  1063. ppitend = pIfList + dwIfCount;
  1064. ACQUIRE_BINDING_LOCK_SHARED();
  1065. for (ppite = pIfList; ppite < ppitend; ppite++) {
  1066. if (dwDestination != 0) {
  1067. //
  1068. // sending to a specific destination
  1069. //
  1070. InitializeUpdateBuffer(
  1071. *ppite, dwAddrIndex, pbuf, dwSendMode, dwDestination,
  1072. IPRIP_RESPONSE
  1073. );
  1074. pbuf->UB_StartRoutine(pbuf);
  1075. ++pbuf;
  1076. }
  1077. else {
  1078. //
  1079. // sending updates on multiple interfaces
  1080. //
  1081. pic = (*ppite)->ITE_Config;
  1082. pib = (*ppite)->ITE_Binding;
  1083. //
  1084. // if broadcast or multicast is enabled on the interface,
  1085. // and it is not configured to send only to listed peers,
  1086. // initialize the broadcast/multicast update buffer
  1087. //
  1088. if (pic->IC_UnicastPeerMode != IPRIP_PEER_ONLY) {
  1089. for (i = 0; i < pib->IB_AddrCount; i++) {
  1090. InitializeUpdateBuffer(
  1091. *ppite, i, pbuf, dwSendMode, dwDestination,
  1092. IPRIP_RESPONSE
  1093. );
  1094. pbuf->UB_StartRoutine(pbuf);
  1095. ++pbuf;
  1096. }
  1097. }
  1098. if (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED) {
  1099. //
  1100. // initialize update buffers for unicast peers, if any
  1101. //
  1102. pdwPeer = IPRIP_IF_UNICAST_PEER_TABLE(pic);
  1103. pdwPeerEnd = pdwPeer + pic->IC_UnicastPeerCount;
  1104. for ( ; pdwPeer < pdwPeerEnd; pdwPeer++) {
  1105. //
  1106. // Note: forcing peers to be on first address
  1107. //
  1108. InitializeUpdateBuffer(
  1109. *ppite, 0, pbuf, dwSendMode, *pdwPeer,
  1110. IPRIP_RESPONSE
  1111. );
  1112. pbuf->UB_StartRoutine(pbuf);
  1113. ++pbuf;
  1114. }
  1115. }
  1116. }
  1117. }
  1118. RELEASE_BINDING_LOCK_SHARED();
  1119. //
  1120. // start the route enumeration
  1121. //
  1122. if ( pfnGetRouteStart(&Enumerator) == NO_ERROR ) {
  1123. //
  1124. // enumerate and transmit the routes
  1125. //
  1126. while (pfnGetRouteNext(Enumerator, &route) == NO_ERROR) {
  1127. //
  1128. // for each route, send it on each update buffer,
  1129. // subject to split-horizon/poison-reverse/subnet-summary
  1130. // pass in the summary table pointer to store summarized routes
  1131. //
  1132. dwErr = SendRouteOnIfList(
  1133. pBufList, dwBufCount, dwSendMode, &summaryTable, &route
  1134. );
  1135. }
  1136. //
  1137. // terminate the route enumeration
  1138. //
  1139. pfnGetRouteFinish(Enumerator);
  1140. //
  1141. // now send all routes which were summarized
  1142. //
  1143. plstart = summaryTable.RT_HashTableByNetwork;
  1144. plend = plstart + ROUTE_HASHTABLE_SIZE;
  1145. for (phead = plstart; phead < plend; phead++) {
  1146. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  1147. prte = CONTAINING_RECORD(ple, ROUTE_TABLE_ENTRY, RTE_Link);
  1148. //
  1149. // shouldn't summarize when sending summary table contents
  1150. // so we pass NULL instead of a summary table pointer
  1151. //
  1152. SendRouteOnIfList(
  1153. pBufList, dwBufCount, dwSendMode, NULL, &prte->RTE_Route
  1154. );
  1155. }
  1156. }
  1157. //
  1158. // finally, write the summarized routes to RTM
  1159. //
  1160. WriteSummaryRoutes(&summaryTable, ig.IG_RtmHandle);
  1161. }
  1162. } while(FALSE);
  1163. //
  1164. // free the allocated update buffers, if any
  1165. //
  1166. if (pBufList != NULL) {
  1167. pbufend = pBufList + dwBufCount;
  1168. for (pbuf = pBufList; pbuf < pbufend; pbuf++) {
  1169. //
  1170. // send whatever might remain in the update buffer
  1171. //
  1172. pbuf->UB_FinishRoutine(pbuf);
  1173. }
  1174. RIP_FREE(pBufList);
  1175. }
  1176. //
  1177. // delete the summary table
  1178. //
  1179. DeleteRouteTable(&summaryTable);
  1180. return dwErr;
  1181. }
  1182. //----------------------------------------------------------------------------
  1183. // Function: SendRouteOnIfList
  1184. //
  1185. // this function sends a single route on all interfaces in the given
  1186. // interface list, using the update buffers in the given update buffer list
  1187. //----------------------------------------------------------------------------
  1188. DWORD
  1189. SendRouteOnIfList(
  1190. UPDATE_BUFFER pBufList[],
  1191. DWORD dwBufCount,
  1192. DWORD dwSendMode,
  1193. PROUTE_TABLE pSummaryTable,
  1194. PRIP_IP_ROUTE pRoute
  1195. ) {
  1196. RIP_IP_ROUTE route;
  1197. DWORD dwFound, dwTTL;
  1198. PIF_TABLE_ENTRY pite;
  1199. PIPRIP_IF_CONFIG pic;
  1200. PUPDATE_BUFFER pbuf, pbufend;
  1201. DWORD dwDestNetwork, dwNexthopNetwork;
  1202. DWORD dwDestNetclassAddr, dwDestNetclassMask;
  1203. DWORD dwRouteNetclassAddr, dwRouteNetclassMask;
  1204. DWORD dwRouteNetwork, dwRouteNetmask, dwRouteProtocol;
  1205. #if ROUTE_DBG
  1206. CHAR szDest[32];
  1207. CHAR szDestMask[32];
  1208. CHAR szNexthop[32];
  1209. CHAR szNexthopMask[32];
  1210. CHAR szRoute[32];
  1211. CHAR szRouteMask[32];
  1212. //
  1213. // set up variables used for error and information messages
  1214. //
  1215. lstrcpy(szRoute, INET_NTOA(pRoute->RR_Network.N_NetNumber));
  1216. lstrcpy(szRouteMask, INET_NTOA(pRoute->RR_Network.N_NetMask));
  1217. lstrcpy(szNexthop, INET_NTOA(pRoute->RR_NextHopAddress.N_NetNumber));
  1218. lstrcpy(szNexthopMask, INET_NTOA(pRoute->RR_NextHopAddress.N_NetMask));
  1219. #endif
  1220. //
  1221. // we never send summary routes if they are read from RTM;
  1222. // we only send them if they are generated in the process
  1223. // of advertising actual routes on this iteration;
  1224. // we can tell the difference by checking whether we are still
  1225. // generating summary routes (i.e. if pSummaryTable is non-NULL);
  1226. // if we aren't it is time to start sending summary routes
  1227. //
  1228. if (pSummaryTable != NULL && pRoute->RR_RoutingProtocol == PROTO_IP_RIP &&
  1229. GETROUTEFLAG(pRoute) == ROUTEFLAG_SUMMARY) {
  1230. return NO_ERROR;
  1231. }
  1232. //
  1233. // get the route's network and netmask, and compute
  1234. // the route's network class address and the network class mask;
  1235. // to support supernetting, we double-check the class mask
  1236. // and use the supernet mask if necessary
  1237. //
  1238. dwRouteProtocol = pRoute->RR_RoutingProtocol;
  1239. dwRouteNetwork = pRoute->RR_Network.N_NetNumber;
  1240. dwRouteNetmask = pRoute->RR_Network.N_NetMask;
  1241. dwRouteNetclassMask = NETCLASS_MASK(dwRouteNetwork);
  1242. if (dwRouteNetclassMask > dwRouteNetmask) {
  1243. dwRouteNetclassMask = dwRouteNetmask;
  1244. }
  1245. dwRouteNetclassAddr = (dwRouteNetwork & dwRouteNetclassMask);
  1246. //
  1247. // go through each update buffer
  1248. //
  1249. pbufend = pBufList + dwBufCount;
  1250. for (pbuf = pBufList; pbuf < pbufend; pbuf++) {
  1251. pite = pbuf->UB_ITE;
  1252. pic = pite->ITE_Config;
  1253. //
  1254. // if this is a broadcast route entry, skip it
  1255. // The first condition uses the netmask information for this route,
  1256. // stored in route table, to determine if it is a broadcast route
  1257. // The second condition uses the netmask which is computed based
  1258. // on the address class
  1259. // The third condition checks if it is an all 1's broadcast
  1260. //
  1261. if ( IS_DIRECTED_BROADCAST_ADDR(dwRouteNetwork, dwRouteNetmask) ||
  1262. IS_DIRECTED_BROADCAST_ADDR(dwRouteNetwork, dwRouteNetclassMask) ||
  1263. IS_LOCAL_BROADCAST_ADDR(dwRouteNetwork) ) {
  1264. continue;
  1265. }
  1266. //
  1267. // if this is the multicast route entry, skip it
  1268. //
  1269. if ( CLASSD_ADDR( dwRouteNetwork ) || CLASSE_ADDR( dwRouteNetwork ) ) {
  1270. continue;
  1271. }
  1272. //
  1273. // If this is a loopback route, skip it.
  1274. //
  1275. if ( IS_LOOPBACK_ADDR( dwRouteNetwork ) ) {
  1276. continue;
  1277. }
  1278. //
  1279. // if this is the rotue to the outgoing interface's network,
  1280. // (e.g. the route to 10.1.1.0 on interface 10.1.1.1/255.255.255.0)
  1281. // don't include it in the update
  1282. // (clearly, we shouldn't AND the default-route's netmask (0)
  1283. // with anything and expect this to work
  1284. //
  1285. if (dwRouteNetmask &&
  1286. dwRouteNetwork == (pbuf->UB_Address & dwRouteNetmask)) {
  1287. continue;
  1288. }
  1289. //
  1290. // if announcing host routes is disabled on the interface
  1291. // and this is a host route, skip it
  1292. //
  1293. if (dwRouteNetmask == HOSTADDR_MASK &&
  1294. IPRIP_FLAG_IS_DISABLED(pic, ANNOUNCE_HOST_ROUTES)) {
  1295. continue;
  1296. }
  1297. //
  1298. // if announcing default routes is disabled
  1299. // and this is a default route, skip it
  1300. //
  1301. if (dwRouteNetwork == 0 &&
  1302. IPRIP_FLAG_IS_DISABLED(pic, ANNOUNCE_DEFAULT_ROUTES)) {
  1303. continue;
  1304. }
  1305. //
  1306. // now put the route through the announce filters
  1307. //
  1308. if (pic->IC_AnnounceFilterMode != IPRIP_FILTER_DISABLED) {
  1309. //
  1310. // discard if we are including all routes and this route is listed
  1311. // as an exception, or if we are excluding all routes and
  1312. // this route is not listed as an exception
  1313. //
  1314. IS_ROUTE_IN_ANNOUNCE_FILTER(pic, dwRouteNetwork, dwFound);
  1315. if ((pic->IC_AnnounceFilterMode == IPRIP_FILTER_INCLUDE &&
  1316. !dwFound) ||
  1317. (pic->IC_AnnounceFilterMode == IPRIP_FILTER_EXCLUDE &&
  1318. dwFound)) {
  1319. continue;
  1320. }
  1321. }
  1322. //
  1323. // SUBNET-SUMMARY PROCESSING:
  1324. //
  1325. // if the route is not on the network we are sending this to or
  1326. // if the route's mask is longer than that of the network we are
  1327. // sending to, or if the route is a network route, add it to the
  1328. // summary table instead of sending it immediately.
  1329. // default routes are excepted from summarization
  1330. //
  1331. route = *pRoute;
  1332. if (pSummaryTable != NULL && dwRouteNetwork != 0) {
  1333. //
  1334. // get the destination address to which the update is being
  1335. // sent for this interface; double-check the netclass mask
  1336. // to accomodate supernets
  1337. //
  1338. dwDestNetclassAddr = pbuf->UB_DestAddress;
  1339. dwDestNetclassMask = NETCLASS_MASK(dwDestNetclassAddr);
  1340. if (dwDestNetclassMask > pbuf->UB_DestNetmask) {
  1341. dwDestNetclassMask = pbuf->UB_DestNetmask;
  1342. }
  1343. dwDestNetclassAddr = (dwDestNetclassAddr & dwDestNetclassMask);
  1344. if ((dwRouteNetwork == dwRouteNetclassAddr &&
  1345. dwRouteNetmask == dwRouteNetclassMask) ||
  1346. dwDestNetclassAddr != dwRouteNetclassAddr) {
  1347. if ((pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1) ||
  1348. !IPRIP_FLAG_IS_ENABLED(pic, NO_SUBNET_SUMMARY)) {
  1349. //
  1350. // either the route is a network route,
  1351. // or the update is going to a network different
  1352. // from that of the route
  1353. //
  1354. //
  1355. // create an entry in the summary table instead of sending;
  1356. //
  1357. route.RR_Network.N_NetNumber = dwRouteNetclassAddr;
  1358. route.RR_Network.N_NetMask = dwRouteNetclassMask;
  1359. if ((dwRouteNetwork != dwRouteNetclassAddr) ||
  1360. (dwRouteNetmask != dwRouteNetclassMask)) {
  1361. route.RR_RoutingProtocol = PROTO_IP_RIP;
  1362. SETROUTEFLAG(&route, ROUTEFLAG_SUMMARY);
  1363. SETROUTETAG(&route, pic->IC_RouteTag);
  1364. }
  1365. CreateRouteEntry(
  1366. pSummaryTable, &route, pic->IC_RouteExpirationInterval,
  1367. pic->IC_RouteRemovalInterval
  1368. );
  1369. continue;
  1370. }
  1371. }
  1372. else
  1373. if (pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1 &&
  1374. dwRouteNetmask != HOSTADDR_MASK &&
  1375. pbuf->UB_Netmask < dwRouteNetmask) {
  1376. //
  1377. // this is neither a host route nor a default route,
  1378. // and the subnet-mask on the outgoing interface is shorter
  1379. // than that of the route, so the route's network must be
  1380. // truncated lest it be considered a host route by the routers
  1381. // who will receive this update
  1382. // only do this in RIP1 mode, since in RIP2 mode
  1383. // we can include the netmask in the route entry
  1384. //
  1385. route.RR_Network.N_NetNumber &= pbuf->UB_Netmask;
  1386. route.RR_Network.N_NetMask = pbuf->UB_Netmask;
  1387. route.RR_RoutingProtocol = PROTO_IP_RIP;
  1388. SETROUTEFLAG(&route, ROUTEFLAG_SUMMARY);
  1389. SETROUTETAG(&route, pic->IC_RouteTag);
  1390. CreateRouteEntry(
  1391. pSummaryTable, &route, pic->IC_RouteExpirationInterval,
  1392. pic->IC_RouteRemovalInterval
  1393. );
  1394. continue;
  1395. }
  1396. }
  1397. //
  1398. // Summary route checks
  1399. //
  1400. // Summary routes are to sent only on those interfaces that
  1401. // require them i.e. Interfaces on which the annouce mode is
  1402. // RIP1 or on which summarization has been explicity turned on
  1403. //
  1404. if (pSummaryTable == NULL &&
  1405. ((GETROUTEFLAG(&route) & ROUTEFLAG_SUMMARY) == ROUTEFLAG_SUMMARY) &&
  1406. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP1 &&
  1407. IPRIP_FLAG_IS_ENABLED(pic, NO_SUBNET_SUMMARY)) {
  1408. //
  1409. // This is a summary route, and the interface over which it is
  1410. // to be sent does not require summary routes to be sent on it
  1411. //
  1412. continue;
  1413. }
  1414. //
  1415. // SPLIT-HORIZON/POISON-REVERSE PROCESSING:
  1416. //
  1417. //
  1418. // note that we only do split-horizon/poison-reverse on RIP routes
  1419. //
  1420. //
  1421. // Modification : Split-horizon/poison-reverse done for all routes
  1422. //
  1423. // if (dwRouteProtocol != PROTO_IP_RIP ||
  1424. // IPRIP_FLAG_IS_DISABLED(pic, SPLIT_HORIZON))
  1425. if (IPRIP_FLAG_IS_DISABLED(pic, SPLIT_HORIZON)) {
  1426. //
  1427. // add the entry as-is:
  1428. // sender should use us as the nexthop to this destination
  1429. //
  1430. route.RR_NextHopAddress.N_NetNumber = 0;
  1431. route.RR_NextHopAddress.N_NetMask = 0;
  1432. pbuf->UB_AddRoutine(pbuf, &route);
  1433. }
  1434. else
  1435. if (IPRIP_FLAG_IS_DISABLED(pic, POISON_REVERSE)) {
  1436. //
  1437. // if the route is being sent to the network from which
  1438. // the route was learnt, exclude the route altogether
  1439. //
  1440. dwDestNetwork = (pbuf->UB_DestAddress & pbuf->UB_DestNetmask);
  1441. dwNexthopNetwork = (route.RR_NextHopAddress.N_NetNumber &
  1442. route.RR_NextHopAddress.N_NetMask);
  1443. //
  1444. // Check if the route next hop is on the same network as the
  1445. // socket from which this RIP response is being sent.
  1446. // If so, do not include this route in the update.
  1447. // Otherwise, we may still need to do poison-reverse
  1448. // since the next-hop may be the other end of a point-to-point link
  1449. // (endpoints of such links can be on different networks)
  1450. // in which case the first test would succeed (different networks)
  1451. // but we'd still be required to perform split-horizon.
  1452. // Therefore if the outgoing interface is the one from which
  1453. // the route was learnt, we do not include this route in the update.
  1454. //
  1455. if (dwNexthopNetwork == dwDestNetwork ||
  1456. (pbuf->UB_ITE->ITE_Type == DEMAND_DIAL &&
  1457. route.RR_InterfaceID == pbuf->UB_ITE->ITE_Index)) {
  1458. continue;
  1459. }
  1460. else {
  1461. //
  1462. // sending to a different network, so sender should use
  1463. // us as the nexthop to this destination
  1464. //
  1465. route.RR_NextHopAddress.N_NetNumber = 0;
  1466. route.RR_NextHopAddress.N_NetMask = 0;
  1467. }
  1468. pbuf->UB_AddRoutine(pbuf, &route);
  1469. }
  1470. else {
  1471. //
  1472. // if the route is being sent to the network from which
  1473. // the route was learnt, include the route with infinite metric
  1474. //
  1475. dwDestNetwork = (pbuf->UB_DestAddress & pbuf->UB_DestNetmask);
  1476. dwNexthopNetwork = (route.RR_NextHopAddress.N_NetNumber &
  1477. route.RR_NextHopAddress.N_NetMask);
  1478. if (dwNexthopNetwork == dwDestNetwork ||
  1479. (pbuf->UB_ITE->ITE_Type == DEMAND_DIAL &&
  1480. route.RR_InterfaceID == pbuf->UB_ITE->ITE_Index)) {
  1481. //
  1482. // if a route is advertised with infinite metric due to
  1483. // poison-reverse and it would still be advertised with
  1484. // infinite metric in a triggered update, save bandwidth
  1485. // by excluding the route
  1486. //
  1487. if (dwSendMode == SENDMODE_TRIGGERED_UPDATE) {
  1488. continue;
  1489. }
  1490. else {
  1491. SETROUTEMETRIC(&route, IPRIP_INFINITE);
  1492. }
  1493. }
  1494. else {
  1495. //
  1496. // sending to a different network, so sender should use
  1497. // us as the nexthop to this destination
  1498. //
  1499. route.RR_NextHopAddress.N_NetNumber = 0;
  1500. route.RR_NextHopAddress.N_NetMask = 0;
  1501. }
  1502. pbuf->UB_AddRoutine(pbuf, &route);
  1503. }
  1504. //
  1505. // hold advertized destinations
  1506. //
  1507. if ((dwSendMode == SENDMODE_FULL_UPDATE) ||
  1508. (dwSendMode == SENDMODE_GENERAL_RESPONSE1) ||
  1509. (dwSendMode == SENDMODE_GENERAL_RESPONSE2)) {
  1510. //
  1511. // use the hold interval from the interface over which the
  1512. // route is over.
  1513. //
  1514. if (pite->ITE_Index == route.RR_InterfaceID) {
  1515. DWORD dwErr;
  1516. dwErr = RtmHoldDestination(
  1517. ig.IG_RtmHandle, route.hDest, RTM_VIEW_MASK_UCAST,
  1518. pic-> IC_RouteRemovalInterval * 1000
  1519. );
  1520. if (dwErr != NO_ERROR) {
  1521. TRACE1(ANY, "error %d holding dest", dwErr);
  1522. }
  1523. }
  1524. }
  1525. }
  1526. return NO_ERROR;
  1527. }
  1528. //----------------------------------------------------------------------------
  1529. // Function: SendGeneralRequest
  1530. //
  1531. // This function transmits RIP requests on interface to all neighbors in
  1532. // the interfaces neighbor list. A request is also sent via broadcast or
  1533. // multicast is the neighbor list is not used exclusively.
  1534. //----------------------------------------------------------------------------
  1535. DWORD
  1536. SendGeneralRequest(
  1537. PIF_TABLE_ENTRY pite
  1538. ) {
  1539. DWORD i, dwErr;
  1540. PIPRIP_ENTRY pie;
  1541. PIPRIP_IF_CONFIG pic;
  1542. PIPRIP_IF_BINDING pib;
  1543. PIPRIP_IP_ADDRESS paddr;
  1544. PDWORD pdwPeer, pdwPeerEnd;
  1545. pic = pite->ITE_Config;
  1546. pib = pite->ITE_Binding;
  1547. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  1548. ACQUIRE_BINDING_LOCK_SHARED();
  1549. do { // error breakout loop
  1550. //
  1551. // broadcast/multicast a request if not using neighbor-list only
  1552. //
  1553. if (pic->IC_UnicastPeerMode != IPRIP_PEER_ONLY) {
  1554. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  1555. UPDATE_BUFFER ub;
  1556. //
  1557. // initialize the update buffer
  1558. //
  1559. dwErr = InitializeUpdateBuffer(
  1560. pite, i, &ub, SENDMODE_GENERAL_REQUEST, 0,
  1561. IPRIP_REQUEST
  1562. );
  1563. ub.UB_StartRoutine(&ub);
  1564. //
  1565. // set up the general request entry
  1566. //
  1567. pie = (PIPRIP_ENTRY)(ub.UB_Buffer + ub.UB_Length);
  1568. pie->IE_AddrFamily = ADDRFAMILY_REQUEST;
  1569. pie->IE_RouteTag = 0;
  1570. pie->IE_Destination = 0;
  1571. pie->IE_SubnetMask = 0;
  1572. pie->IE_Nexthop = 0;
  1573. pie->IE_Metric = htonl(IPRIP_INFINITE);
  1574. ub.UB_Length += sizeof(IPRIP_ENTRY);
  1575. //
  1576. // send the buffer
  1577. //
  1578. ub.UB_FinishRoutine(&ub);
  1579. }
  1580. }
  1581. //
  1582. // if the list of peers is not in use, we are done
  1583. //
  1584. if (pic->IC_UnicastPeerMode == IPRIP_PEER_DISABLED) { break; }
  1585. //
  1586. // send requests to all the configured peers
  1587. //
  1588. pdwPeer = IPRIP_IF_UNICAST_PEER_TABLE(pic);
  1589. pdwPeerEnd = pdwPeer + pic->IC_UnicastPeerCount;
  1590. for ( ; pdwPeer < pdwPeerEnd; pdwPeer++) {
  1591. UPDATE_BUFFER ub;
  1592. //
  1593. // initialize the update buffer
  1594. // Note: we are forcing the peers onto the first address
  1595. //
  1596. dwErr = InitializeUpdateBuffer(
  1597. pite, 0, &ub, SENDMODE_GENERAL_REQUEST, *pdwPeer,
  1598. IPRIP_REQUEST
  1599. );
  1600. ub.UB_StartRoutine(&ub);
  1601. //
  1602. // set up the general request entry
  1603. //
  1604. pie = (PIPRIP_ENTRY)(ub.UB_Buffer + ub.UB_Length);
  1605. pie->IE_AddrFamily = ADDRFAMILY_REQUEST;
  1606. pie->IE_RouteTag = 0;
  1607. pie->IE_Destination = 0;
  1608. pie->IE_SubnetMask = 0;
  1609. pie->IE_Nexthop = 0;
  1610. pie->IE_Metric = htonl(IPRIP_INFINITE);
  1611. ub.UB_Length += sizeof(IPRIP_ENTRY);
  1612. //
  1613. // send the buffer
  1614. //
  1615. ub.UB_FinishRoutine(&ub);
  1616. }
  1617. } while(FALSE);
  1618. RELEASE_BINDING_LOCK_SHARED();
  1619. return NO_ERROR;
  1620. }
  1621. //----------------------------------------------------------------------------
  1622. // Function: AuthenticatePacket
  1623. //
  1624. // Given a RIP packet and an interface configuration block, this function
  1625. // accepts or rejects the packet based on the authentication settings
  1626. // of the interface and the authentication content of the packet.
  1627. //----------------------------------------------------------------------------
  1628. DWORD
  1629. AuthenticatePacket(
  1630. PBYTE pbuf,
  1631. PIPRIP_AUTHENT_ENTRY pae,
  1632. PIPRIP_IF_CONFIG pic,
  1633. PIPRIP_IF_STATS pis,
  1634. PIPRIP_PEER_STATS pps,
  1635. PIPRIP_ENTRY *ppie
  1636. ) {
  1637. DWORD dwErr;
  1638. dwErr = NO_ERROR;
  1639. if (pic->IC_AuthenticationType == IPRIP_AUTHTYPE_NONE) {
  1640. //
  1641. // interface is not configured for authentication,
  1642. // so discard authenticated packets
  1643. //
  1644. if (pae->IAE_AddrFamily == htons(ADDRFAMILY_AUTHENT)) {
  1645. if (pis != NULL) {
  1646. InterlockedIncrement(&pis->IS_BadResponsePacketsReceived);
  1647. }
  1648. if (pps != NULL) {
  1649. InterlockedIncrement(&pps->PS_BadResponsePacketsFromPeer);
  1650. }
  1651. dwErr = ERROR_ACCESS_DENIED;
  1652. }
  1653. }
  1654. else {
  1655. //
  1656. // interface is using authentication,
  1657. // so discard unauthenticated packets
  1658. // and packets using different authentication schemes
  1659. //
  1660. if (pae->IAE_AddrFamily != htons(ADDRFAMILY_AUTHENT) ||
  1661. pae->IAE_AuthType != htons((WORD)pic->IC_AuthenticationType)) {
  1662. if (pis != NULL) {
  1663. InterlockedIncrement(&pis->IS_BadResponsePacketsReceived);
  1664. }
  1665. if (pps != NULL) {
  1666. InterlockedIncrement(&pps->PS_BadResponsePacketsFromPeer);
  1667. }
  1668. dwErr = ERROR_ACCESS_DENIED;
  1669. }
  1670. else {
  1671. //
  1672. // interface and packet are using the same authentication:
  1673. // check that the packet passes validation
  1674. //
  1675. switch(pic->IC_AuthenticationType) {
  1676. case IPRIP_AUTHTYPE_SIMPLE_PASSWORD:
  1677. //
  1678. // for simple passwords, just compare the keys
  1679. //
  1680. dwErr = (DWORD)memcmp(
  1681. pae->IAE_AuthKey, pic->IC_AuthenticationKey,
  1682. IPRIP_MAX_AUTHKEY_SIZE
  1683. );
  1684. if (dwErr != 0) { dwErr = ERROR_ACCESS_DENIED; }
  1685. break;
  1686. case IPRIP_AUTHTYPE_MD5:
  1687. //
  1688. // TBD: unimplemented unless required.
  1689. //
  1690. break;
  1691. }
  1692. //
  1693. // advance the "first entry" pointer
  1694. //
  1695. if (dwErr == NO_ERROR) { ++(*ppie); }
  1696. }
  1697. }
  1698. return dwErr;
  1699. }
  1700. //----------------------------------------------------------------------------
  1701. // Function: WorkerFunctionProcessInput
  1702. //
  1703. // This function is responsible for processing input.
  1704. // If any peer filters exist, it applies them to the routes received
  1705. // and passes the packets on to the processing functions.
  1706. //----------------------------------------------------------------------------
  1707. VOID
  1708. WorkerFunctionProcessInput(
  1709. PVOID pContext
  1710. ) {
  1711. PINPUT_CONTEXT pwc;
  1712. DWORD dwErr, dwCommand;
  1713. PIPRIP_GLOBAL_CONFIG pigc;
  1714. if (!ENTER_RIP_WORKER()) { return; }
  1715. TRACE0(ENTER, "entering WorkerFunctionProcessInput");
  1716. do {
  1717. ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
  1718. dwErr = DequeueRecvEntry(ig.IG_RecvQueue, &dwCommand, (PBYTE *)&pwc);
  1719. RELEASE_LIST_LOCK(ig.IG_RecvQueue);
  1720. if (dwErr != NO_ERROR) {
  1721. TRACE1(RECEIVE, "error %d dequeueing received packet", dwErr);
  1722. break;
  1723. }
  1724. //
  1725. // call the processing function for this type of packet
  1726. //
  1727. if (dwCommand == IPRIP_REQUEST) {
  1728. ProcessRequest(pwc);
  1729. }
  1730. else
  1731. if (dwCommand == IPRIP_RESPONSE) {
  1732. DWORD dwSource, dwFound = 0;
  1733. dwSource = pwc->IC_InputSource.sin_addr.s_addr;
  1734. //
  1735. // make sure the packet is from the RIP port
  1736. //
  1737. if (pwc->IC_InputSource.sin_port != htons(IPRIP_PORT)) {
  1738. LPSTR lpszAddr = INET_NTOA(dwSource);
  1739. TRACE2(
  1740. RECEIVE, "invalid port in RESPONSE from %s on interface %d",
  1741. lpszAddr, pwc->IC_InterfaceIndex
  1742. );
  1743. LOGINFO1(INVALID_PORT, lpszAddr, NO_ERROR);
  1744. RIP_FREE(pwc);
  1745. break;
  1746. }
  1747. //
  1748. // put the packet through the peer filters since it is a response
  1749. //
  1750. ACQUIRE_GLOBAL_LOCK_SHARED();
  1751. pigc = ig.IG_Config;
  1752. if (dwCommand == IPRIP_RESPONSE &&
  1753. pigc->GC_PeerFilterMode != IPRIP_FILTER_DISABLED) {
  1754. //
  1755. // discard if this is not from a trusted peer:
  1756. // this is so if we are including only listed peers and this peer
  1757. // is not listed, or if we are excluding all listed peers
  1758. // and this peer is listed
  1759. //
  1760. IS_PEER_IN_FILTER(pigc, dwSource, dwFound);
  1761. if ((!dwFound &&
  1762. pigc->GC_PeerFilterMode == IPRIP_FILTER_INCLUDE) ||
  1763. (dwFound &&
  1764. pigc->GC_PeerFilterMode == IPRIP_FILTER_EXCLUDE)) {
  1765. LPSTR lpszAddr = INET_NTOA(dwSource);
  1766. TRACE2(
  1767. RECEIVE,
  1768. "FILTER: dropping RESPONSE from %s on interface %d",
  1769. lpszAddr, pwc->IC_InterfaceIndex
  1770. );
  1771. LOGINFO1(RESPONSE_FILTERED, lpszAddr, NO_ERROR);
  1772. RELEASE_GLOBAL_LOCK_SHARED();
  1773. RIP_FREE(pwc);
  1774. break;
  1775. }
  1776. }
  1777. RELEASE_GLOBAL_LOCK_SHARED();
  1778. ProcessResponse(pwc);
  1779. }
  1780. } while(FALSE);
  1781. TRACE0(LEAVE, "leaving WorkerFunctionProcessInput");
  1782. LEAVE_RIP_WORKER();
  1783. return;
  1784. }
  1785. //----------------------------------------------------------------------------
  1786. // Function: ProcessRequest
  1787. //
  1788. // This function handles the processing of an incoming request packet.
  1789. //----------------------------------------------------------------------------
  1790. VOID
  1791. ProcessRequest(
  1792. PVOID pContext
  1793. ) {
  1794. PBYTE pbuf;
  1795. DWORD dwSize;
  1796. CHAR szSource[20];
  1797. PIPRIP_IF_STATS pis;
  1798. PIPRIP_ENTRY pie;
  1799. PIPRIP_HEADER pih;
  1800. PIPRIP_AUTHENT_ENTRY pae;
  1801. PIF_TABLE pTable;
  1802. PINPUT_CONTEXT pwc;
  1803. PIF_TABLE_ENTRY pite;
  1804. PIPRIP_IF_CONFIG pic;
  1805. PIPRIP_IP_ADDRESS paddr;
  1806. PPEER_TABLE_ENTRY ppte;
  1807. PIPRIP_PEER_STATS pps;
  1808. TRACE0(ENTER, "entering ProcessRequest");
  1809. pTable = ig.IG_IfTable;
  1810. ACQUIRE_IF_LOCK_SHARED();
  1811. do { // breakout loop
  1812. //
  1813. // retrieve the interface on which the request arrived
  1814. //
  1815. pwc = (PINPUT_CONTEXT)pContext;
  1816. pite = GetIfByIndex(pTable, pwc->IC_InterfaceIndex);
  1817. if (pite == NULL || IF_IS_INACTIVE(pite)) {
  1818. TRACE1(
  1819. REQUEST, "processing request: interface %d not found",
  1820. pwc->IC_InterfaceIndex
  1821. );
  1822. break;
  1823. }
  1824. pic = pite->ITE_Config;
  1825. paddr = IPRIP_IF_ADDRESS_TABLE(pite->ITE_Binding) + pwc->IC_AddrIndex;
  1826. pbuf = pwc->IC_InputPacket.IP_Packet;
  1827. pih = (PIPRIP_HEADER)pbuf;
  1828. pie = (PIPRIP_ENTRY)(pbuf + sizeof(IPRIP_HEADER));
  1829. pae = (PIPRIP_AUTHENT_ENTRY)pie;
  1830. pis = NULL;
  1831. pps = NULL;
  1832. lstrcpy(szSource, INET_NTOA(pwc->IC_InputSource.sin_addr));
  1833. //
  1834. // make sure this is a packet we can respond to;
  1835. // discard if this is a v1 packet and this interface is v2-only or
  1836. // if this is a v2-packet and this interface is v1-only
  1837. //
  1838. if ((pih->IH_Version != 2 &&
  1839. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP2)) {
  1840. CHAR szVersion[10];
  1841. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  1842. TRACE2(
  1843. REQUEST, "discarding non-v2 request on RIPv2 interface %d (%s)",
  1844. pite->ITE_Index, lpszAddr
  1845. );
  1846. wsprintf(szVersion, "%d", pih->IH_Version);
  1847. LOGINFO4(
  1848. PACKET_VERSION_MISMATCH, szVersion, lpszAddr, szSource, "2", 0
  1849. );
  1850. break;
  1851. }
  1852. else
  1853. if ((pih->IH_Version != 1 &&
  1854. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1)) {
  1855. CHAR szVersion[10];
  1856. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  1857. TRACE2(
  1858. REQUEST, "discarding RIPv2 request on RIPv1 interface %d (%s)",
  1859. pite->ITE_Index, lpszAddr
  1860. );
  1861. wsprintf(szVersion, "%d", pih->IH_Version);
  1862. LOGINFO4(
  1863. PACKET_VERSION_MISMATCH, szVersion, lpszAddr, szSource, "1", 0
  1864. );
  1865. break;
  1866. }
  1867. //
  1868. // version 2 packets call for authentication processing;
  1869. //
  1870. if (pih->IH_Version == 2) {
  1871. DWORD dwErr;
  1872. dwErr = AuthenticatePacket(pbuf, pae, pic, pis, pps, &pie);
  1873. if (dwErr == ERROR_ACCESS_DENIED) {
  1874. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  1875. TRACE3(
  1876. REQUEST, "dropping packet from %s on interface %d (%s): authentication failed",
  1877. szSource, pite->ITE_Index, lpszAddr
  1878. );
  1879. LOGWARN2(AUTHENTICATION_FAILED, lpszAddr, szSource, NO_ERROR);
  1880. break;
  1881. }
  1882. }
  1883. //
  1884. // find the total remaining size of the packet
  1885. //
  1886. dwSize = (DWORD)(((ULONG_PTR)pbuf + pwc->IC_InputLength) - (ULONG_PTR)pie);
  1887. //
  1888. // see which kind of request this is
  1889. //
  1890. if (pie->IE_AddrFamily == ADDRFAMILY_REQUEST &&
  1891. pie->IE_Metric == htonl(IPRIP_INFINITE) &&
  1892. dwSize == sizeof(IPRIP_ENTRY)) {
  1893. //
  1894. // GENERAL REQUEST:
  1895. //
  1896. // send all routes on the interface
  1897. //
  1898. if (pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED ||
  1899. pwc->IC_InputSource.sin_port != htons(IPRIP_PORT)) {
  1900. TRACE3(
  1901. REQUEST, "responding to GENERAL REQUEST from %s on interface %d (%s)",
  1902. szSource, pite->ITE_Index, INET_NTOA(paddr->IA_Address)
  1903. );
  1904. //
  1905. // send version 2 packets in response to version 2 requests
  1906. // and send version 1 packets in response to all other requests
  1907. //
  1908. if (pih->IH_Version != 2) {
  1909. SendRoutes(
  1910. &pite, 1, SENDMODE_GENERAL_RESPONSE1,
  1911. pwc->IC_InputSource.sin_addr.s_addr, pwc->IC_AddrIndex
  1912. );
  1913. }
  1914. else {
  1915. SendRoutes(
  1916. &pite, 1, SENDMODE_GENERAL_RESPONSE2,
  1917. pwc->IC_InputSource.sin_addr.s_addr, pwc->IC_AddrIndex
  1918. );
  1919. }
  1920. InterlockedIncrement(&ig.IG_Stats.GS_TotalResponsesSent);
  1921. }
  1922. }
  1923. else
  1924. if (pic->IC_AnnounceMode == IPRIP_ANNOUNCE_DISABLED &&
  1925. pwc->IC_InputSource.sin_port == htons(IPRIP_PORT)) {
  1926. //
  1927. // SPECIFIC REQUEST:
  1928. // We are in silent mode and the request came from port 520,
  1929. // so we are not allowed to respond.
  1930. //
  1931. TRACE3(
  1932. REQUEST, "ignoring SPECIFIC REQUEST from %s on interface %d (%s)",
  1933. szSource, pite->ITE_Index, INET_NTOA(paddr->IA_Address)
  1934. );
  1935. }
  1936. else {
  1937. IP_NETWORK net;
  1938. UPDATE_BUFFER ub;
  1939. RIP_IP_ROUTE route;
  1940. PIPRIP_ENTRY piend;
  1941. RTM_NET_ADDRESS rna;
  1942. RTM_DEST_INFO rdi;
  1943. DWORD dwErr;
  1944. //
  1945. // SPECIFIC REQUEST:
  1946. // have to look up each destination in the packet
  1947. // and fill in our metric for it if it exists in RTM
  1948. //
  1949. TRACE3(
  1950. REQUEST, "responding to SPECIFIC REQUEST from %s on interface %d (%s)",
  1951. szSource, pite->ITE_Index, INET_NTOA(paddr->IA_Address)
  1952. );
  1953. //
  1954. // acquire the binding-table lock since InitializeUpdateBuffer
  1955. // needs to call GuessSubnetMask to generate a broadcast address
  1956. // to which the response will be sent
  1957. //
  1958. ACQUIRE_BINDING_LOCK_SHARED();
  1959. if (pih->IH_Version != 2) {
  1960. InitializeUpdateBuffer(
  1961. pite, pwc->IC_AddrIndex, &ub, SENDMODE_SPECIFIC_RESPONSE1,
  1962. pwc->IC_InputSource.sin_addr.s_addr, IPRIP_RESPONSE
  1963. );
  1964. }
  1965. else {
  1966. InitializeUpdateBuffer(
  1967. pite, pwc->IC_AddrIndex, &ub, SENDMODE_SPECIFIC_RESPONSE2,
  1968. pwc->IC_InputSource.sin_addr.s_addr, IPRIP_RESPONSE
  1969. );
  1970. }
  1971. //
  1972. // we must reply to the port from which the message was sent
  1973. //
  1974. ub.UB_Destination = pwc->IC_InputSource;
  1975. //
  1976. // start the update buffer
  1977. //
  1978. ub.UB_StartRoutine(&ub);
  1979. //
  1980. // query RTM for each route entry in packet
  1981. //
  1982. piend = (PIPRIP_ENTRY)(pbuf + pwc->IC_InputLength);
  1983. for ( ; pie < piend; pie++) {
  1984. //
  1985. // ignore unrecognized address families
  1986. //
  1987. if (pie->IE_AddrFamily != htons(AF_INET)) {
  1988. continue;
  1989. }
  1990. net.N_NetNumber = pie->IE_Destination;
  1991. if (pih->IH_Version == 2 && pie->IE_SubnetMask != 0) {
  1992. net.N_NetMask = pie->IE_SubnetMask;
  1993. }
  1994. else {
  1995. net.N_NetMask = GuessSubnetMask(net.N_NetNumber, NULL);
  1996. }
  1997. //
  1998. // lookup best route to the requested destination
  1999. // and get the metric
  2000. //
  2001. RTM_IPV4_SET_ADDR_AND_MASK(
  2002. &rna, net.N_NetNumber, net.N_NetMask
  2003. );
  2004. dwErr = RtmGetExactMatchDestination(
  2005. ig.IG_RtmHandle, &rna, RTM_BEST_PROTOCOL,
  2006. RTM_VIEW_MASK_UCAST, &rdi
  2007. );
  2008. if (dwErr != NO_ERROR) {
  2009. pie->IE_Metric = htonl(IPRIP_INFINITE);
  2010. }
  2011. else
  2012. {
  2013. //
  2014. // if there is no best route to this destination
  2015. // metric is INFINITE
  2016. //
  2017. if (rdi.ViewInfo[0].Route == NULL) {
  2018. pie->IE_Metric = htonl(IPRIP_INFINITE);
  2019. }
  2020. else {
  2021. dwErr = GetRouteInfo(
  2022. rdi.ViewInfo[0].Route, NULL, &rdi, &route
  2023. );
  2024. if (dwErr != NO_ERROR) {
  2025. pie->IE_Metric = htonl(IPRIP_INFINITE);
  2026. }
  2027. else {
  2028. //
  2029. // non-RIP routes are advertised with metric 2
  2030. //
  2031. pie->IE_Metric = (route.RR_RoutingProtocol == PROTO_IP_RIP ?
  2032. htonl(GETROUTEMETRIC(&route)) : htonl(2));
  2033. }
  2034. }
  2035. //
  2036. // release the dest info
  2037. //
  2038. dwErr = RtmReleaseDestInfo(ig.IG_RtmHandle, &rdi);
  2039. if (dwErr != NO_ERROR)
  2040. {
  2041. char szNet[20], szMask[20];
  2042. lstrcpy(szNet, INET_NTOA(route.RR_Network.N_NetNumber));
  2043. lstrcpy(szMask, INET_NTOA(route.RR_Network.N_NetMask));
  2044. TRACE3(
  2045. ROUTE, "error %d releasing dest %s:%s", dwErr,
  2046. szNet, szMask
  2047. );
  2048. }
  2049. }
  2050. RTM_ROUTE_FROM_IPRIP_ENTRY(&route, pie);
  2051. ub.UB_AddRoutine(&ub, &route);
  2052. }
  2053. RELEASE_BINDING_LOCK_SHARED();
  2054. //
  2055. // send the buffer now
  2056. //
  2057. ub.UB_FinishRoutine(&ub);
  2058. InterlockedIncrement(&ig.IG_Stats.GS_TotalResponsesSent);
  2059. }
  2060. } while(FALSE);
  2061. RELEASE_IF_LOCK_SHARED();
  2062. RIP_FREE(pContext);
  2063. TRACE0(LEAVE, "leaving ProcessRequest");
  2064. }
  2065. //----------------------------------------------------------------------------
  2066. // Function: ProcessResponse
  2067. //
  2068. // this function process an incoming IPRIP response packet
  2069. //----------------------------------------------------------------------------
  2070. VOID
  2071. ProcessResponse(
  2072. PVOID pContext
  2073. ) {
  2074. DWORD dwSource;
  2075. PBYTE pPacket;
  2076. PIPRIP_IF_STATS pis;
  2077. PIF_TABLE pTable;
  2078. PIPRIP_HEADER pih;
  2079. BOOL bTriggerUpdate;
  2080. PIPRIP_ENTRY pie, piend;
  2081. PIPRIP_AUTHENT_ENTRY pae;
  2082. PIF_TABLE_ENTRY pite;
  2083. PIPRIP_IF_CONFIG pic;
  2084. PIPRIP_IP_ADDRESS paddr;
  2085. PINPUT_CONTEXT pwc;
  2086. PPEER_TABLE pPeers;
  2087. PPEER_TABLE_ENTRY ppte;
  2088. PIPRIP_PEER_STATS pps;
  2089. CHAR szSource[20], szNetwork[20];
  2090. LPSTR lpszTemp = NULL;
  2091. TRACE0(ENTER, "entering ProcessResponse");
  2092. bTriggerUpdate = FALSE;
  2093. pTable = ig.IG_IfTable;
  2094. pPeers = ig.IG_PeerTable;
  2095. ACQUIRE_IF_LOCK_SHARED();
  2096. do { // breakout loop
  2097. pwc = (PINPUT_CONTEXT)pContext;
  2098. //
  2099. // get pointer to receiving interface
  2100. //
  2101. pite = GetIfByIndex(pTable, pwc->IC_InterfaceIndex);
  2102. if (pite == NULL || IF_IS_INACTIVE(pite)) {
  2103. TRACE1(
  2104. RESPONSE, "processing response: interface %d not found",
  2105. pwc->IC_InterfaceIndex
  2106. );
  2107. break;
  2108. }
  2109. ZeroMemory(szSource, sizeof(szSource));
  2110. ZeroMemory(szNetwork, sizeof(szSource));
  2111. dwSource = pwc->IC_InputSource.sin_addr.s_addr;
  2112. lpszTemp = INET_NTOA(dwSource);
  2113. if (lpszTemp != NULL) { lstrcpy(szSource, lpszTemp); }
  2114. else { ZeroMemory(szSource, sizeof(szSource)); }
  2115. //
  2116. // get pointer to peer struct for sender
  2117. //
  2118. ACQUIRE_PEER_LOCK_SHARED();
  2119. ppte = GetPeerByAddress(pPeers, dwSource, GETMODE_EXACT, NULL);
  2120. if (ppte != NULL) { pps = &ppte->PTE_Stats; }
  2121. else { pps = NULL; }
  2122. RELEASE_PEER_LOCK_SHARED();
  2123. pis = &pite->ITE_Stats;
  2124. pic = pite->ITE_Config;
  2125. paddr = IPRIP_IF_ADDRESS_TABLE(pite->ITE_Binding) + pwc->IC_AddrIndex;
  2126. pPacket = pwc->IC_InputPacket.IP_Packet;
  2127. pih = (PIPRIP_HEADER)pPacket;
  2128. pie = (PIPRIP_ENTRY)(pPacket + sizeof(IPRIP_HEADER));
  2129. pae = (PIPRIP_AUTHENT_ENTRY)pie;
  2130. //
  2131. // make sure our configuration allows us to handle this packet
  2132. //
  2133. if ((pih->IH_Version != 2 &&
  2134. pic->IC_AcceptMode == IPRIP_ACCEPT_RIP2)) {
  2135. CHAR szVersion[10];
  2136. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  2137. InterlockedIncrement(&pis->IS_BadResponsePacketsReceived);
  2138. if (pps != NULL) {
  2139. InterlockedIncrement(&pps->PS_BadResponsePacketsFromPeer);
  2140. }
  2141. if (lpszAddr != NULL) {
  2142. TRACE2(
  2143. RESPONSE, "dropping non-v2 packet on RIPv2 interface %d (%s)",
  2144. pite->ITE_Index, lpszAddr
  2145. );
  2146. wsprintf(szVersion, "%d", pih->IH_Version);
  2147. LOGWARN4(
  2148. PACKET_VERSION_MISMATCH, szVersion, lpszAddr, szSource, "2", 0
  2149. );
  2150. }
  2151. break;
  2152. }
  2153. else
  2154. if ((pih->IH_Version != 1 &&
  2155. pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1)) {
  2156. CHAR szVersion[10];
  2157. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  2158. InterlockedIncrement(&pis->IS_BadResponsePacketsReceived);
  2159. if (pps != NULL) {
  2160. InterlockedIncrement(&pps->PS_BadResponsePacketsFromPeer);
  2161. }
  2162. if (lpszAddr != NULL) {
  2163. TRACE2(
  2164. RESPONSE, "dropping RIPv2 packet on RIPv1 interface %d (%s)",
  2165. pite->ITE_Index, lpszAddr
  2166. );
  2167. wsprintf(szVersion, "%d", pih->IH_Version);
  2168. LOGWARN4(
  2169. PACKET_VERSION_MISMATCH, szVersion, lpszAddr, szSource, "1", 0
  2170. );
  2171. }
  2172. break;
  2173. }
  2174. //
  2175. // version 2 packets call for authentication processing;
  2176. //
  2177. if (pih->IH_Version == 2) {
  2178. DWORD dwErr;
  2179. dwErr = AuthenticatePacket(pPacket, pae, pic, pis, pps, &pie);
  2180. if (dwErr == ERROR_ACCESS_DENIED) {
  2181. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  2182. if (lpszAddr != NULL) {
  2183. TRACE3(
  2184. RESPONSE, "dropping packet from %s on interface %d (%s): authentication failed",
  2185. szSource, pite->ITE_Index, lpszAddr
  2186. );
  2187. LOGWARN2(AUTHENTICATION_FAILED, lpszAddr, szSource, NO_ERROR);
  2188. }
  2189. break;
  2190. }
  2191. }
  2192. //
  2193. // need to lock the binding table since GuessSubnetMask will be called
  2194. // inside ProcessResponseEntry
  2195. // need to lock the global config since EnqueueSendEntry will be called
  2196. // inside ProcessResponseEntry
  2197. //
  2198. ACQUIRE_BINDING_LOCK_SHARED();
  2199. ACQUIRE_GLOBAL_LOCK_SHARED();
  2200. //
  2201. // process each entry; reserved fields must be checked for non-RIPv2
  2202. //
  2203. piend = (PIPRIP_ENTRY)(pPacket + pwc->IC_InputLength);
  2204. if (pih->IH_Version == 1) {
  2205. for ( ; pie < piend; pie++) {
  2206. //
  2207. // validate the route entry fields
  2208. //
  2209. if (pie->IE_AddrFamily != htons(AF_INET) ||
  2210. pie->IE_RouteTag != 0 || pie->IE_SubnetMask != 0 ||
  2211. pie->IE_Nexthop != 0) {
  2212. LPSTR lpszAddr;
  2213. //
  2214. // update stats on ignored entries
  2215. //
  2216. InterlockedIncrement(&pis->IS_BadResponseEntriesReceived);
  2217. if (pps != NULL) {
  2218. InterlockedIncrement(
  2219. &pps->PS_BadResponseEntriesFromPeer
  2220. );
  2221. }
  2222. lpszAddr = INET_NTOA(pie->IE_Destination);
  2223. if (lpszAddr != NULL) {
  2224. lstrcpy(szNetwork, lpszAddr);
  2225. lpszAddr = INET_NTOA(paddr->IA_Address);
  2226. if (lpszAddr != NULL) {
  2227. LOGINFO3(
  2228. ROUTE_ENTRY_IGNORED, lpszAddr, szNetwork, szSource, 0
  2229. );
  2230. }
  2231. }
  2232. continue;
  2233. }
  2234. //
  2235. // entry is alright, process it
  2236. //
  2237. if (ProcessResponseEntry(
  2238. pite, pwc->IC_AddrIndex, dwSource, pie, pps
  2239. )) {
  2240. bTriggerUpdate = TRUE;
  2241. }
  2242. }
  2243. }
  2244. else
  2245. if (pih->IH_Version == 2) {
  2246. //
  2247. // this is a RIPv2 packet, so the reserved fields in entries
  2248. // may optionally contain information about the route;
  2249. //
  2250. for ( ; pie < piend; pie++) {
  2251. //
  2252. // validate the route entry fields
  2253. //
  2254. if (pie->IE_AddrFamily != htons(AF_INET)) {
  2255. LPSTR lpszAddr;
  2256. //
  2257. // update stats on ignored entries
  2258. //
  2259. InterlockedIncrement(&pis->IS_BadResponseEntriesReceived);
  2260. if (pps != NULL) {
  2261. InterlockedIncrement(
  2262. &pps->PS_BadResponseEntriesFromPeer
  2263. );
  2264. }
  2265. lpszAddr = INET_NTOA(pie->IE_Destination);
  2266. if (lpszAddr != NULL) {
  2267. lstrcpy(szNetwork, lpszAddr);
  2268. lpszAddr = INET_NTOA(paddr->IA_Address);
  2269. if (lpszAddr != NULL) {
  2270. LOGINFO3(
  2271. ROUTE_ENTRY_IGNORED, lpszAddr, szNetwork, szSource, 0
  2272. );
  2273. }
  2274. }
  2275. continue;
  2276. }
  2277. //
  2278. // entry is alright, process it
  2279. //
  2280. if (ProcessResponseEntry(
  2281. pite, pwc->IC_AddrIndex, dwSource, pie, pps
  2282. )) {
  2283. bTriggerUpdate = TRUE;
  2284. }
  2285. }
  2286. }
  2287. else {
  2288. //
  2289. // this packet's version is greater than 2, so we ignore
  2290. // the contents of the reserved fields
  2291. //
  2292. for ( ; pie < piend; pie++) {
  2293. //
  2294. // validate the route entry fields
  2295. //
  2296. if (pie->IE_AddrFamily != htons(AF_INET)) {
  2297. LPSTR lpszAddr;
  2298. //
  2299. // update stats on ignored entries
  2300. //
  2301. InterlockedIncrement(&pis->IS_BadResponseEntriesReceived);
  2302. if (pps != NULL) {
  2303. InterlockedIncrement(
  2304. &pps->PS_BadResponseEntriesFromPeer
  2305. );
  2306. }
  2307. lpszAddr = INET_NTOA(pie->IE_Destination);
  2308. if (lpszAddr != NULL) {
  2309. lstrcpy(szNetwork, lpszAddr);
  2310. lpszAddr = INET_NTOA(paddr->IA_Address);
  2311. if (lpszAddr != NULL) {
  2312. LOGINFO3(
  2313. ROUTE_ENTRY_IGNORED, lpszAddr, szNetwork, szSource, 0
  2314. );
  2315. }
  2316. }
  2317. continue;
  2318. }
  2319. //
  2320. // entry is alright, clear reserved fields and process
  2321. //
  2322. pie->IE_Nexthop = 0;
  2323. pie->IE_RouteTag = 0;
  2324. pie->IE_SubnetMask = 0;
  2325. if (ProcessResponseEntry(
  2326. pite, pwc->IC_AddrIndex, dwSource, pie, pps
  2327. )) {
  2328. bTriggerUpdate = TRUE;
  2329. }
  2330. }
  2331. }
  2332. RELEASE_GLOBAL_LOCK_SHARED();
  2333. RELEASE_BINDING_LOCK_SHARED();
  2334. //
  2335. // generate a triggered update if necessary
  2336. //
  2337. if (bTriggerUpdate) {
  2338. QueueRipWorker(WorkerFunctionStartTriggeredUpdate, NULL);
  2339. }
  2340. } while(FALSE);
  2341. RELEASE_IF_LOCK_SHARED();
  2342. RIP_FREE(pContext);
  2343. TRACE0(LEAVE, "leaving ProcessResponse");
  2344. }
  2345. //----------------------------------------------------------------------------
  2346. // Function: ProcessResponseEntry
  2347. //
  2348. // this function processes the given response packet entry, received
  2349. // on the given interface from the given source.
  2350. // If a triggered update is necessary, this function returns TRUE.
  2351. //----------------------------------------------------------------------------
  2352. BOOL
  2353. ProcessResponseEntry(
  2354. PIF_TABLE_ENTRY pITE,
  2355. DWORD dwAddrIndex,
  2356. DWORD dwSource,
  2357. PIPRIP_ENTRY pIE,
  2358. PIPRIP_PEER_STATS pPS
  2359. ) {
  2360. IP_NETWORK in;
  2361. PIPRIP_IF_STATS pis;
  2362. PIPRIP_IF_CONFIG pic;
  2363. PIPRIP_IP_ADDRESS paddr;
  2364. CHAR szSource[32];
  2365. CHAR szNetmask[32];
  2366. CHAR szNexthop[32];
  2367. CHAR szNetwork[32];
  2368. BOOL bRouteExists, bRelRoute = FALSE;
  2369. RIP_IP_ROUTE route;
  2370. DWORD dwNetclassMask, dwNexthop, dwRipMetric;
  2371. DWORD dwErr, dwFlags, dwFound, dwNetwork, dwNetmask;
  2372. LPSTR lpszAddr;
  2373. RTM_NET_ADDRESS rna;
  2374. PRTM_ROUTE_INFO prri = NULL;
  2375. RTM_ROUTE_HANDLE hRtmRoute;
  2376. // TRACE0(ENTER, "entering ProcessResponseEntry");
  2377. pis = &pITE->ITE_Stats;
  2378. pic = pITE->ITE_Config;
  2379. paddr = IPRIP_IF_ADDRESS_TABLE(pITE->ITE_Binding) + dwAddrIndex;
  2380. //
  2381. // read destination and figure out subnet mask
  2382. // if mask is not given in the packet
  2383. //
  2384. dwNetwork = pIE->IE_Destination;
  2385. if (pIE->IE_SubnetMask == 0) {
  2386. dwNetmask = GuessSubnetMask(dwNetwork, &dwNetclassMask);
  2387. }
  2388. else {
  2389. //
  2390. // double-check the netclass mask, to accomodate supernets
  2391. //
  2392. dwNetmask = pIE->IE_SubnetMask;
  2393. dwNetclassMask = NETCLASS_MASK(dwNetwork);
  2394. if (dwNetclassMask > dwNetmask) {
  2395. dwNetclassMask = dwNetmask;
  2396. }
  2397. }
  2398. #if 1
  2399. dwNexthop = dwSource;
  2400. #else
  2401. // BUG 205349: using the nexthop field results in flapping
  2402. // when more than two routers are on the same network.
  2403. // The full fix is to distinguish between the source of the route
  2404. // and the nexthop of the route.
  2405. //
  2406. // read the next-hop field;
  2407. // if it is zero or it is not on the same subnet
  2408. // as the receiving interface, ignore it and use the address
  2409. // of the source as the next-hop.
  2410. // otherwise, use the address specified in the packet
  2411. // as the next-hop.
  2412. //
  2413. if (!pIE->IE_Nexthop ||
  2414. (pIE->IE_Nexthop & paddr->IA_Netmask) !=
  2415. (paddr->IA_Address & paddr->IA_Netmask)) { dwNexthop = dwSource; }
  2416. else { dwNexthop = pIE->IE_Nexthop; }
  2417. #endif
  2418. //
  2419. // set up variables used for error and information messages
  2420. //
  2421. lpszAddr = INET_NTOA(dwSource);
  2422. if (lpszAddr != NULL) { lstrcpy(szSource, lpszAddr);}
  2423. else { ZeroMemory(szSource, sizeof(szSource)); }
  2424. lpszAddr = INET_NTOA(dwNetwork);
  2425. if (lpszAddr != NULL) { lstrcpy(szNetwork, lpszAddr);}
  2426. else { ZeroMemory(szSource, sizeof(szSource)); }
  2427. lpszAddr = INET_NTOA(dwNetmask);
  2428. if (lpszAddr != NULL) { lstrcpy(szNetmask, lpszAddr);}
  2429. else { ZeroMemory(szSource, sizeof(szSource)); }
  2430. lpszAddr = INET_NTOA(dwNexthop);
  2431. if (lpszAddr != NULL) { lstrcpy(szNexthop, lpszAddr);}
  2432. else { ZeroMemory(szSource, sizeof(szSource)); }
  2433. if (pPS != NULL) {
  2434. InterlockedExchange(
  2435. &pPS->PS_LastPeerRouteTag, (DWORD)ntohs(pIE->IE_RouteTag)
  2436. );
  2437. }
  2438. do { // breakout loop
  2439. //
  2440. // make sure metric is in rational range
  2441. //
  2442. dwRipMetric = ntohl(pIE->IE_Metric);
  2443. if (dwRipMetric > IPRIP_INFINITE) {
  2444. TRACE4(
  2445. RESPONSE,
  2446. "metric == %d, ignoring route to %s via %s advertised by %s",
  2447. dwRipMetric, szNetwork, szNexthop, szSource
  2448. );
  2449. LOGWARN3(
  2450. ROUTE_METRIC_INVALID,szNetwork, szNexthop, szSource, dwRipMetric
  2451. );
  2452. break;
  2453. }
  2454. //
  2455. // make sure route is to valid address type
  2456. //
  2457. if (CLASSD_ADDR(dwNetwork) || CLASSE_ADDR(dwNetwork)) {
  2458. TRACE3(
  2459. RESPONSE,
  2460. "invalid class, ignoring route to %s via %s advertised by %s",
  2461. szNetwork, szNexthop, szSource
  2462. );
  2463. LOGINFO3(
  2464. ROUTE_CLASS_INVALID, szNetwork, szNexthop, szSource, NO_ERROR
  2465. );
  2466. break;
  2467. }
  2468. //
  2469. // make sure route is not to loopback address
  2470. //
  2471. if (IS_LOOPBACK_ADDR(dwNetwork)) {
  2472. TRACE3(
  2473. RESPONSE,
  2474. "ignoring loopback route to %s via %s advertised by %s",
  2475. szNetwork, szNexthop, szSource
  2476. );
  2477. LOGWARN3(
  2478. LOOPBACK_ROUTE_INVALID, szNetwork, szNexthop, szSource, NO_ERROR
  2479. );
  2480. break;
  2481. }
  2482. //
  2483. // make sure route it is not a broadcast route
  2484. // The first condition uses the netmask information received in the
  2485. // advertisement
  2486. // The second condition uses the netmask which is computed based
  2487. // on the address class
  2488. // The third condition checks for the all 1's broadcast
  2489. //
  2490. if ( IS_DIRECTED_BROADCAST_ADDR(dwNetwork, dwNetmask) ||
  2491. IS_DIRECTED_BROADCAST_ADDR(dwNetwork, dwNetclassMask) ||
  2492. IS_LOCAL_BROADCAST_ADDR(dwNetwork) ) {
  2493. TRACE3(
  2494. RESPONSE,
  2495. "ignoring broadcast route to %s via %s advertised by %s",
  2496. szNetwork, szNexthop, szSource
  2497. );
  2498. LOGWARN3(
  2499. BROADCAST_ROUTE_INVALID, szNetwork, szNexthop, szSource, 0
  2500. );
  2501. break;
  2502. }
  2503. //
  2504. // discard host routes if the receiving interface
  2505. // is not configured to accept host routes
  2506. //
  2507. //
  2508. // At this stage the broadcast routes have already been weeded out.
  2509. // So it is safe to assume that
  2510. // if Network address width is greater than the Netmask address
  2511. // width, then it is a host route.
  2512. // Or,
  2513. // if the dwNetmask is 255.255.255.255 then it is a host route.
  2514. //
  2515. if ( ((dwNetwork & ~dwNetmask) != 0) || (dwNetmask == HOSTADDR_MASK) ) {
  2516. //
  2517. // This is a host-route; see whether we can accept it.
  2518. //
  2519. if (IPRIP_FLAG_IS_ENABLED(pic, ACCEPT_HOST_ROUTES)) {
  2520. //
  2521. // The host route can be accepted.
  2522. // Set the mask to all-ones to ensure that
  2523. // the route can be added to the stack.
  2524. //
  2525. dwNetmask = HOSTADDR_MASK;
  2526. }
  2527. else {
  2528. //
  2529. // The host-route must be rejected.
  2530. //
  2531. TRACE3(
  2532. RESPONSE,
  2533. "ignoring host route to %s via %s advertised by %s",
  2534. szNetwork, szNexthop, szSource
  2535. );
  2536. LOGINFO3(
  2537. HOST_ROUTE_INVALID, szNetwork, szNexthop, szSource, NO_ERROR
  2538. );
  2539. break;
  2540. }
  2541. }
  2542. //
  2543. // discard default routes if the receiving interface
  2544. // is not configured to accept default routes
  2545. //
  2546. if (dwNetwork == 0 &&
  2547. IPRIP_FLAG_IS_DISABLED(pic, ACCEPT_DEFAULT_ROUTES)) {
  2548. TRACE3(
  2549. RESPONSE,
  2550. "ignoring default route to %s via %s advertised by %s",
  2551. szNetwork, szNexthop, szSource
  2552. );
  2553. LOGINFO3(
  2554. DEFAULT_ROUTE_INVALID, szNetwork, szNexthop, szSource, NO_ERROR
  2555. );
  2556. break;
  2557. }
  2558. //
  2559. // put the route through the accept filters
  2560. //
  2561. if (pic->IC_AcceptFilterMode != IPRIP_FILTER_DISABLED) {
  2562. //
  2563. // discard the route if the receiving interface is including
  2564. // all routes but this route is listed as an exception, or if
  2565. // the receiving interface is excluding all routes and this
  2566. // route is not listed as an exception
  2567. //
  2568. IS_ROUTE_IN_ACCEPT_FILTER(pic, dwNetwork, dwFound);
  2569. if ((pic->IC_AcceptFilterMode == IPRIP_FILTER_INCLUDE && !dwFound)||
  2570. (pic->IC_AcceptFilterMode == IPRIP_FILTER_EXCLUDE && dwFound)) {
  2571. TRACE3(
  2572. RESPONSE,
  2573. "ignoring filtered route to %s via %s advertised by %s",
  2574. szNetwork, szNexthop, szSource
  2575. );
  2576. LOGINFO3(
  2577. ROUTE_FILTERED, szNetwork, szNexthop, szSource, NO_ERROR
  2578. );
  2579. break;
  2580. }
  2581. }
  2582. //
  2583. // see if the route already exists in RTM's table
  2584. //
  2585. in.N_NetNumber = dwNetwork;
  2586. in.N_NetMask = dwNetmask;
  2587. RTM_IPV4_SET_ADDR_AND_MASK( &rna, dwNetwork, dwNetmask );
  2588. prri = RIP_ALLOC( RTM_SIZE_OF_ROUTE_INFO(
  2589. ig.IG_RtmProfile.MaxNextHopsInRoute
  2590. ) );
  2591. if ( prri == NULL ) {
  2592. dwErr = GetLastError();
  2593. TRACE2(
  2594. ANY, "ProcessResponseEntry: error %d while allocating %d bytes",
  2595. dwErr,
  2596. RTM_SIZE_OF_ROUTE_INFO(ig.IG_RtmProfile.MaxNextHopsInRoute)
  2597. );
  2598. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  2599. break;
  2600. }
  2601. prri-> RouteOwner = ig.IG_RtmHandle;
  2602. dwErr = RtmGetExactMatchRoute(
  2603. ig.IG_RtmHandle, &rna, RTM_MATCH_OWNER, prri, 0,
  2604. RTM_VIEW_MASK_ANY, &hRtmRoute
  2605. );
  2606. if ((dwErr != NO_ERROR) || (hRtmRoute == NULL)) {
  2607. bRouteExists = FALSE;
  2608. }
  2609. else{
  2610. bRelRoute = TRUE;
  2611. dwErr = GetRouteInfo(
  2612. hRtmRoute, prri, NULL, &route
  2613. );
  2614. if (dwErr != NO_ERROR) {
  2615. bRouteExists = FALSE;
  2616. break;
  2617. }
  2618. else {
  2619. bRouteExists = TRUE;
  2620. }
  2621. }
  2622. //
  2623. // add the cost of this interface to the metric
  2624. //
  2625. dwRipMetric = min(IPRIP_INFINITE, dwRipMetric + pic->IC_Metric);
  2626. if (dwRipMetric >= IPRIP_INFINITE && !bRouteExists) {
  2627. TRACE4(
  2628. RESPONSE,
  2629. "metric==%d, ignoring route to %s via %s advertised by %s",
  2630. IPRIP_INFINITE, szNetwork, szNexthop, szSource
  2631. );
  2632. break;
  2633. }
  2634. //
  2635. // ROUTE ADDITION/UPDATE/REMOVAL:
  2636. //
  2637. if (!bRouteExists) {
  2638. //
  2639. // NEW ROUTE:
  2640. //
  2641. // set up struct to pass to RTM
  2642. //
  2643. ZeroMemory(&route, sizeof(route));
  2644. route.RR_RoutingProtocol = PROTO_IP_RIP;
  2645. route.RR_Network = in;
  2646. SETROUTEMETRIC(&route, dwRipMetric);
  2647. route.RR_InterfaceID = pITE->ITE_Index;
  2648. route.RR_NextHopAddress.N_NetNumber = dwNexthop;
  2649. route.RR_NextHopAddress.N_NetMask = paddr->IA_Netmask;
  2650. SETROUTETAG(&route, ntohs(pIE->IE_RouteTag));
  2651. //
  2652. // add route to RTM
  2653. //
  2654. COMPUTE_ROUTE_METRIC(&route);
  2655. #if ROUTE_DBG
  2656. TRACE3(
  2657. RESPONSE,
  2658. "Adding route to %s via %s advertised by %s",
  2659. szNetwork, szNexthop, szSource
  2660. );
  2661. #endif
  2662. dwErr = AddRtmRoute(
  2663. ig.IG_RtmHandle, &route, NULL,
  2664. pic->IC_RouteExpirationInterval,
  2665. pic->IC_RouteRemovalInterval,
  2666. TRUE
  2667. );
  2668. if (dwErr != NO_ERROR) {
  2669. TRACE4(
  2670. RESPONSE,
  2671. "error %d adding route to %s via %s advertised by %s",
  2672. dwErr, szNetwork, szNexthop, szSource
  2673. );
  2674. LOGINFO3(
  2675. ADD_ROUTE_FAILED_2, szNetwork, szNexthop, szSource, dwErr
  2676. );
  2677. break;
  2678. }
  2679. InterlockedIncrement(&ig.IG_Stats.GS_SystemRouteChanges);
  2680. LOGINFO3(
  2681. NEW_ROUTE_LEARNT_1, szNetwork, szNexthop, szSource, NO_ERROR
  2682. );
  2683. }
  2684. else {
  2685. DWORD dwTimer = 0, dwChangeFlags = 0;
  2686. BOOL bTriggerUpdate = FALSE, bActive = TRUE;
  2687. //
  2688. // EXISTING ROUTE:
  2689. //
  2690. // reset time-to-live, and mark route as expiring,
  2691. // if this advertisement is from the same source
  2692. // as the existing route, and the existing route's metric
  2693. // is not already INFINITE; thus, if a route has been
  2694. // advertised as unreachable, we don't reset its time-to-live
  2695. // just because we hear an advertisement for the route
  2696. //
  2697. if (dwNexthop == route.RR_NextHopAddress.N_NetNumber &&
  2698. GETROUTEMETRIC(&route) != IPRIP_INFINITE) {
  2699. dwTimer = pic->IC_RouteExpirationInterval;
  2700. //
  2701. // if existing route was a summary route, make sure
  2702. // set the validity flag before you mark it as a
  2703. // non summary route. Fix for bug #81544
  2704. //
  2705. if ( GETROUTEFLAG( &route ) == ROUTEFLAG_SUMMARY ) {
  2706. CHAR szRouteNetwork[20], szRouteNetmask[20];
  2707. LPSTR lpszAddrTemp = INET_NTOA(route.RR_Network.N_NetNumber);
  2708. if (lpszAddrTemp != NULL) {
  2709. lstrcpy(szRouteNetwork, lpszAddrTemp);
  2710. lpszAddrTemp = INET_NTOA(route.RR_Network.N_NetMask);
  2711. if (lpszAddrTemp != NULL) {
  2712. lstrcpy(szRouteNetmask, lpszAddrTemp);
  2713. TRACE2(
  2714. RESPONSE,
  2715. "%s %s summary route to valid route",
  2716. szRouteNetwork, szRouteNetmask
  2717. );
  2718. }
  2719. }
  2720. SETROUTEFLAG( &route, ~ROUTEFLAG_SUMMARY );
  2721. }
  2722. }
  2723. //
  2724. // we only need to do further processing if
  2725. // (a) the advertised route is from the same source as
  2726. // the existing route and the metrics are different, or
  2727. // (b) the advertised route has a better metric
  2728. //
  2729. if ((dwNexthop == route.RR_NextHopAddress.N_NetNumber &&
  2730. dwRipMetric != GETROUTEMETRIC(&route)) ||
  2731. (dwRipMetric < GETROUTEMETRIC(&route))) {
  2732. //
  2733. // if the next-hop's differ, adopt the new next-hop
  2734. //
  2735. if (dwNexthop != route.RR_NextHopAddress.N_NetNumber) {
  2736. route.RR_NextHopAddress.N_NetNumber = dwNexthop;
  2737. route.RR_NextHopAddress.N_NetMask = paddr->IA_Netmask;
  2738. InterlockedIncrement(&ig.IG_Stats.GS_SystemRouteChanges);
  2739. LOGINFO2(
  2740. ROUTE_NEXTHOP_CHANGED, szNetwork, szNexthop, NO_ERROR
  2741. );
  2742. }
  2743. else {
  2744. CHAR szMetric[12];
  2745. wsprintf(szMetric, "%d", dwRipMetric);
  2746. LOGINFO3(
  2747. ROUTE_METRIC_CHANGED, szNetwork, szNexthop, szMetric, 0
  2748. );
  2749. }
  2750. //
  2751. // check the metric to decide the new time-to-live
  2752. //
  2753. if (dwRipMetric == IPRIP_INFINITE) {
  2754. //
  2755. // Delete the route
  2756. //
  2757. #if ROUTE_DBG
  2758. TRACE2(
  2759. ROUTE, "Deleting route to %s:%s", szNetwork, szNetmask
  2760. );
  2761. #endif
  2762. dwTimer = 0;
  2763. dwErr = RtmReferenceHandles(
  2764. ig.IG_RtmHandle, 1, &hRtmRoute
  2765. );
  2766. if (dwErr != NO_ERROR) {
  2767. TRACE3(
  2768. ANY, "error %d referencing route to %s:%s", dwErr,
  2769. szNetwork, szNetmask
  2770. );
  2771. break;
  2772. }
  2773. dwErr = RtmDeleteRouteToDest(
  2774. ig.IG_RtmHandle, hRtmRoute,
  2775. &dwChangeFlags
  2776. );
  2777. if (dwErr != NO_ERROR) {
  2778. TRACE3(
  2779. ANY, "error %d deleting route to %s:%s", dwErr,
  2780. szNetwork, szNetmask
  2781. );
  2782. }
  2783. break;
  2784. }
  2785. else {
  2786. //
  2787. // set the expiration flag and use the expiration TTL
  2788. //
  2789. dwTimer = pic->IC_RouteExpirationInterval;
  2790. }
  2791. //
  2792. // use the advertised metric, and set the interface ID,
  2793. // adapter index, and route tag
  2794. //
  2795. SETROUTEMETRIC(&route, dwRipMetric);
  2796. route.RR_InterfaceID = pITE->ITE_Index;
  2797. // route.RR_FamilySpecificData.FSD_AdapterIndex =
  2798. // pITE->ITE_Binding.AdapterIndex;
  2799. SETROUTETAG(&route, ntohs(pIE->IE_RouteTag));
  2800. //
  2801. // always require a triggered update if we reach here
  2802. //
  2803. bTriggerUpdate = TRUE;
  2804. }
  2805. if (dwTimer != 0) {
  2806. COMPUTE_ROUTE_METRIC(&route);
  2807. #if ROUTE_DBG
  2808. TRACE4(
  2809. RESPONSE,
  2810. "Editing route to %s via %s advertised by %s, metric %d",
  2811. szNetwork, szNexthop, szSource, dwRipMetric
  2812. );
  2813. #endif
  2814. dwErr = AddRtmRoute(
  2815. ig.IG_RtmHandle, &route, NULL, dwTimer,
  2816. pic-> IC_RouteRemovalInterval, TRUE
  2817. );
  2818. if (dwErr != NO_ERROR) {
  2819. TRACE4(
  2820. RESPONSE,
  2821. "error %d adding route to %s via %s advertised by %s",
  2822. dwErr, szNetwork, szNexthop, szSource
  2823. );
  2824. LOGINFO3(
  2825. ADD_ROUTE_FAILED_2,szNetwork,szNexthop,szSource, dwErr
  2826. );
  2827. }
  2828. }
  2829. }
  2830. } while(FALSE);
  2831. //
  2832. // if some sort of error occured, increment stats appropriately
  2833. //
  2834. if (dwErr != NO_ERROR ) {
  2835. InterlockedIncrement(&pis->IS_BadResponseEntriesReceived);
  2836. if (pPS != NULL) {
  2837. InterlockedIncrement(&pPS->PS_BadResponseEntriesFromPeer);
  2838. }
  2839. }
  2840. //
  2841. // Release the dest info structure
  2842. //
  2843. if (bRelRoute) {
  2844. dwErr = RtmReleaseRouteInfo(ig.IG_RtmHandle, prri);
  2845. if (dwErr != NO_ERROR) {
  2846. TRACE2(
  2847. ANY, "error %d releasing dest %s", dwErr, szNetwork
  2848. );
  2849. }
  2850. }
  2851. if ( prri ) {
  2852. RIP_FREE(prri);
  2853. }
  2854. //
  2855. // always return FALSE. This way no RIP route add/delete/operations
  2856. // will set of the triggered update mechanism. This mech. is set of
  2857. // by route change notifications recevied from RTMv2
  2858. //
  2859. return FALSE;
  2860. }
  2861. //----------------------------------------------------------------------------
  2862. // Function: WorkerFunctionStartFullUpdate
  2863. //
  2864. // this function initiates a full-update. It checks to see if a full-update
  2865. // is already pending, and if not, it sets the full-update-pending flag and
  2866. // schedules the full-update work item. Then it sets a flag on its interface
  2867. // indicating a full-update should be generated on the interface.
  2868. //----------------------------------------------------------------------------
  2869. VOID
  2870. WorkerFunctionStartFullUpdate(
  2871. PVOID pContext,
  2872. BOOLEAN bNotUsed
  2873. ) {
  2874. DWORD dwIndex;
  2875. PIF_TABLE pTable;
  2876. PIF_TABLE_ENTRY pite;
  2877. PIPRIP_IF_CONFIG pic;
  2878. if (!ENTER_RIP_API()) { return; }
  2879. TRACE0(ENTER, "entering WorkerFunctionStartFullUpdate");
  2880. pTable = ig.IG_IfTable;
  2881. ACQUIRE_IF_LOCK_SHARED();
  2882. EnterCriticalSection(&pTable->IT_CS);
  2883. do { // breakout loop
  2884. //
  2885. // retrieve the interface on which the full-update will be sent
  2886. //
  2887. dwIndex = PtrToUlong(pContext);
  2888. pite = GetIfByIndex(pTable, dwIndex);
  2889. if (pite == NULL) {
  2890. TRACE1(
  2891. SEND, "starting full-update: interface %d not found", dwIndex
  2892. );
  2893. break;
  2894. }
  2895. //
  2896. // if the interface is no longer active, do nothing
  2897. //
  2898. if (IF_IS_INACTIVE(pite)) {
  2899. pite->ITE_Flags &= ~ITEFLAG_FULL_UPDATE_INQUEUE;
  2900. break;
  2901. }
  2902. //
  2903. // do nothing if a full-update is already pending
  2904. //
  2905. if (IF_FULL_UPDATE_PENDING(pite)) { break; }
  2906. //
  2907. // only do full-updates on periodic-update interfaces
  2908. // and don't do full-updates on interfaces configured to be silent;
  2909. //
  2910. if (pite->ITE_Config->IC_UpdateMode != IPRIP_UPDATE_PERIODIC ||
  2911. pite->ITE_Config->IC_AnnounceMode == IPRIP_ANNOUNCE_DISABLED) {
  2912. pite->ITE_Flags &= ~ITEFLAG_FULL_UPDATE_INQUEUE;
  2913. break;
  2914. }
  2915. //
  2916. // set the full update flags on the interface;
  2917. //
  2918. pite->ITE_Flags |= ITEFLAG_FULL_UPDATE_PENDING;
  2919. //
  2920. // if there is no full-update pending,
  2921. // queue the full-update finishing function
  2922. //
  2923. if (!IPRIP_FULL_UPDATE_PENDING(pTable)) {
  2924. DWORD dwRand;
  2925. //
  2926. // set the global full-update-pending flag
  2927. //
  2928. pTable->IT_Flags |= IPRIP_FLAG_FULL_UPDATE_PENDING;
  2929. //
  2930. // we need a random interval between 1 and 5 seconds
  2931. //
  2932. dwRand = GetTickCount();
  2933. dwRand = RtlRandom(&dwRand);
  2934. dwRand = 1000 + (DWORD)((double)dwRand / MAXLONG * (4.0 * 1000));
  2935. //
  2936. // Schedule a full update
  2937. //
  2938. if (!ChangeTimerQueueTimer(
  2939. ig.IG_TimerQueueHandle, pTable->IT_FinishFullUpdateTimer,
  2940. dwRand, 10000000)) {
  2941. TRACE1(
  2942. SEND, "error %d setting finish full update timer",
  2943. GetLastError()
  2944. );
  2945. }
  2946. }
  2947. } while(FALSE);
  2948. LeaveCriticalSection(&pTable->IT_CS);
  2949. RELEASE_IF_LOCK_SHARED();
  2950. TRACE0(LEAVE, "leaving WorkerFunctionStartFullUpdate");
  2951. LEAVE_RIP_API();
  2952. }
  2953. //----------------------------------------------------------------------------
  2954. // Function: EnqueueStartFullUpdate
  2955. //
  2956. // This function is called to enqueue the next start-full-update event
  2957. // for the given interface. The interface's state is updated as necessary.
  2958. // It assumes that the following locks have been acquired:
  2959. // IT_RWL - shared
  2960. // IT_CS - exclusive
  2961. // TimerQueue lock - exclusive
  2962. //----------------------------------------------------------------------------
  2963. VOID
  2964. EnqueueStartFullUpdate(
  2965. PIF_TABLE_ENTRY pite,
  2966. LARGE_INTEGER qwLastFullUpdateTime
  2967. ) {
  2968. //
  2969. // set last-full-update time
  2970. //
  2971. if (!ChangeTimerQueueTimer(
  2972. ig.IG_TimerQueueHandle, pite->ITE_FullOrDemandUpdateTimer,
  2973. RipSecsToMilliSecs(pite->ITE_Config->IC_FullUpdateInterval),
  2974. 10000000
  2975. )) {
  2976. TRACE1(
  2977. SEND, "error %d updating start full update timer",
  2978. GetLastError()
  2979. );
  2980. pite->ITE_Flags &= ~ITEFLAG_FULL_UPDATE_INQUEUE;
  2981. }
  2982. }
  2983. //----------------------------------------------------------------------------
  2984. // Function: WorkerFunctionFinishFullUpdate
  2985. //
  2986. // This function sends a full-update on every interface which has the
  2987. // full-update pending flag set, and schedules the next full-update on each
  2988. // interface.
  2989. //----------------------------------------------------------------------------
  2990. VOID
  2991. WorkerFunctionFinishFullUpdate(
  2992. PVOID pContext,
  2993. BOOLEAN bNotUsed
  2994. ) {
  2995. PIF_TABLE pTable;
  2996. PIPRIP_IF_CONFIG pic;
  2997. PLIST_ENTRY ple, phead;
  2998. DWORD dwErr, dwIndex, dwIfCount;
  2999. LARGE_INTEGER qwCurrentTime;
  3000. PIF_TABLE_ENTRY pite, *ppite, *ppitend, *pIfList;
  3001. if (!ENTER_RIP_API()) { return; }
  3002. TRACE0(ENTER, "entering WorkerFunctionFinishFullUpdate");
  3003. pTable = ig.IG_IfTable;
  3004. ACQUIRE_IF_LOCK_SHARED();
  3005. EnterCriticalSection(&pTable->IT_CS);
  3006. pIfList = NULL;
  3007. ppite = NULL;
  3008. do {
  3009. //
  3010. // first count how many there are
  3011. //
  3012. dwIfCount = 0;
  3013. phead = &pTable->IT_ListByAddress;
  3014. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  3015. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  3016. if (IF_IS_ACTIVE(pite) && IF_FULL_UPDATE_PENDING(pite)) {
  3017. pic = pite->ITE_Config;
  3018. if (pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3019. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED) {
  3020. ++dwIfCount;
  3021. }
  3022. }
  3023. }
  3024. if (dwIfCount == 0) {
  3025. TRACE0(SEND, "finishing full-update: no interfaces");
  3026. break;
  3027. }
  3028. //
  3029. // then make memory for the interface pointers
  3030. //
  3031. pIfList = RIP_ALLOC(dwIfCount * sizeof(PIF_TABLE_ENTRY));
  3032. if (pIfList == NULL) {
  3033. dwErr = GetLastError();
  3034. TRACE2(
  3035. SEND, "error code %d allocating %d bytes for interface list",
  3036. dwErr, dwIfCount * sizeof(PIF_TABLE_ENTRY)
  3037. );
  3038. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  3039. //
  3040. // enqueue the next full-update for each interface
  3041. //
  3042. RipQuerySystemTime(&qwCurrentTime);
  3043. pTable->IT_LastUpdateTime = qwCurrentTime;
  3044. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  3045. pite=CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  3046. if (IF_IS_ACTIVE(pite) && IF_FULL_UPDATE_PENDING(pite)) {
  3047. pic = pite->ITE_Config;
  3048. if (pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3049. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED) {
  3050. EnqueueStartFullUpdate(pite, qwCurrentTime);
  3051. }
  3052. }
  3053. }
  3054. break;
  3055. }
  3056. //
  3057. // and copy the interface pointers to the memory allocated
  3058. //
  3059. ppitend = pIfList + dwIfCount;
  3060. for (ple = phead->Flink, ppite = pIfList;
  3061. ple != phead && ppite < ppitend; ple = ple->Flink) {
  3062. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  3063. if (IF_IS_ACTIVE(pite) && IF_FULL_UPDATE_PENDING(pite)) {
  3064. pic = pite->ITE_Config;
  3065. if (pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3066. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED) {
  3067. *ppite++ = pite;
  3068. }
  3069. }
  3070. }
  3071. //
  3072. // send the updates
  3073. //
  3074. TRACE1(SEND, "sending full-updates on %d interfaces", dwIfCount);
  3075. SendRoutes(pIfList, dwIfCount, SENDMODE_FULL_UPDATE, 0, 0);
  3076. //
  3077. // enqueue the next full-update for each interface
  3078. //
  3079. RipQuerySystemTime(&qwCurrentTime);
  3080. pTable->IT_LastUpdateTime = qwCurrentTime;
  3081. for (ppite = pIfList; ppite < ppitend; ppite++) {
  3082. EnqueueStartFullUpdate(*ppite, qwCurrentTime);
  3083. }
  3084. //
  3085. // free the memory allocated for the interface pointers
  3086. //
  3087. RIP_FREE(pIfList);
  3088. } while(FALSE);
  3089. //
  3090. // clear the full-update pending flags
  3091. //
  3092. phead = &pTable->IT_ListByAddress;
  3093. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  3094. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  3095. pite->ITE_Flags &= ~ITEFLAG_FULL_UPDATE_PENDING;
  3096. }
  3097. pTable->IT_Flags &= ~IPRIP_FLAG_FULL_UPDATE_PENDING;
  3098. LeaveCriticalSection(&pTable->IT_CS);
  3099. RELEASE_IF_LOCK_SHARED();
  3100. TRACE0(LEAVE, "leaving WorkerFunctionFinishFullUpdate");
  3101. LEAVE_RIP_API();
  3102. }
  3103. //----------------------------------------------------------------------------
  3104. // Function: FinishTriggeredUpdate
  3105. //
  3106. // This function is responsible for sending out a triggered update
  3107. // on all interfaces which have triggered updates enabled.
  3108. // No triggered updates are sent on interfaces which already have
  3109. // a full-update pending.
  3110. // Assumes interface table is locked for reading or writing,
  3111. // and update-lock (IT_CS) is held.
  3112. //----------------------------------------------------------------------------
  3113. VOID
  3114. FinishTriggeredUpdate(
  3115. ) {
  3116. PIF_TABLE pTable;
  3117. PIPRIP_IF_STATS pis;
  3118. DWORD dwErr, dwIfCount;
  3119. PIPRIP_IF_CONFIG pic = NULL;
  3120. PLIST_ENTRY ple, phead;
  3121. LARGE_INTEGER qwCurrentTime;
  3122. PIF_TABLE_ENTRY pite, *ppite, *ppitend, *pIfList;
  3123. pTable = ig.IG_IfTable;
  3124. //
  3125. // we lock the send queue now so that no routes are added
  3126. // until the existing ones are transmitted
  3127. //
  3128. ACQUIRE_LIST_LOCK(ig.IG_SendQueue);
  3129. do { // breakout loop
  3130. //
  3131. // count the interfaces on which the triggered update will be sent
  3132. //
  3133. dwIfCount = 0;
  3134. phead = &pTable->IT_ListByAddress;
  3135. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  3136. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  3137. pic = pite->ITE_Config;
  3138. if (IF_IS_ACTIVE(pite) && !IF_FULL_UPDATE_PENDING(pite) &&
  3139. pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3140. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED &&
  3141. IPRIP_FLAG_IS_ENABLED(pic, TRIGGERED_UPDATES)) {
  3142. ++dwIfCount;
  3143. }
  3144. }
  3145. if (dwIfCount == 0) {
  3146. TRACE0(SEND, "finishing triggered-update: no interfaces");
  3147. break;
  3148. }
  3149. //
  3150. // allocate memory to hold the interface pointers
  3151. //
  3152. pIfList = RIP_ALLOC(dwIfCount * sizeof(PIF_TABLE_ENTRY));
  3153. if (pIfList == NULL) {
  3154. dwErr = GetLastError();
  3155. TRACE2(
  3156. SEND, "error code %d allocating %d bytes for interface list",
  3157. dwErr, dwIfCount * sizeof(PIF_TABLE_ENTRY)
  3158. );
  3159. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  3160. break;
  3161. }
  3162. //
  3163. // copy the interface pointers to the allocated memory
  3164. //
  3165. ppitend = pIfList + dwIfCount;
  3166. for (ple = phead->Flink, ppite = pIfList;
  3167. ple != phead && ppite < ppitend; ple = ple->Flink) {
  3168. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  3169. pic = pite->ITE_Config;
  3170. if (IF_IS_ACTIVE(pite) && !IF_FULL_UPDATE_PENDING(pite) &&
  3171. pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3172. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED &&
  3173. IPRIP_FLAG_IS_ENABLED(pic, TRIGGERED_UPDATES)) {
  3174. *ppite++ = pite;
  3175. }
  3176. }
  3177. //
  3178. // send the triggered-update routes
  3179. //
  3180. TRACE1(SEND, "sending triggered-updates on %d interfaces", dwIfCount);
  3181. SendRoutes(pIfList, dwIfCount, SENDMODE_TRIGGERED_UPDATE, 0, 0);
  3182. //
  3183. // update the statistics for each interface
  3184. //
  3185. for (ppite = pIfList; ppite < ppitend; ppite++) {
  3186. pis = &(*ppite)->ITE_Stats;
  3187. InterlockedIncrement(&pis->IS_TriggeredUpdatesSent);
  3188. }
  3189. //
  3190. // update the last time at which an update was sent
  3191. //
  3192. RipQuerySystemTime(&pTable->IT_LastUpdateTime);
  3193. //
  3194. // free the memory allocated for the interfaces
  3195. //
  3196. RIP_FREE(pIfList);
  3197. } while (FALSE);
  3198. //
  3199. // make sure send-queue is empty
  3200. //
  3201. FlushSendQueue(ig.IG_SendQueue);
  3202. RELEASE_LIST_LOCK(ig.IG_SendQueue);
  3203. pTable->IT_Flags &= ~IPRIP_FLAG_TRIGGERED_UPDATE_PENDING;
  3204. return;
  3205. }
  3206. //----------------------------------------------------------------------------
  3207. // Function: WorkerFunctionStartTriggeredUpdate
  3208. //
  3209. // This function checks to see if the minimum interval between triggered
  3210. // updates has elapsed, and if so, sends a triggered update. Otherwise,
  3211. // it schedules the triggered update to be sent, and sets flags to indicate
  3212. // that a triggered update is pending
  3213. //----------------------------------------------------------------------------
  3214. VOID
  3215. WorkerFunctionStartTriggeredUpdate(
  3216. PVOID pContext
  3217. ) {
  3218. PIF_TABLE pTable;
  3219. LARGE_INTEGER qwCurrentTime, qwSoonestTriggerTime;
  3220. if (!ENTER_RIP_WORKER()) { return; }
  3221. TRACE0(ENTER, "entering WorkerFunctionStartTriggeredUpdate");
  3222. pTable = ig.IG_IfTable;
  3223. ACQUIRE_IF_LOCK_SHARED();
  3224. EnterCriticalSection(&pTable->IT_CS);
  3225. //
  3226. // if triggered update is not pending, queue a triggered update
  3227. //
  3228. if (!IPRIP_TRIGGERED_UPDATE_PENDING(pTable)) {
  3229. //
  3230. // figure out when is the soonest time a triggered update
  3231. // can be sent, based on the configured minimum interval
  3232. // between triggered updates (in seconds) and the last time
  3233. // a triggered update was generated (in 100-nanosecond units)
  3234. //
  3235. ACQUIRE_GLOBAL_LOCK_SHARED();
  3236. qwSoonestTriggerTime.HighPart = 0;
  3237. qwSoonestTriggerTime.LowPart =
  3238. ig.IG_Config->GC_MinTriggeredUpdateInterval;
  3239. RipSecsToSystemTime(&qwSoonestTriggerTime);
  3240. RELEASE_GLOBAL_LOCK_SHARED();
  3241. qwSoonestTriggerTime = RtlLargeIntegerAdd(
  3242. qwSoonestTriggerTime,
  3243. pTable->IT_LastUpdateTime
  3244. );
  3245. RipQuerySystemTime(&qwCurrentTime);
  3246. //
  3247. // figure out if clock has been set backward, by comparing
  3248. // the current time against the last update time
  3249. //
  3250. if (RtlLargeIntegerLessThan(
  3251. qwCurrentTime, pTable->IT_LastUpdateTime
  3252. )) {
  3253. //
  3254. // Send triggered update anyway, since there is no way
  3255. // to figure out the if minimum time between updates has
  3256. // elapsed
  3257. //
  3258. FinishTriggeredUpdate();
  3259. }
  3260. else if (RtlLargeIntegerLessThan(qwCurrentTime, qwSoonestTriggerTime)) {
  3261. //
  3262. // must defer the triggered update
  3263. //
  3264. qwSoonestTriggerTime = RtlLargeIntegerSubtract(
  3265. qwSoonestTriggerTime, qwCurrentTime
  3266. );
  3267. RipSystemTimeToMillisecs(&qwSoonestTriggerTime);
  3268. if (!ChangeTimerQueueTimer(
  3269. ig.IG_TimerQueueHandle,
  3270. pTable->IT_FinishTriggeredUpdateTimer,
  3271. qwSoonestTriggerTime.LowPart, 10000000
  3272. )) {
  3273. TRACE1(
  3274. SEND, "error %d updating finish update timer",
  3275. GetLastError()
  3276. );
  3277. }
  3278. else {
  3279. pTable->IT_Flags |= IPRIP_FLAG_TRIGGERED_UPDATE_PENDING;
  3280. }
  3281. }
  3282. else {
  3283. //
  3284. // the minimum time between triggered updates has elapsed,
  3285. // so send the triggered update now
  3286. //
  3287. FinishTriggeredUpdate();
  3288. }
  3289. }
  3290. LeaveCriticalSection(&pTable->IT_CS);
  3291. RELEASE_IF_LOCK_SHARED();
  3292. TRACE0(LEAVE, "leaving WorkerFunctionStartTriggeredUpdate");
  3293. LEAVE_RIP_WORKER();
  3294. }
  3295. //----------------------------------------------------------------------------
  3296. // Function: WorkerFunctionFinishTriggeredUpdate
  3297. //
  3298. // This function generates a triggered update on all interfaces which
  3299. // do not have triggered updates disabled.
  3300. //----------------------------------------------------------------------------
  3301. VOID
  3302. WorkerFunctionFinishTriggeredUpdate(
  3303. PVOID pContext,
  3304. BOOLEAN bNotUsed
  3305. ) {
  3306. PIF_TABLE pTable;
  3307. if (!ENTER_RIP_API()) { return; }
  3308. TRACE0(ENTER, "entering WorkerFunctionFinishTriggeredUpdate");
  3309. pTable = ig.IG_IfTable;
  3310. ACQUIRE_IF_LOCK_SHARED();
  3311. EnterCriticalSection(&pTable->IT_CS);
  3312. FinishTriggeredUpdate();
  3313. LeaveCriticalSection(&pTable->IT_CS);
  3314. RELEASE_IF_LOCK_SHARED();
  3315. TRACE0(LEAVE, "leaving WorkerFunctionFinishTriggeredUpdate");
  3316. LEAVE_RIP_API();
  3317. return;
  3318. }
  3319. //----------------------------------------------------------------------------
  3320. // Function: WorkerFunctionStartDemandUpdate
  3321. //
  3322. // This function initiates a demand-update on the speficied interface,
  3323. // sending a general request on the interface. It then schedules a work-item
  3324. // to report back to Router Manager when the update is done
  3325. //----------------------------------------------------------------------------
  3326. VOID
  3327. WorkerFunctionStartDemandUpdate(
  3328. PVOID pContext
  3329. ) {
  3330. PIF_TABLE pTable;
  3331. RIP_IP_ROUTE route;
  3332. PUPDATE_CONTEXT pwc;
  3333. PIF_TABLE_ENTRY pite;
  3334. DWORD dwErr, dwIndex;
  3335. if (!ENTER_RIP_WORKER()) { return; }
  3336. TRACE0(ENTER, "entering WorkerFunctionStartDemandUpdate");
  3337. pTable = ig.IG_IfTable;
  3338. ACQUIRE_IF_LOCK_SHARED();
  3339. do { // breakout loop
  3340. //
  3341. // retrieve the interface on which to perform the demand update
  3342. //
  3343. dwIndex = PtrToUlong(pContext);
  3344. pite = GetIfByIndex(pTable, dwIndex);
  3345. if (pite == NULL) {
  3346. TRACE1(SEND, "demand-update: interface %d not found", dwIndex);
  3347. break;
  3348. }
  3349. //
  3350. // make sure interface is active and has demand-updates enabled
  3351. //
  3352. if (IF_IS_INACTIVE(pite)) {
  3353. TRACE1(SEND, "demand-update: interface %d not active", dwIndex);
  3354. EnqueueDemandUpdateMessage(dwIndex, ERROR_CAN_NOT_COMPLETE);
  3355. break;
  3356. }
  3357. else
  3358. if (pite->ITE_Config->IC_UpdateMode != IPRIP_UPDATE_DEMAND) {
  3359. TRACE1(SEND, "demand-updates disabled on interface %d ", dwIndex);
  3360. EnqueueDemandUpdateMessage(dwIndex, ERROR_CAN_NOT_COMPLETE);
  3361. break;
  3362. }
  3363. //
  3364. // setup the update context
  3365. //
  3366. pwc = RIP_ALLOC(sizeof(UPDATE_CONTEXT));
  3367. if (pwc == NULL) {
  3368. dwErr = GetLastError();
  3369. TRACE2(
  3370. SEND, "error %d allocating %d bytes",
  3371. dwErr, sizeof(UPDATE_CONTEXT)
  3372. );
  3373. EnqueueDemandUpdateMessage(dwIndex, dwErr);
  3374. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  3375. break;
  3376. }
  3377. pwc->UC_InterfaceIndex = dwIndex;
  3378. pwc->UC_RetryCount = 1;
  3379. pwc->UC_RouteCount = 0;
  3380. //
  3381. // Create a timer for the demand update checks
  3382. //
  3383. if (!CreateTimerQueueTimer(
  3384. &pite->ITE_FullOrDemandUpdateTimer,
  3385. ig.IG_TimerQueueHandle,
  3386. WorkerFunctionFinishDemandUpdate, (PVOID)pwc,
  3387. 5000, 5000, 0
  3388. )) {
  3389. EnqueueDemandUpdateMessage(dwIndex, GetLastError());
  3390. }
  3391. //
  3392. // request routing tables from neighbors
  3393. //
  3394. SendGeneralRequest(pite);
  3395. } while (FALSE);
  3396. RELEASE_IF_LOCK_SHARED();
  3397. TRACE0(LEAVE, "leaving WorkerFunctionStartDemandUpdate");
  3398. LEAVE_RIP_WORKER();
  3399. }
  3400. //----------------------------------------------------------------------------
  3401. // Function: WorkerFunctionFinishDemandUpdate
  3402. //
  3403. // This function queues a message informing the Router Manager that
  3404. // the demand-update requested is complete
  3405. //----------------------------------------------------------------------------
  3406. VOID
  3407. WorkerFunctionFinishDemandUpdate(
  3408. PVOID pContext,
  3409. BOOLEAN bNotUsed
  3410. ) {
  3411. PIF_TABLE pTable;
  3412. PUPDATE_CONTEXT pwc;
  3413. PIF_TABLE_ENTRY pite;
  3414. DWORD dwErr, dwIndex, dwRouteCount;
  3415. if (pContext == NULL) { return; }
  3416. if (!ENTER_RIP_API()) { return; }
  3417. TRACE0(ENTER, "entering WorkerFunctionFinishDemandUpdate");
  3418. //
  3419. // get the update context
  3420. //
  3421. pwc = (PUPDATE_CONTEXT)pContext;
  3422. dwIndex = pwc->UC_InterfaceIndex;
  3423. pTable = ig.IG_IfTable;
  3424. ACQUIRE_IF_LOCK_SHARED();
  3425. do {
  3426. //
  3427. // retrieve the interface being updated
  3428. //
  3429. pite = GetIfByIndex(pTable, dwIndex);
  3430. if (pite == NULL) {
  3431. EnqueueDemandUpdateMessage(dwIndex, ERROR_CAN_NOT_COMPLETE);
  3432. break;
  3433. }
  3434. //
  3435. // report failure if the interface is no longer active
  3436. //
  3437. if (!IF_IS_ACTIVE(pite)) {
  3438. EnqueueDemandUpdateMessage(dwIndex, ERROR_CAN_NOT_COMPLETE);
  3439. break;
  3440. }
  3441. //
  3442. // get a count of the routes now on the interface
  3443. //
  3444. dwRouteCount = CountInterfaceRoutes(dwIndex);
  3445. //
  3446. // if there are still no routes, send another request
  3447. // unless we have sent the maximum number of requests
  3448. //
  3449. if (dwRouteCount == 0 && ++pwc->UC_RetryCount < MAX_UPDATE_REQUESTS) {
  3450. SendGeneralRequest(pite);
  3451. break;
  3452. }
  3453. //
  3454. // if the number of routes has not changed in the last 5 seconds,
  3455. // tell the router manager that the update is complete;
  3456. // otherwise, update the route count and enqueue another check
  3457. //
  3458. if (pwc->UC_RouteCount == dwRouteCount) {
  3459. EnqueueDemandUpdateMessage(dwIndex, NO_ERROR);
  3460. RIP_FREE(pwc);
  3461. if (!DeleteTimerQueueTimer(
  3462. ig.IG_TimerQueueHandle, pite->ITE_FullOrDemandUpdateTimer,
  3463. NULL)) {
  3464. TRACE1(
  3465. SEND, "error %d deleting demand update timer",
  3466. GetLastError()
  3467. );
  3468. }
  3469. pite->ITE_FullOrDemandUpdateTimer = NULL;
  3470. }
  3471. else {
  3472. pwc->UC_RouteCount = dwRouteCount;
  3473. }
  3474. } while(FALSE);
  3475. RELEASE_IF_LOCK_SHARED();
  3476. TRACE0(LEAVE, "leaving WorkerFunctionFinishDemandUpdate");
  3477. LEAVE_RIP_API();
  3478. }
  3479. //----------------------------------------------------------------------------
  3480. // Function: CountInterfaceRoutes
  3481. //
  3482. // Returns a count of the RIP routes associated with the specified interface
  3483. //----------------------------------------------------------------------------
  3484. DWORD
  3485. CountInterfaceRoutes(
  3486. DWORD dwInterfaceIndex
  3487. ) {
  3488. HANDLE hRouteEnum;
  3489. PHANDLE phRoutes = NULL;
  3490. DWORD dwHandles, dwFlags, i, dwErr, dwCount = 0;
  3491. dwErr = RtmCreateRouteEnum(
  3492. ig.IG_RtmHandle, NULL, RTM_VIEW_MASK_UCAST,
  3493. RTM_ENUM_OWN_ROUTES, NULL, RTM_MATCH_INTERFACE,
  3494. NULL, dwInterfaceIndex, &hRouteEnum
  3495. );
  3496. if (dwErr != NO_ERROR) {
  3497. TRACE1(
  3498. ANY, "CountInterfaceRoutes : error %d creating enum handle",
  3499. dwErr
  3500. );
  3501. return 0;
  3502. }
  3503. //
  3504. // allocate handle array large enough to hold max handles in an
  3505. // enum
  3506. //
  3507. phRoutes = RIP_ALLOC(ig.IG_RtmProfile.MaxHandlesInEnum * sizeof(HANDLE));
  3508. if ( phRoutes == NULL ) {
  3509. dwErr = GetLastError();
  3510. TRACE2(
  3511. ANY, "CountInterfaceRoutes: error %d while allocating %d bytes"
  3512. " to hold max handles in an enum",
  3513. dwErr, ig.IG_RtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  3514. );
  3515. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  3516. return 0;
  3517. }
  3518. do
  3519. {
  3520. dwHandles = ig.IG_RtmProfile.MaxHandlesInEnum;
  3521. dwErr = RtmGetEnumRoutes(
  3522. ig.IG_RtmHandle, hRouteEnum, &dwHandles, phRoutes
  3523. );
  3524. for ( i = 0; i < dwHandles; i++ )
  3525. {
  3526. //
  3527. // Release all route handles
  3528. //
  3529. dwErr = RtmReleaseRoutes(ig.IG_RtmHandle, 1, &phRoutes[i]);
  3530. if (dwErr != NO_ERROR) {
  3531. TRACE1(
  3532. ANY, "CountInterfaceRoutes : error %d releasing routes",
  3533. dwErr
  3534. );
  3535. }
  3536. }
  3537. dwCount += dwHandles;
  3538. } while (dwErr == NO_ERROR);
  3539. //
  3540. // close enum handle
  3541. //
  3542. dwErr = RtmDeleteEnumHandle(ig.IG_RtmHandle, hRouteEnum);
  3543. if (dwErr != NO_ERROR) {
  3544. TRACE1(
  3545. ANY, "CountInterfaceRoutes : error %d closing enum handle", dwErr
  3546. );
  3547. }
  3548. if ( phRoutes ) {
  3549. RIP_FREE(phRoutes);
  3550. }
  3551. return dwCount;
  3552. }
  3553. //----------------------------------------------------------------------------
  3554. // Function: EnqueueDemandUpdateMessage
  3555. //
  3556. // This function posts a message to IPRIP's Router Manager event queue
  3557. // indicating the status of a demand update request.
  3558. //----------------------------------------------------------------------------
  3559. VOID
  3560. EnqueueDemandUpdateMessage(
  3561. DWORD dwInterfaceIndex,
  3562. DWORD dwError
  3563. ) {
  3564. MESSAGE msg;
  3565. PUPDATE_COMPLETE_MESSAGE pmsg;
  3566. //
  3567. // set up an UPDATE_COMPLETE message
  3568. //
  3569. pmsg = &msg.UpdateCompleteMessage;
  3570. pmsg->UpdateType = RF_DEMAND_UPDATE_ROUTES;
  3571. pmsg->UpdateStatus = dwError;
  3572. pmsg->InterfaceIndex = dwInterfaceIndex;
  3573. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  3574. EnqueueEvent(ig.IG_EventQueue, UPDATE_COMPLETE, msg);
  3575. SetEvent(ig.IG_EventEvent);
  3576. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  3577. }
  3578. //----------------------------------------------------------------------------
  3579. // Function: WorkerFunctionProcessRtmMessage
  3580. //
  3581. // This function handles messages from RTM about new or expired routes.
  3582. //----------------------------------------------------------------------------
  3583. VOID
  3584. WorkerFunctionProcessRtmMessage(
  3585. PVOID pContext
  3586. ) {
  3587. DWORD dwErr, dwFlags, dwNumDests, dwSize;
  3588. PIF_TABLE pTable;
  3589. BOOL bTriggerUpdate, bDone = FALSE;
  3590. PIF_TABLE_ENTRY pite;
  3591. PIPRIP_IF_CONFIG pic;
  3592. RIP_IP_ROUTE route;
  3593. PRTM_DEST_INFO prdi;
  3594. CHAR szNetwork[32], szNexthop[32];
  3595. if (!ENTER_RIP_WORKER()) { return; }
  3596. TRACE0(ENTER, "entering WorkerFunctionProcessRtmMessage");
  3597. pTable = ig.IG_IfTable;
  3598. //
  3599. // allocate a buffer for retrieving the dest info
  3600. //
  3601. dwSize = RTM_SIZE_OF_DEST_INFO( ig.IG_RtmProfile.NumberOfViews );
  3602. prdi = (PRTM_DEST_INFO) RIP_ALLOC( dwSize );
  3603. if ( prdi == NULL ) {
  3604. dwErr = GetLastError();
  3605. TRACE2(
  3606. ROUTE, "error %d allocating %d bytes for dest info buffers",
  3607. dwErr, dwSize
  3608. );
  3609. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  3610. LEAVE_RIP_WORKER();
  3611. return;
  3612. }
  3613. //
  3614. // Acquire locks
  3615. //
  3616. ACQUIRE_IF_LOCK_SHARED();
  3617. ACQUIRE_GLOBAL_LOCK_SHARED();
  3618. ACQUIRE_LIST_LOCK(ig.IG_SendQueue);
  3619. bTriggerUpdate = FALSE;
  3620. //
  3621. // loop dequeueing messages until RTM says there are no more left
  3622. //
  3623. while (!bDone) {
  3624. //
  3625. // Retrieve route changes
  3626. //
  3627. dwNumDests = 1;
  3628. dwErr = RtmGetChangedDests(
  3629. ig.IG_RtmHandle, ig.IG_RtmNotifHandle, &dwNumDests, prdi
  3630. );
  3631. if ((dwErr != NO_ERROR) && (dwErr != ERROR_NO_MORE_ITEMS)) {
  3632. TRACE1(ROUTE, "error %d retrieving changed dests", dwErr);
  3633. break;
  3634. }
  3635. //
  3636. // check if there are any more changed dests
  3637. //
  3638. if (dwErr == ERROR_NO_MORE_ITEMS) { bDone = TRUE; }
  3639. if (dwNumDests < 1) { break; }
  3640. if ((prdi-> ViewInfo[0].HoldRoute != NULL) ||
  3641. (prdi-> ViewInfo[0].Route != NULL)) {
  3642. ZeroMemory(&route, sizeof(RIP_IP_ROUTE));
  3643. //
  3644. // For each route change check if you have a held down route.
  3645. // if so get the info for the held down route since that is
  3646. // the one to be advertized.
  3647. //
  3648. // N.B. RIP summary routes are not advertized via the route
  3649. // change processing mechanism.
  3650. //
  3651. dwErr = GetRouteInfo(
  3652. (prdi-> ViewInfo[0].HoldRoute != NULL) ?
  3653. prdi-> ViewInfo[0].HoldRoute : prdi-> ViewInfo[0].Route,
  3654. NULL, prdi, &route
  3655. );
  3656. if (dwErr == NO_ERROR) {
  3657. //
  3658. // do not advertize RIP summary routes
  3659. //
  3660. if ((route.RR_RoutingProtocol != PROTO_IP_RIP) ||
  3661. (GETROUTEFLAG(&route) & ROUTEFLAG_SUMMARY) !=
  3662. ROUTEFLAG_SUMMARY) {
  3663. //
  3664. // held down routes are advertized with INFINITE metric
  3665. //
  3666. if (prdi-> ViewInfo[0].HoldRoute != NULL) {
  3667. SETROUTEMETRIC(&route, IPRIP_INFINITE);
  3668. }
  3669. EnqueueSendEntry( ig.IG_SendQueue, &route );
  3670. bTriggerUpdate = TRUE;
  3671. }
  3672. #if ROUTE_DBG
  3673. else if (route.RR_RoutingProtocol == PROTO_IP_RIP) {
  3674. TRACE0(ROUTE, "Ignoring route change caused by RIP summary route");
  3675. }
  3676. #endif
  3677. }
  3678. }
  3679. //
  3680. // release the destination info
  3681. //
  3682. dwErr = RtmReleaseChangedDests(
  3683. ig.IG_RtmHandle, ig.IG_RtmNotifHandle, 1, prdi
  3684. );
  3685. if (dwErr != NO_ERROR) {
  3686. TRACE1(ANY, "error %d releasing changed dests", dwErr);
  3687. }
  3688. }
  3689. if (prdi) { RIP_FREE(prdi); }
  3690. //
  3691. // queue a triggered update now if necessary
  3692. //
  3693. if (bTriggerUpdate) {
  3694. QueueRipWorker(WorkerFunctionStartTriggeredUpdate, NULL);
  3695. }
  3696. RELEASE_LIST_LOCK(ig.IG_SendQueue);
  3697. RELEASE_GLOBAL_LOCK_SHARED();
  3698. RELEASE_IF_LOCK_SHARED();
  3699. TRACE0(LEAVE, "leaving WorkerFunctionProcessRtmMessage");
  3700. LEAVE_RIP_WORKER();
  3701. }
  3702. //----------------------------------------------------------------------------
  3703. // Function: WorkerFunctionActivateInterface
  3704. //
  3705. // This function sends out the initial general request on an interface.
  3706. //----------------------------------------------------------------------------
  3707. VOID
  3708. WorkerFunctionActivateInterface(
  3709. PVOID pContext
  3710. ) {
  3711. PIF_TABLE pTable;
  3712. UPDATE_BUFFER ub;
  3713. PIPRIP_ENTRY pEntry;
  3714. PIF_TABLE_ENTRY pite;
  3715. PIPRIP_IF_CONFIG pic;
  3716. PIPRIP_IF_BINDING pib;
  3717. PIPRIP_IP_ADDRESS paddr;
  3718. SOCKADDR_IN sinDest;
  3719. DWORD i, dwErr, dwIndex;
  3720. LARGE_INTEGER qwCurrentTime;
  3721. if (!ENTER_RIP_WORKER()) { return; }
  3722. TRACE0(ENTER, "entering WorkerFunctionActivateInterface");
  3723. pTable = ig.IG_IfTable;
  3724. ACQUIRE_IF_LOCK_SHARED();
  3725. do { // breakout loop
  3726. //
  3727. // retrieve the interface to be activated
  3728. //
  3729. dwIndex = PtrToUlong(pContext);
  3730. pite = GetIfByIndex(pTable, dwIndex);
  3731. if (pite == NULL) {
  3732. TRACE1(IF, "activating interface: interface %d not found", dwIndex);
  3733. break;
  3734. }
  3735. pic = pite->ITE_Config;
  3736. pib = pite->ITE_Binding;
  3737. //
  3738. // If binding is NULL, assume that interface has been
  3739. // deativated. This check has been introduced as a consequence
  3740. // of WorkerFunctionDeactivateInterface being made synchronous.
  3741. // As a result, by the time this function is invoked an interface
  3742. // that was in the process of being activated could have been
  3743. // deactivated.
  3744. //
  3745. // The change to synchronous deactivate was made
  3746. // to accomadate demand dial interfaces that could get connected
  3747. // and disconnected immeditately, causing the above behaviour
  3748. //
  3749. if ( pib == NULL ) {
  3750. TRACE1( IF, "activating interface %d: Binding not found", dwIndex );
  3751. break;
  3752. }
  3753. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  3754. //
  3755. // request input notification on the interface's sockets
  3756. //
  3757. if (pic->IC_AcceptMode != IPRIP_ACCEPT_DISABLED) {
  3758. for (i = 0; i < pib->IB_AddrCount; i++) {
  3759. dwErr = WSAEventSelect(
  3760. pite->ITE_Sockets[i], ig.IG_IpripInputEvent,
  3761. FD_READ
  3762. );
  3763. if (dwErr != NO_ERROR) {
  3764. LPSTR lpszAddr = INET_NTOA(paddr[i].IA_Address);
  3765. if (lpszAddr != NULL) {
  3766. TRACE3(
  3767. IF, "WSAEventSelect returned %d for interface %d (%s)",
  3768. dwErr, dwIndex, lpszAddr
  3769. );
  3770. LOGERR1(EVENTSELECT_FAILED, lpszAddr, 0);
  3771. }
  3772. }
  3773. }
  3774. }
  3775. //
  3776. // if interface is silent or interface does demand-udpates,
  3777. // no initial request is sent on it
  3778. //
  3779. if (pic->IC_UpdateMode != IPRIP_UPDATE_PERIODIC ||
  3780. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_DISABLED) {
  3781. //
  3782. // configured to be silent, do nothing
  3783. //
  3784. break;
  3785. }
  3786. //
  3787. // send general request to neighboring routers
  3788. //
  3789. SendGeneralRequest(pite);
  3790. //
  3791. // create timer for periodic updates, if required.
  3792. //
  3793. EnterCriticalSection(&pTable->IT_CS);
  3794. if (pite->ITE_FullOrDemandUpdateTimer == NULL) {
  3795. if (!CreateTimerQueueTimer(
  3796. &pite->ITE_FullOrDemandUpdateTimer,
  3797. ig.IG_TimerQueueHandle,
  3798. WorkerFunctionStartFullUpdate, pContext,
  3799. RipSecsToMilliSecs(pic->IC_FullUpdateInterval),
  3800. 10000000, 0
  3801. )) {
  3802. dwErr = GetLastError();
  3803. TRACE1(IF, "error %d returned by CreateTimerQueueTimer", dwErr);
  3804. break;
  3805. }
  3806. else {
  3807. pite->ITE_Flags |= ITEFLAG_FULL_UPDATE_INQUEUE;
  3808. }
  3809. }
  3810. else {
  3811. RipQuerySystemTime(&qwCurrentTime);
  3812. EnqueueStartFullUpdate(pite, qwCurrentTime);
  3813. }
  3814. LeaveCriticalSection(&pTable->IT_CS);
  3815. } while(FALSE);
  3816. RELEASE_IF_LOCK_SHARED();
  3817. TRACE0(LEAVE, "leaving WorkerFunctionActivateInterface");
  3818. LEAVE_RIP_WORKER();
  3819. }
  3820. //----------------------------------------------------------------------------
  3821. // Function: WorkerFunctionDeactivateInterface
  3822. //
  3823. // This function generates shutdown update on the given interface, and
  3824. // removes from RTM all RIP-learnt routes associated with the interface.
  3825. // Assumes the interface table has already been exclusively locked
  3826. //----------------------------------------------------------------------------
  3827. VOID
  3828. WorkerFunctionDeactivateInterface(
  3829. PVOID pContext
  3830. ) {
  3831. UPDATE_BUFFER ub;
  3832. PIF_TABLE pTable;
  3833. RIP_IP_ROUTE route;
  3834. HANDLE hEnumerator;
  3835. PHANDLE phRoutes = NULL;
  3836. BOOL bTriggerUpdate;
  3837. PIF_TABLE_ENTRY pite;
  3838. PIPRIP_IF_CONFIG pic;
  3839. PIPRIP_IF_BINDING pib;
  3840. PIPRIP_IP_ADDRESS paddr;
  3841. DWORD i, dwErr, dwFlags, dwIndex, dwHandles;
  3842. TRACE0(ENTER, "entering WorkerFunctionDeactivateInterface");
  3843. dwIndex = PtrToUlong(pContext);
  3844. bTriggerUpdate = FALSE;
  3845. pTable = ig.IG_IfTable;
  3846. do { // breakout loop
  3847. //
  3848. // find the interface to be deactivated
  3849. //
  3850. pite = GetIfByIndex(pTable, dwIndex);
  3851. if (pite == NULL) {
  3852. TRACE1(
  3853. IF, "de-activating interface: interface %d not found", dwIndex
  3854. );
  3855. break;
  3856. }
  3857. pib = pite->ITE_Binding;
  3858. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  3859. //
  3860. // if graceful shutdown is on and demand-update is off,
  3861. // send the graceful-shutdown update
  3862. //
  3863. if (pite->ITE_Config->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3864. IPRIP_FLAG_IS_ENABLED(pite->ITE_Config, GRACEFUL_SHUTDOWN)) {
  3865. //
  3866. // transmit all RTM routes with non-infinite metrics set to 15
  3867. //
  3868. if (pite->ITE_Config->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED) {
  3869. SendRoutes(&pite, 1, SENDMODE_SHUTDOWN_UPDATE, 0, 0);
  3870. }
  3871. }
  3872. //
  3873. // this function is called either because an interface
  3874. // that was active (bound and enabled) is either no longer enabled
  3875. // or is no longer bound. We complete the deactivation differently
  3876. // depending on which of these is the case
  3877. //
  3878. if (!IF_IS_BOUND(pite) ) {
  3879. //
  3880. // the interface was bound, but isn't anymore.
  3881. // close the socket for the interface
  3882. //
  3883. DeleteIfSocket(pite);
  3884. ACQUIRE_BINDING_LOCK_EXCLUSIVE();
  3885. dwErr = DeleteBindingEntry(ig.IG_BindingTable, pite->ITE_Binding);
  3886. RELEASE_BINDING_LOCK_EXCLUSIVE();
  3887. RIP_FREE(pite->ITE_Binding);
  3888. pite->ITE_Binding = NULL;
  3889. }
  3890. else {
  3891. //
  3892. // the interface was enabled, but isn't anymore.
  3893. // tell WinSock to stop notifying us of input
  3894. //
  3895. for (i = 0; i < pib->IB_AddrCount; i++) {
  3896. WSAEventSelect(pite->ITE_Sockets[i], ig.IG_IpripInputEvent, 0);
  3897. }
  3898. }
  3899. //
  3900. // if full updates pending/queued on this interface, cancel them.
  3901. //
  3902. pite-> ITE_Flags &= ~ITEFLAG_FULL_UPDATE_PENDING;
  3903. pite-> ITE_Flags &= ~ITEFLAG_FULL_UPDATE_INQUEUE;
  3904. //
  3905. // if we're announcing routes over this interface,
  3906. // delete the periodic announcement timer
  3907. //
  3908. if (pite->ITE_Config->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  3909. pite->ITE_Config->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED) {
  3910. if (!DeleteTimerQueueTimer(
  3911. ig.IG_TimerQueueHandle,
  3912. pite->ITE_FullOrDemandUpdateTimer,
  3913. NULL)) {
  3914. TRACE1(
  3915. ANY, "error %d deleting update timer", GetLastError()
  3916. );
  3917. }
  3918. pite->ITE_FullOrDemandUpdateTimer = NULL;
  3919. }
  3920. //
  3921. // we're done if graceful shutdown is disabled
  3922. // or if this is a demand-update interface
  3923. //
  3924. if (pite->ITE_Config->IC_UpdateMode != IPRIP_UPDATE_PERIODIC ||
  3925. IPRIP_FLAG_IS_DISABLED(pite->ITE_Config, GRACEFUL_SHUTDOWN)) {
  3926. break;
  3927. }
  3928. //
  3929. // move the routes learnt on this interface to the send-queue
  3930. // and set their metrics to 16
  3931. //
  3932. dwErr = RtmCreateRouteEnum(
  3933. ig.IG_RtmHandle, NULL, RTM_VIEW_MASK_ANY,
  3934. RTM_ENUM_OWN_ROUTES, NULL, RTM_MATCH_INTERFACE, NULL,
  3935. pite->ITE_Index, &hEnumerator
  3936. );
  3937. if (dwErr != NO_ERROR) {
  3938. TRACE1(
  3939. ANY, "WorkerFunctionDeactivateInterface: error %d creating"
  3940. " enum handle", dwErr
  3941. );
  3942. break;
  3943. }
  3944. //
  3945. // allocate handle array large enough to hold max handles in an
  3946. // enum
  3947. //
  3948. phRoutes = RIP_ALLOC(ig.IG_RtmProfile.MaxHandlesInEnum*sizeof(HANDLE));
  3949. if ( phRoutes == NULL ) {
  3950. dwErr = GetLastError();
  3951. TRACE2(
  3952. ANY, "WorkerFunctionDeactivateInterface: error %d "
  3953. "while allocating %d bytes to hold max handles in an enum",
  3954. dwErr, ig.IG_RtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  3955. );
  3956. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  3957. break;
  3958. }
  3959. //
  3960. // find all RIP routes learnt on this interface
  3961. //
  3962. ACQUIRE_GLOBAL_LOCK_SHARED();
  3963. ACQUIRE_LIST_LOCK(ig.IG_SendQueue);
  3964. do {
  3965. dwHandles = ig.IG_RtmProfile.MaxHandlesInEnum;
  3966. dwErr = RtmGetEnumRoutes(
  3967. ig.IG_RtmHandle, hEnumerator, &dwHandles, phRoutes
  3968. );
  3969. for ( i = 0; i < dwHandles; i++ ) {
  3970. if (GetRouteInfo(
  3971. phRoutes[i], NULL, NULL, &route
  3972. ) == NO_ERROR) {
  3973. //
  3974. // set the route's metric to infinite
  3975. //
  3976. SETROUTEMETRIC(&route, IPRIP_INFINITE);
  3977. //
  3978. // add the route to the send-queue
  3979. //
  3980. EnqueueSendEntry(ig.IG_SendQueue, &route);
  3981. bTriggerUpdate = TRUE;
  3982. }
  3983. if (RtmDeleteRouteToDest(
  3984. ig.IG_RtmHandle, phRoutes[i], &dwFlags
  3985. ) != NO_ERROR) {
  3986. //
  3987. // If delete is successful, this is automatic
  3988. //
  3989. if (RtmReleaseRoutes(
  3990. ig.IG_RtmHandle, 1, &phRoutes[i]
  3991. ) != NO_ERROR) {
  3992. TRACE1(
  3993. ANY, "WorkerFunctionDeactivateInterface: "
  3994. "error %d releasing route handles", dwErr
  3995. );
  3996. }
  3997. }
  3998. }
  3999. } while ( dwErr == NO_ERROR );
  4000. //
  4001. // close the enm handle
  4002. //
  4003. dwErr = RtmDeleteEnumHandle(ig.IG_RtmHandle, hEnumerator);
  4004. if (dwErr != NO_ERROR) {
  4005. TRACE1(
  4006. ANY, "WorkerFunctionDeactivateInterface: error %d "
  4007. "closing enum handle", dwErr
  4008. );
  4009. }
  4010. RELEASE_LIST_LOCK(ig.IG_SendQueue);
  4011. RELEASE_GLOBAL_LOCK_SHARED();
  4012. //
  4013. // queue a triggered-update work-item for the other active interfaces
  4014. //
  4015. if (bTriggerUpdate) {
  4016. dwErr = QueueRipWorker(WorkerFunctionStartTriggeredUpdate, NULL);
  4017. if (dwErr != NO_ERROR) {
  4018. TRACE1(
  4019. IF, "error %d queueing triggered update work-item", dwErr
  4020. );
  4021. LOGERR0(QUEUE_WORKER_FAILED, dwErr);
  4022. }
  4023. }
  4024. } while(FALSE);
  4025. if ( phRoutes ) {
  4026. RIP_FREE(phRoutes);
  4027. }
  4028. TRACE0(LEAVE, "leaving WorkerFunctionDeactivateInterface");
  4029. }
  4030. //----------------------------------------------------------------------------
  4031. // Function: WorkerFunctionFinishStopProtocol
  4032. //
  4033. // This function is called when IPRIP is stopping; it sends out shutdown
  4034. // updates on all interfaces and removes all RIP routes from RTM
  4035. //----------------------------------------------------------------------------
  4036. VOID
  4037. WorkerFunctionFinishStopProtocol(
  4038. PVOID pContext
  4039. ) {
  4040. MESSAGE msg = {0, 0, 0};
  4041. LONG lThreadCount;
  4042. PIF_TABLE pTable;
  4043. PIPRIP_IF_CONFIG pic;
  4044. PLIST_ENTRY ple, phead;
  4045. DWORD dwErr, dwIfCount;
  4046. PIF_TABLE_ENTRY pite, *ppite, *ppitend, *pIfList;
  4047. HANDLE WaitHandle;
  4048. TRACE0(ENTER, "entering WorkerFunctionFinishStopProtocol");
  4049. //
  4050. // NOTE: since this is called while the router is stopping,
  4051. // there is no need for it to use ENTER_RIP_WORKER()/LEAVE_RIP_WORKER()
  4052. //
  4053. lThreadCount = PtrToUlong(pContext);
  4054. //
  4055. // waits for input thread and timer thread to stop,
  4056. // and also waits for API callers and worker functions to finish
  4057. //
  4058. while (lThreadCount-- > 0) {
  4059. WaitForSingleObject(ig.IG_ActivitySemaphore, INFINITE);
  4060. }
  4061. //
  4062. // deregister the events set with NtdllWait thread and delete the
  4063. // timer queue registered with NtdllTimer thread.
  4064. // These calls should not be inside IG_CS lock and must be done
  4065. // after all the threads have stopped.
  4066. //
  4067. WaitHandle = InterlockedExchangePointer(&ig.IG_IpripInputEventHandle, NULL) ;
  4068. if (WaitHandle) {
  4069. UnregisterWaitEx( WaitHandle, INVALID_HANDLE_VALUE ) ;
  4070. }
  4071. if (ig.IG_TimerQueueHandle) {
  4072. DeleteTimerQueueEx(ig.IG_TimerQueueHandle, INVALID_HANDLE_VALUE);
  4073. }
  4074. //
  4075. // we enter the critical section and leave, just to be sure that
  4076. // all threads have quit their calls to LeaveRipWorker()
  4077. //
  4078. EnterCriticalSection(&ig.IG_CS);
  4079. LeaveCriticalSection(&ig.IG_CS);
  4080. TRACE0(STOP, "all threads stopped, now performing graceful shutdown");
  4081. pTable = ig.IG_IfTable;
  4082. ACQUIRE_IF_LOCK_EXCLUSIVE();
  4083. //
  4084. // send out graceful shutdown updates on all active interfaces
  4085. //
  4086. do {
  4087. phead = &pTable->IT_ListByAddress;
  4088. //
  4089. // first count the interfaces on which graceful shutdown is enabled
  4090. //
  4091. dwIfCount = 0;
  4092. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  4093. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  4094. pic = pite->ITE_Config;
  4095. if (IF_IS_ACTIVE(pite) &&
  4096. pite->ITE_Binding &&
  4097. pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  4098. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED &&
  4099. IPRIP_FLAG_IS_ENABLED(pic, GRACEFUL_SHUTDOWN)) {
  4100. ++dwIfCount;
  4101. }
  4102. }
  4103. if (dwIfCount == 0) { break; }
  4104. //
  4105. // allocate space for the interface pointers
  4106. //
  4107. pIfList = RIP_ALLOC(dwIfCount * sizeof(PIF_TABLE_ENTRY));
  4108. if (pIfList == NULL) {
  4109. dwErr = GetLastError();
  4110. TRACE2(
  4111. STOP, "shutdown: error %d allocating %d bytes for interfaces",
  4112. dwErr, dwIfCount * sizeof(PIF_TABLE_ENTRY)
  4113. );
  4114. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  4115. break;
  4116. }
  4117. //
  4118. // copy the interface pointers into the space allocated
  4119. //
  4120. ppitend = pIfList + dwIfCount;
  4121. for (ple = phead->Flink, ppite = pIfList;
  4122. ple != phead && ppite < ppitend; ple = ple->Flink) {
  4123. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  4124. pic = pite->ITE_Config;
  4125. if (IF_IS_ACTIVE(pite) &&
  4126. pite->ITE_Binding &&
  4127. pic->IC_UpdateMode == IPRIP_UPDATE_PERIODIC &&
  4128. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED &&
  4129. IPRIP_FLAG_IS_ENABLED(pic, GRACEFUL_SHUTDOWN)) {
  4130. *ppite++ = pite;
  4131. }
  4132. }
  4133. //
  4134. // pass the array of interfaces to SendRoutes
  4135. //
  4136. TRACE1(STOP, "sending shutdown updates on %d interfaces", dwIfCount);
  4137. SendRoutes(pIfList, dwIfCount, SENDMODE_SHUTDOWN_UPDATE, 0, 0);
  4138. //
  4139. // free the array of interfaces
  4140. //
  4141. RIP_FREE(pIfList);
  4142. } while(FALSE);
  4143. RELEASE_IF_LOCK_EXCLUSIVE();
  4144. //
  4145. // delete all IPRIP routes from RTM
  4146. //
  4147. for (ple = phead->Flink; ple != phead; ple = ple->Flink)
  4148. {
  4149. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  4150. BlockDeleteRoutesOnInterface(
  4151. ig.IG_RtmHandle, pite-> ITE_Index
  4152. );
  4153. }
  4154. //
  4155. // cleanup the global structures
  4156. //
  4157. TRACE0(STOP, "IPRIP is cleaning up resources");
  4158. ProtocolCleanup(TRUE);
  4159. LOGINFO0(IPRIP_STOPPED, NO_ERROR);
  4160. //
  4161. // let the Router Manager know that we are done
  4162. //
  4163. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  4164. EnqueueEvent(ig.IG_EventQueue, ROUTER_STOPPED, msg);
  4165. SetEvent(ig.IG_EventEvent);
  4166. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  4167. return;
  4168. }
  4169. VOID
  4170. PrintGlobalStats(
  4171. HANDLE hConsole,
  4172. PCOORD pc,
  4173. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4174. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4175. );
  4176. VOID
  4177. PrintGlobalConfig(
  4178. HANDLE hConsole,
  4179. PCOORD pc,
  4180. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4181. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4182. );
  4183. VOID
  4184. PrintIfStats(
  4185. HANDLE hConsole,
  4186. PCOORD pc,
  4187. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4188. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4189. );
  4190. VOID
  4191. PrintIfConfig(
  4192. HANDLE hConsole,
  4193. PCOORD pc,
  4194. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4195. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4196. );
  4197. VOID
  4198. PrintIfBinding(
  4199. HANDLE hConsole,
  4200. PCOORD pc,
  4201. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4202. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4203. );
  4204. VOID
  4205. PrintPeerStats(
  4206. HANDLE hConsole,
  4207. PCOORD pc,
  4208. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4209. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4210. );
  4211. #define ClearScreen(h) { \
  4212. DWORD _dwin,_dwout; \
  4213. COORD _c = {0, 0}; \
  4214. CONSOLE_SCREEN_BUFFER_INFO _csbi; \
  4215. GetConsoleScreenBufferInfo(h,&_csbi); \
  4216. _dwin = _csbi.dwSize.X * _csbi.dwSize.Y; \
  4217. FillConsoleOutputCharacter(h,' ',_dwin,_c,&_dwout); \
  4218. }
  4219. VOID
  4220. WorkerFunctionMibDisplay(
  4221. PVOID pContext,
  4222. BOOLEAN bNotUsed
  4223. ) {
  4224. COORD c;
  4225. HANDLE hConsole = NULL;
  4226. DWORD dwErr, dwTraceID;
  4227. DWORD dwExactSize, dwInSize, dwOutSize;
  4228. IPRIP_MIB_GET_INPUT_DATA imgid;
  4229. PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
  4230. LARGE_INTEGER qwNextDisplay, qwCurrentTime;
  4231. if (!ENTER_RIP_API()) { return; }
  4232. TraceGetConsole(ig.IG_MibTraceID, &hConsole);
  4233. if (hConsole == NULL) {
  4234. LEAVE_RIP_WORKER();
  4235. return;
  4236. }
  4237. ClearScreen(hConsole);
  4238. c.X = c.Y = 0;
  4239. dwInSize = sizeof(imgid);
  4240. imgid.IMGID_TypeID = IPRIP_GLOBAL_STATS_ID;
  4241. pimgod = NULL;
  4242. //
  4243. // get size of the first entry in the first table
  4244. //
  4245. dwErr = MibGetFirst(dwInSize, &imgid, &dwOutSize, pimgod);
  4246. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  4247. //
  4248. // allocate a buffer, and set its size
  4249. //
  4250. pimgod = RIP_ALLOC(dwOutSize);
  4251. //
  4252. // perform the query again
  4253. //
  4254. dwErr = MibGetFirst(dwInSize, &imgid, &dwOutSize, pimgod);
  4255. }
  4256. //
  4257. // now that we have the first element in the first table,
  4258. // we can enumerate the elements in the remaining tables using GetNext
  4259. //
  4260. while (dwErr == NO_ERROR) {
  4261. //
  4262. // print the current element and set up the query
  4263. // for the next element (the display functions change imgid
  4264. // so that it can be used to query the next element)
  4265. //
  4266. switch(pimgod->IMGOD_TypeID) {
  4267. case IPRIP_GLOBAL_STATS_ID:
  4268. PrintGlobalStats(hConsole, &c, &imgid, pimgod);
  4269. break;
  4270. case IPRIP_GLOBAL_CONFIG_ID:
  4271. PrintGlobalConfig(hConsole,&c, &imgid, pimgod);
  4272. break;
  4273. case IPRIP_IF_CONFIG_ID:
  4274. PrintIfConfig(hConsole, &c, &imgid, pimgod);
  4275. break;
  4276. case IPRIP_IF_BINDING_ID:
  4277. PrintIfBinding(hConsole, &c, &imgid, pimgod);
  4278. break;
  4279. case IPRIP_IF_STATS_ID:
  4280. PrintIfStats(hConsole, &c, &imgid, pimgod);
  4281. break;
  4282. case IPRIP_PEER_STATS_ID:
  4283. PrintPeerStats(hConsole, &c, &imgid, pimgod);
  4284. break;
  4285. default:
  4286. break;
  4287. }
  4288. RIP_FREE(pimgod);
  4289. pimgod = NULL;
  4290. dwOutSize = 0;
  4291. //
  4292. // move to the next line on the console
  4293. //
  4294. ++c.Y;
  4295. //
  4296. // query the next MIB element
  4297. //
  4298. dwErr = MibGetNext(dwInSize, &imgid, &dwOutSize, pimgod);
  4299. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  4300. //
  4301. // allocate a new buffer, and set its size
  4302. //
  4303. pimgod = RIP_ALLOC(dwOutSize);
  4304. //
  4305. // perform the query again
  4306. //
  4307. dwErr = MibGetNext(dwInSize, &imgid, &dwOutSize, pimgod);
  4308. }
  4309. }
  4310. //
  4311. // if memory was allocated, free it now
  4312. //
  4313. if (pimgod != NULL) { RIP_FREE(pimgod); }
  4314. LEAVE_RIP_API();
  4315. }
  4316. #define WriteLine(h,c,fmt,arg) { \
  4317. DWORD _dw; \
  4318. CHAR _sz[200], _fmt[200]; \
  4319. wsprintf(_fmt,"%-100s",fmt); \
  4320. wsprintf(_sz,_fmt,arg); \
  4321. WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \
  4322. ++(c).Y; \
  4323. }
  4324. VOID
  4325. PrintGlobalStats(
  4326. HANDLE hConsole,
  4327. PCOORD pc,
  4328. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4329. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4330. ) {
  4331. PIPRIP_GLOBAL_STATS pgs;
  4332. pgs = (PIPRIP_GLOBAL_STATS)pimgod->IMGOD_Buffer;
  4333. WriteLine(
  4334. hConsole, *pc, "System Route Changes: %d",
  4335. pgs->GS_SystemRouteChanges
  4336. );
  4337. WriteLine(
  4338. hConsole, *pc, "Total Responses Sent: %d",
  4339. pgs->GS_TotalResponsesSent
  4340. );
  4341. pimgid->IMGID_TypeID = IPRIP_GLOBAL_STATS_ID;
  4342. }
  4343. VOID
  4344. PrintGlobalConfig(
  4345. HANDLE hConsole,
  4346. PCOORD pc,
  4347. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4348. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4349. ) {
  4350. PIPRIP_GLOBAL_CONFIG pgc;
  4351. PDWORD pdwPeer, pdwPeerEnd;
  4352. CHAR szFilter[32];
  4353. LPSTR lpszAddr = NULL;
  4354. pgc = (PIPRIP_GLOBAL_CONFIG)pimgod->IMGOD_Buffer;
  4355. switch (pgc->GC_PeerFilterMode) {
  4356. case IPRIP_FILTER_DISABLED:
  4357. lstrcpy(szFilter, "disabled"); break;
  4358. case IPRIP_FILTER_INCLUDE:
  4359. lstrcpy(szFilter, "include all"); break;
  4360. case IPRIP_FILTER_EXCLUDE:
  4361. lstrcpy(szFilter, "exclude all"); break;
  4362. default:
  4363. lstrcpy(szFilter, "invalid"); break;
  4364. }
  4365. WriteLine(
  4366. hConsole, *pc, "Logging Level: %d",
  4367. pgc->GC_LoggingLevel
  4368. );
  4369. WriteLine(
  4370. hConsole, *pc, "Max Receive Queue Size: %d bytes",
  4371. pgc->GC_MaxRecvQueueSize
  4372. );
  4373. WriteLine(
  4374. hConsole, *pc, "Max Send Queue Size: %d bytes",
  4375. pgc->GC_MaxSendQueueSize
  4376. );
  4377. WriteLine(
  4378. hConsole, *pc, "Min Triggered Update interval: %d seconds",
  4379. pgc->GC_MinTriggeredUpdateInterval
  4380. );
  4381. WriteLine(
  4382. hConsole, *pc, "Peer Filter Mode: %s",
  4383. szFilter
  4384. );
  4385. WriteLine(
  4386. hConsole, *pc, "Peer Filter Count: %d",
  4387. pgc->GC_PeerFilterCount
  4388. );
  4389. pdwPeer = IPRIP_GLOBAL_PEER_FILTER_TABLE(pgc);
  4390. pdwPeerEnd = pdwPeer + pgc->GC_PeerFilterCount;
  4391. for ( ; pdwPeer < pdwPeerEnd; pdwPeer++) {
  4392. lpszAddr = INET_NTOA(*pdwPeer);
  4393. if (lpszAddr != NULL) {
  4394. WriteLine(
  4395. hConsole, *pc, " %s",
  4396. lpszAddr
  4397. );
  4398. }
  4399. }
  4400. pimgid->IMGID_TypeID = IPRIP_GLOBAL_CONFIG_ID;
  4401. }
  4402. VOID
  4403. PrintIfStats(
  4404. HANDLE hConsole,
  4405. PCOORD pc,
  4406. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4407. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4408. ) {
  4409. PIPRIP_IF_STATS pis;
  4410. pis = (PIPRIP_IF_STATS)pimgod->IMGOD_Buffer;
  4411. WriteLine(
  4412. hConsole, *pc, "Interface Index: %d",
  4413. pimgod->IMGOD_IfIndex
  4414. );
  4415. WriteLine(
  4416. hConsole, *pc, "Send Failures: %d",
  4417. pis->IS_SendFailures
  4418. );
  4419. WriteLine(
  4420. hConsole, *pc, "Receive Failures: %d",
  4421. pis->IS_ReceiveFailures
  4422. );
  4423. WriteLine(
  4424. hConsole, *pc, "Requests Sent: %d",
  4425. pis->IS_RequestsSent
  4426. );
  4427. WriteLine(
  4428. hConsole, *pc, "Requests Received: %d",
  4429. pis->IS_RequestsReceived
  4430. );
  4431. WriteLine(
  4432. hConsole, *pc, "Responses Sent: %d",
  4433. pis->IS_ResponsesSent
  4434. );
  4435. WriteLine(
  4436. hConsole, *pc, "Responses Received: %d",
  4437. pis->IS_ResponsesReceived
  4438. );
  4439. WriteLine(
  4440. hConsole, *pc, "Bad Response Packets Received: %d",
  4441. pis->IS_BadResponsePacketsReceived
  4442. );
  4443. WriteLine(
  4444. hConsole, *pc, "Bad Response Entries Received: %d",
  4445. pis->IS_BadResponseEntriesReceived
  4446. );
  4447. WriteLine(
  4448. hConsole, *pc, "Triggered Updates Sent: %d",
  4449. pis->IS_TriggeredUpdatesSent
  4450. );
  4451. pimgid->IMGID_TypeID = IPRIP_IF_STATS_ID;
  4452. pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
  4453. }
  4454. VOID
  4455. PrintIfConfig(
  4456. HANDLE hConsole,
  4457. PCOORD pc,
  4458. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4459. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4460. ) {
  4461. PIPRIP_IF_CONFIG pic;
  4462. PDWORD pdwPeer, pdwPeerEnd;
  4463. PIPRIP_ROUTE_FILTER pfilt, pfiltend;
  4464. CHAR szAuthType[24], szAuthKey[64];
  4465. CHAR szPeer[20], szAccept[20], szAnnounce[20], szFilter[64];
  4466. CHAR szUpdateMode[24], szAcceptMode[24], szAnnounceMode[24];
  4467. LPSTR lpszAddr = NULL;
  4468. pic = (PIPRIP_IF_CONFIG)pimgod->IMGOD_Buffer;
  4469. switch (pic->IC_UpdateMode) {
  4470. case IPRIP_UPDATE_PERIODIC:
  4471. lstrcpy(szUpdateMode, "periodic");
  4472. break;
  4473. case IPRIP_UPDATE_DEMAND:
  4474. lstrcpy(szUpdateMode, "demand");
  4475. break;
  4476. default:
  4477. lstrcpy(szUpdateMode, "invalid");
  4478. break;
  4479. }
  4480. switch (pic->IC_AcceptMode) {
  4481. case IPRIP_ACCEPT_DISABLED:
  4482. lstrcpy(szAcceptMode, "disabled");
  4483. break;
  4484. case IPRIP_ACCEPT_RIP1:
  4485. lstrcpy(szAcceptMode, "RIP1");
  4486. break;
  4487. case IPRIP_ACCEPT_RIP1_COMPAT:
  4488. lstrcpy(szAcceptMode, "RIP1 compatible");
  4489. break;
  4490. case IPRIP_ACCEPT_RIP2:
  4491. lstrcpy(szAcceptMode, "RIP2");
  4492. break;
  4493. default:
  4494. lstrcpy(szAcceptMode, "invalid");
  4495. break;
  4496. }
  4497. switch(pic->IC_AnnounceMode) {
  4498. case IPRIP_ANNOUNCE_DISABLED:
  4499. lstrcpy(szAnnounceMode, "disabled");
  4500. break;
  4501. case IPRIP_ANNOUNCE_RIP1:
  4502. lstrcpy(szAnnounceMode, "RIP1");
  4503. break;
  4504. case IPRIP_ANNOUNCE_RIP1_COMPAT:
  4505. lstrcpy(szAnnounceMode, "RIP1 compatible");
  4506. break;
  4507. case IPRIP_ANNOUNCE_RIP2:
  4508. lstrcpy(szAnnounceMode, "RIP2");
  4509. break;
  4510. default:
  4511. lstrcpy(szAnnounceMode, "invalid");
  4512. break;
  4513. }
  4514. switch (pic->IC_AuthenticationType) {
  4515. case IPRIP_AUTHTYPE_NONE:
  4516. lstrcpy(szAuthType, "none");
  4517. break;
  4518. case IPRIP_AUTHTYPE_SIMPLE_PASSWORD:
  4519. lstrcpy(szAuthType, "simple password");
  4520. break;
  4521. case IPRIP_AUTHTYPE_MD5:
  4522. lstrcpy(szAuthType, "MD5");
  4523. break;
  4524. default:
  4525. lstrcpy(szAuthType, "invalid");
  4526. break;
  4527. }
  4528. {
  4529. PSTR psz;
  4530. CHAR szDigits[] = "0123456789ABCDEF";
  4531. PBYTE pb, pbend;
  4532. psz = szAuthKey;
  4533. pbend = pic->IC_AuthenticationKey + IPRIP_MAX_AUTHKEY_SIZE;
  4534. for (pb = pic->IC_AuthenticationKey; pb < pbend; pb++) {
  4535. *psz++ = szDigits[*pb / 16];
  4536. *psz++ = szDigits[*pb % 16];
  4537. *psz++ = '-';
  4538. }
  4539. *(--psz) = '\0';
  4540. }
  4541. switch (pic->IC_UnicastPeerMode) {
  4542. case IPRIP_PEER_DISABLED:
  4543. lstrcpy(szPeer, "disabled"); break;
  4544. case IPRIP_PEER_ALSO:
  4545. lstrcpy(szPeer, "also"); break;
  4546. case IPRIP_PEER_ONLY:
  4547. lstrcpy(szPeer, "only"); break;
  4548. default:
  4549. lstrcpy(szPeer, "invalid"); break;
  4550. }
  4551. switch (pic->IC_AcceptFilterMode) {
  4552. case IPRIP_FILTER_DISABLED:
  4553. lstrcpy(szAccept, "disabled"); break;
  4554. case IPRIP_FILTER_INCLUDE:
  4555. lstrcpy(szAccept, "include all"); break;
  4556. case IPRIP_FILTER_EXCLUDE:
  4557. lstrcpy(szAccept, "exclude all"); break;
  4558. default:
  4559. lstrcpy(szAccept, "invalid"); break;
  4560. }
  4561. switch (pic->IC_AnnounceFilterMode) {
  4562. case IPRIP_FILTER_DISABLED:
  4563. lstrcpy(szAnnounce, "disabled"); break;
  4564. case IPRIP_FILTER_INCLUDE:
  4565. lstrcpy(szAnnounce, "include all"); break;
  4566. case IPRIP_FILTER_EXCLUDE:
  4567. lstrcpy(szAnnounce, "exclude all"); break;
  4568. default:
  4569. lstrcpy(szAnnounce, "invalid"); break;
  4570. }
  4571. WriteLine(
  4572. hConsole, *pc, "Interface Index: %d",
  4573. pimgod->IMGOD_IfIndex
  4574. );
  4575. WriteLine(
  4576. hConsole, *pc, "Metric: %d",
  4577. pic->IC_Metric
  4578. );
  4579. WriteLine(
  4580. hConsole, *pc, "Update Mode: %s",
  4581. szUpdateMode
  4582. );
  4583. WriteLine(
  4584. hConsole, *pc, "Accept Mode: %s",
  4585. szAcceptMode
  4586. );
  4587. WriteLine(
  4588. hConsole, *pc, "Announce Mode: %s",
  4589. szAnnounceMode
  4590. );
  4591. WriteLine(
  4592. hConsole, *pc, "Accept Host Routes: %s",
  4593. (IPRIP_FLAG_IS_ENABLED(pic, ACCEPT_HOST_ROUTES) ? "enabled" : "disabled")
  4594. );
  4595. WriteLine(
  4596. hConsole, *pc, "Announce Host Routes: %s",
  4597. (IPRIP_FLAG_IS_ENABLED(pic, ANNOUNCE_HOST_ROUTES) ? "enabled" : "disabled")
  4598. );
  4599. WriteLine(
  4600. hConsole, *pc, "Accept Default Routes: %s",
  4601. (IPRIP_FLAG_IS_ENABLED(pic, ACCEPT_DEFAULT_ROUTES) ? "enabled" : "disabled")
  4602. );
  4603. WriteLine(
  4604. hConsole, *pc, "Announce Default Routes: %s",
  4605. (IPRIP_FLAG_IS_ENABLED(pic, ANNOUNCE_DEFAULT_ROUTES) ? "enabled" : "disabled")
  4606. );
  4607. WriteLine(
  4608. hConsole, *pc, "Split Horizon: %s",
  4609. (IPRIP_FLAG_IS_ENABLED(pic, SPLIT_HORIZON) ? "enabled" : "disabled")
  4610. );
  4611. WriteLine(
  4612. hConsole, *pc, "Poison Reverse: %s",
  4613. (IPRIP_FLAG_IS_ENABLED(pic, POISON_REVERSE) ? "enabled" : "disabled")
  4614. );
  4615. WriteLine(
  4616. hConsole, *pc, "Graceful Shutdown: %s",
  4617. (IPRIP_FLAG_IS_ENABLED(pic, GRACEFUL_SHUTDOWN) ? "enabled" : "disabled")
  4618. );
  4619. WriteLine(
  4620. hConsole, *pc, "Triggered Updates: %s",
  4621. (IPRIP_FLAG_IS_ENABLED(pic, TRIGGERED_UPDATES) ? "enabled" : "disabled")
  4622. );
  4623. WriteLine(
  4624. hConsole, *pc, "Overwrite Static Routes: %s",
  4625. (IPRIP_FLAG_IS_ENABLED(pic, OVERWRITE_STATIC_ROUTES) ? "enabled" : "disabled")
  4626. );
  4627. WriteLine(
  4628. hConsole, *pc, "Route Expiration Interval: %d seconds",
  4629. pic->IC_RouteExpirationInterval
  4630. );
  4631. WriteLine(
  4632. hConsole, *pc, "Route Removal Interval: %d seconds",
  4633. pic->IC_RouteRemovalInterval
  4634. );
  4635. WriteLine(
  4636. hConsole, *pc, "Full Update Interval: %d seconds",
  4637. pic->IC_FullUpdateInterval
  4638. );
  4639. WriteLine(
  4640. hConsole, *pc, "Authentication Type: %s",
  4641. szAuthType
  4642. );
  4643. WriteLine(
  4644. hConsole, *pc, "Authentication Key: %s",
  4645. szAuthKey
  4646. );
  4647. WriteLine(
  4648. hConsole, *pc, "Route Tag: %d",
  4649. pic->IC_RouteTag
  4650. );
  4651. WriteLine(
  4652. hConsole, *pc, "Unicast Peer Mode: %s",
  4653. szPeer
  4654. );
  4655. WriteLine(
  4656. hConsole, *pc, "Accept Filter Mode: %s",
  4657. szAccept
  4658. );
  4659. WriteLine(
  4660. hConsole, *pc, "Announce Filter Mode: %s",
  4661. szAnnounce
  4662. );
  4663. WriteLine(
  4664. hConsole, *pc, "Unicast Peer Count: %d",
  4665. pic->IC_UnicastPeerCount
  4666. );
  4667. pdwPeer = IPRIP_IF_UNICAST_PEER_TABLE(pic);
  4668. pdwPeerEnd = pdwPeer + pic->IC_UnicastPeerCount;
  4669. for ( ; pdwPeer < pdwPeerEnd; pdwPeer++) {
  4670. lpszAddr = INET_NTOA(*pdwPeer);
  4671. if (lpszAddr != NULL) {
  4672. WriteLine(
  4673. hConsole, *pc, " %s",
  4674. lpszAddr
  4675. );
  4676. }
  4677. }
  4678. WriteLine(
  4679. hConsole, *pc, "Accept Filter Count: %d",
  4680. pic->IC_AcceptFilterCount
  4681. );
  4682. pfilt = IPRIP_IF_ACCEPT_FILTER_TABLE(pic);
  4683. pfiltend = pfilt + pic->IC_AcceptFilterCount;
  4684. for ( ; pfilt < pfiltend; pfilt++) {
  4685. lpszAddr = INET_NTOA(pfilt->RF_LoAddress);
  4686. if (lpszAddr != NULL) {
  4687. lstrcpy(szFilter, lpszAddr);
  4688. strcat(szFilter, " - ");
  4689. lpszAddr = INET_NTOA(pfilt->RF_HiAddress);
  4690. if (lpszAddr != NULL) {
  4691. strcat(szFilter, INET_NTOA(pfilt->RF_HiAddress));
  4692. WriteLine(
  4693. hConsole, *pc, " %s",
  4694. szFilter
  4695. );
  4696. }
  4697. }
  4698. }
  4699. WriteLine(
  4700. hConsole, *pc, "Announce Filter Count: %d",
  4701. pic->IC_AnnounceFilterCount
  4702. );
  4703. pfilt = IPRIP_IF_ANNOUNCE_FILTER_TABLE(pic);
  4704. pfiltend = pfilt + pic->IC_AnnounceFilterCount;
  4705. for ( ; pfilt < pfiltend; pfilt++) {
  4706. lpszAddr = INET_NTOA(pfilt->RF_LoAddress);
  4707. if (lpszAddr != NULL) {
  4708. lstrcpy(szFilter, lpszAddr);
  4709. strcat(szFilter, " - ");
  4710. lpszAddr = INET_NTOA(pfilt->RF_HiAddress);
  4711. if (lpszAddr != NULL) {
  4712. strcat(szFilter, INET_NTOA(pfilt->RF_HiAddress));
  4713. WriteLine(
  4714. hConsole, *pc, " %s",
  4715. szFilter
  4716. );
  4717. }
  4718. }
  4719. }
  4720. pimgid->IMGID_TypeID = IPRIP_IF_CONFIG_ID;
  4721. pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
  4722. }
  4723. VOID
  4724. PrintIfBinding(
  4725. HANDLE hConsole,
  4726. PCOORD pc,
  4727. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4728. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4729. ) {
  4730. DWORD i;
  4731. CHAR szAddr[64];
  4732. PIPRIP_IF_BINDING pib;
  4733. PIPRIP_IP_ADDRESS paddr;
  4734. LPSTR lpszAddr = NULL;
  4735. pib = (PIPRIP_IF_BINDING) pimgod->IMGOD_Buffer;
  4736. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  4737. WriteLine(
  4738. hConsole, *pc, "Interface Index: %d",
  4739. pimgod->IMGOD_IfIndex
  4740. );
  4741. WriteLine(
  4742. hConsole, *pc, "Address Count: %d",
  4743. pib->IB_AddrCount
  4744. );
  4745. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  4746. lpszAddr = INET_NTOA(paddr->IA_Address);
  4747. if (lpszAddr != NULL) {
  4748. lstrcpy(szAddr, lpszAddr);
  4749. lstrcat(szAddr, " - ");
  4750. lpszAddr = INET_NTOA(paddr->IA_Netmask);
  4751. if (lpszAddr != NULL) {
  4752. lstrcat(szAddr, lpszAddr);
  4753. WriteLine(
  4754. hConsole, *pc, "Address Entry: %s",
  4755. szAddr
  4756. );
  4757. }
  4758. }
  4759. }
  4760. pimgid->IMGID_TypeID = IPRIP_IF_BINDING_ID;
  4761. pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
  4762. }
  4763. VOID
  4764. PrintPeerStats(
  4765. HANDLE hConsole,
  4766. PCOORD pc,
  4767. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  4768. PIPRIP_MIB_GET_OUTPUT_DATA pimgod
  4769. ) {
  4770. PIPRIP_PEER_STATS pps;
  4771. LPSTR lpszAddr = INET_NTOA(pimgod->IMGOD_PeerAddress);
  4772. pps = (PIPRIP_PEER_STATS)pimgod->IMGOD_Buffer;
  4773. if (lpszAddr != NULL) {
  4774. WriteLine(
  4775. hConsole, *pc, "Peer Address: %s",
  4776. lpszAddr
  4777. );
  4778. }
  4779. else {
  4780. WriteLine(
  4781. hConsole, *pc, "Peer Address: Failed inet_ntoa conv ",
  4782. lpszAddr
  4783. );
  4784. }
  4785. WriteLine(
  4786. hConsole, *pc, "Last Peer Route Tag: %d",
  4787. pps->PS_LastPeerRouteTag
  4788. );
  4789. WriteLine(
  4790. hConsole, *pc, "Last Peer Update Tick-Count %d ticks",
  4791. pps->PS_LastPeerUpdateTickCount
  4792. );
  4793. WriteLine(
  4794. hConsole, *pc, "Bad Response Packets From Peer: %d",
  4795. pps->PS_BadResponsePacketsFromPeer
  4796. );
  4797. WriteLine(
  4798. hConsole, *pc, "Bad Response Entries From Peer: %d",
  4799. pps->PS_BadResponseEntriesFromPeer
  4800. );
  4801. pimgid->IMGID_TypeID = IPRIP_PEER_STATS_ID;
  4802. pimgid->IMGID_PeerAddress = pimgod->IMGOD_PeerAddress;
  4803. }
  4804. //----------------------------------------------------------------------------
  4805. // Function: CallbackFunctionNetworkEvents
  4806. //
  4807. // This function queues a worker function to process the input packets.
  4808. // It registers a ntdll wait event at the end so that only one thread can
  4809. // be processing the input packets.
  4810. //----------------------------------------------------------------------------
  4811. VOID
  4812. CallbackFunctionNetworkEvents (
  4813. PVOID pContext,
  4814. BOOLEAN NotUsed
  4815. ) {
  4816. HANDLE WaitHandle;
  4817. //
  4818. // enter/leaveRipApi should be called to make sure that rip dll is around
  4819. //
  4820. if (!ENTER_RIP_API()) { return; }
  4821. //
  4822. // set the pointer to NULL, so that Unregister wont be called
  4823. //
  4824. WaitHandle = InterlockedExchangePointer(&ig.IG_IpripInputEventHandle, NULL);
  4825. if (WaitHandle)
  4826. UnregisterWaitEx( WaitHandle, NULL ) ;
  4827. QueueRipWorker(WorkerFunctionNetworkEvents,pContext);
  4828. LEAVE_RIP_API();
  4829. }
  4830. //----------------------------------------------------------------------------
  4831. // Function: ProcessNetworkEvents
  4832. //
  4833. // This function enumerates the input events on each interface
  4834. // and processes any incoming input packets
  4835. //----------------------------------------------------------------------------
  4836. VOID
  4837. WorkerFunctionNetworkEvents (
  4838. PVOID pContext
  4839. ) {
  4840. DWORD i, dwErr;
  4841. PIF_TABLE pTable;
  4842. PIPRIP_IF_CONFIG pic;
  4843. PIPRIP_IF_BINDING pib;
  4844. PIF_TABLE_ENTRY pite;
  4845. PLIST_ENTRY ple, phead;
  4846. WSANETWORKEVENTS wsane;
  4847. PIPRIP_IP_ADDRESS paddr;
  4848. LPSTR lpszAddr = NULL;
  4849. if (!ENTER_RIP_WORKER()) { return; }
  4850. pTable = ig.IG_IfTable;
  4851. ACQUIRE_IF_LOCK_SHARED();
  4852. //
  4853. // go through the list of active interfaces
  4854. // processing sockets which are read-ready
  4855. //
  4856. phead = &pTable->IT_ListByAddress;
  4857. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  4858. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  4859. pic = pite->ITE_Config;
  4860. if (pic->IC_AcceptMode == IPRIP_ACCEPT_DISABLED) { continue; }
  4861. pib = pite->ITE_Binding;
  4862. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  4863. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  4864. if (pite->ITE_Sockets[i] == INVALID_SOCKET) { continue; }
  4865. //
  4866. // enumerate network events to see whether
  4867. // any packets have arrived on this interface
  4868. //
  4869. dwErr = WSAEnumNetworkEvents(pite->ITE_Sockets[i], NULL, &wsane);
  4870. if (dwErr != NO_ERROR) {
  4871. lpszAddr = INET_NTOA(paddr->IA_Address);
  4872. if (lpszAddr != NULL) {
  4873. TRACE3(
  4874. RECEIVE, "error %d checking for input on interface %d (%s)",
  4875. dwErr, pite->ITE_Index, lpszAddr
  4876. );
  4877. LOGWARN1(ENUM_NETWORK_EVENTS_FAILED, lpszAddr, dwErr);
  4878. }
  4879. continue;
  4880. }
  4881. //
  4882. // see if the input bit is set
  4883. //
  4884. if (!(wsane.lNetworkEvents & FD_READ)) { continue; }
  4885. //
  4886. // the input flag is set, now see if there was an error
  4887. //
  4888. if (wsane.iErrorCode[FD_READ_BIT] != NO_ERROR) {
  4889. lpszAddr = INET_NTOA(paddr->IA_Address);
  4890. if (lpszAddr != NULL) {
  4891. TRACE3(
  4892. RECEIVE, "error %d in input record for interface %d (%s)",
  4893. wsane.iErrorCode[FD_READ_BIT], pite->ITE_Index, lpszAddr
  4894. );
  4895. LOGWARN1(INPUT_RECORD_ERROR, lpszAddr, dwErr);
  4896. }
  4897. continue;
  4898. }
  4899. //
  4900. // there is no error, so process the socket
  4901. //
  4902. ProcessSocket(i, pite, pTable);
  4903. }
  4904. }
  4905. RELEASE_IF_LOCK_SHARED();
  4906. //
  4907. // if dll is not stopping, register input event with NtdllWait thread again
  4908. //
  4909. if (ig.IG_Status != IPRIP_STATUS_STOPPING) {
  4910. if (! RegisterWaitForSingleObject(
  4911. &ig.IG_IpripInputEventHandle,
  4912. ig.IG_IpripInputEvent,
  4913. CallbackFunctionNetworkEvents,
  4914. NULL,
  4915. INFINITE,
  4916. (WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE)
  4917. )) {
  4918. dwErr = GetLastError();
  4919. TRACE1(START,
  4920. "error %d registering input event with NtdllWait thread",
  4921. dwErr);
  4922. LOGERR0(REGISTER_WAIT_FAILED, dwErr);
  4923. }
  4924. }
  4925. LEAVE_RIP_WORKER();
  4926. }
  4927. //----------------------------------------------------------------------------
  4928. // Function: ProcessSocket
  4929. //
  4930. // This function receives the message on the given socket and queues it
  4931. // for processing if the configuration on the receiving interface allows it.
  4932. //----------------------------------------------------------------------------
  4933. VOID
  4934. ProcessSocket(
  4935. DWORD dwAddrIndex,
  4936. PIF_TABLE_ENTRY pite,
  4937. PIF_TABLE pTable
  4938. ) {
  4939. SOCKET sock;
  4940. PPEER_TABLE pPeers;
  4941. IPRIP_PACKET pkt;
  4942. PBYTE pInputPacket;
  4943. CHAR szSrcaddr[20];
  4944. LPSTR lpszAddr = NULL;
  4945. PIPRIP_HEADER pih;
  4946. PINPUT_CONTEXT pwc;
  4947. PIPRIP_IF_STATS pis;
  4948. PIPRIP_IF_CONFIG pic;
  4949. PIPRIP_IF_BINDING pib;
  4950. PIPRIP_IP_ADDRESS paddr;
  4951. PIPRIP_PEER_STATS pps;
  4952. PPEER_TABLE_ENTRY ppte;
  4953. DWORD dwErr, dwSrcaddr;
  4954. SOCKADDR_IN sinInputSource;
  4955. INT i, iInputLength, iAddrLength;
  4956. pwc = NULL;
  4957. pis = &pite->ITE_Stats;
  4958. pic = pite->ITE_Config;
  4959. sock = pite->ITE_Sockets[dwAddrIndex];
  4960. pib = pite->ITE_Binding;
  4961. paddr = IPRIP_IF_ADDRESS_TABLE(pib) + dwAddrIndex;
  4962. pPeers = ig.IG_PeerTable;
  4963. do {
  4964. pInputPacket = pkt.IP_Packet;
  4965. //
  4966. // read the incoming packet
  4967. //
  4968. iAddrLength = sizeof(SOCKADDR_IN);
  4969. iInputLength = recvfrom(
  4970. sock, pInputPacket, MAX_PACKET_SIZE, 0,
  4971. (PSOCKADDR)&sinInputSource, &iAddrLength
  4972. );
  4973. if (iInputLength == 0 || iInputLength == SOCKET_ERROR) {
  4974. dwErr = WSAGetLastError();
  4975. lpszAddr = INET_NTOA(paddr->IA_Address);
  4976. if (lpszAddr != NULL) {
  4977. TRACE3(
  4978. RECEIVE, "error %d receiving packet on interface %d (%s)",
  4979. dwErr, pite->ITE_Index, lpszAddr
  4980. );
  4981. LOGERR1(RECVFROM_FAILED, lpszAddr, dwErr);
  4982. }
  4983. InterlockedIncrement(&pis->IS_ReceiveFailures);
  4984. break;
  4985. }
  4986. dwSrcaddr = sinInputSource.sin_addr.s_addr;
  4987. //
  4988. // ignore the packet if it is from a local address
  4989. //
  4990. if (GetIfByAddress(pTable, dwSrcaddr, GETMODE_EXACT, NULL) != NULL) {
  4991. break;
  4992. }
  4993. lpszAddr = INET_NTOA(dwSrcaddr);
  4994. if (lpszAddr != NULL) { lstrcpy(szSrcaddr, lpszAddr); }
  4995. else { ZeroMemory(szSrcaddr, sizeof(szSrcaddr)); }
  4996. lpszAddr = INET_NTOA(paddr->IA_Address);
  4997. if (lpszAddr != NULL) {
  4998. TRACE4(
  4999. RECEIVE, "received %d-byte packet from %s on interface %d (%s)",
  5000. iInputLength, szSrcaddr, pite->ITE_Index, lpszAddr
  5001. );
  5002. }
  5003. //
  5004. // the packet must contain at least one entry
  5005. //
  5006. if (iInputLength < MIN_PACKET_SIZE) {
  5007. lpszAddr = INET_NTOA(paddr->IA_Address);
  5008. if (lpszAddr != NULL) {
  5009. TRACE4(
  5010. RECEIVE,
  5011. "%d-byte packet from %s on interface %d (%s) is too small",
  5012. iInputLength, szSrcaddr, pite->ITE_Index, lpszAddr
  5013. );
  5014. LOGWARN2(PACKET_TOO_SMALL, lpszAddr, szSrcaddr, NO_ERROR);
  5015. }
  5016. break;
  5017. }
  5018. //
  5019. // find out which peer sent this, or create a new peer
  5020. //
  5021. ACQUIRE_PEER_LOCK_EXCLUSIVE();
  5022. dwErr = CreatePeerEntry(pPeers, dwSrcaddr, &ppte);
  5023. if (dwErr == NO_ERROR) {
  5024. pps = &ppte->PTE_Stats;
  5025. }
  5026. else {
  5027. pps = NULL;
  5028. //
  5029. // not a serious error, so go on
  5030. //
  5031. TRACE2(
  5032. RECEIVE, "error %d creating peer statistics entry for %s",
  5033. dwErr, szSrcaddr
  5034. );
  5035. }
  5036. RELEASE_PEER_LOCK_EXCLUSIVE();
  5037. ACQUIRE_PEER_LOCK_SHARED();
  5038. //
  5039. // place a template over the packet
  5040. //
  5041. pih = (PIPRIP_HEADER)pInputPacket;
  5042. //
  5043. // update the peer statistics
  5044. //
  5045. if (pps != NULL) {
  5046. InterlockedExchange(
  5047. &pps->PS_LastPeerUpdateTickCount, GetTickCount()
  5048. );
  5049. InterlockedExchange(
  5050. &pps->PS_LastPeerUpdateVersion, (DWORD)pih->IH_Version
  5051. );
  5052. }
  5053. //
  5054. // discard if the version is invalid, or if the packet is
  5055. // a RIPv1 packet and the reserved field in the header is non-zero
  5056. //
  5057. if (pih->IH_Version == 0) {
  5058. lpszAddr = INET_NTOA(paddr->IA_Address);
  5059. if (lpszAddr != NULL) {
  5060. TRACE3(
  5061. RECEIVE, "invalid version packet from %s on interface %d (%s)",
  5062. szSrcaddr, pite->ITE_Index, lpszAddr
  5063. );
  5064. LOGWARNDATA2(
  5065. PACKET_VERSION_INVALID, lpszAddr, szSrcaddr,
  5066. iInputLength, pInputPacket
  5067. );
  5068. }
  5069. if (pps != NULL) {
  5070. InterlockedIncrement(&pps->PS_BadResponsePacketsFromPeer);
  5071. }
  5072. RELEASE_PEER_LOCK_SHARED();
  5073. break;
  5074. }
  5075. else
  5076. if (pih->IH_Version == 1 && pih->IH_Reserved != 0) {
  5077. lpszAddr = INET_NTOA(paddr->IA_Address);
  5078. if (lpszAddr != NULL) {
  5079. TRACE3(
  5080. RECEIVE, "invalid packet header from %s on interface %d (%s)",
  5081. szSrcaddr, pite->ITE_Index, lpszAddr
  5082. );
  5083. LOGWARNDATA2(
  5084. PACKET_HEADER_CORRUPT, lpszAddr, szSrcaddr,
  5085. iInputLength, pInputPacket
  5086. );
  5087. }
  5088. if (pps != NULL) {
  5089. InterlockedIncrement(&pps->PS_BadResponsePacketsFromPeer);
  5090. }
  5091. RELEASE_PEER_LOCK_SHARED();
  5092. break;
  5093. }
  5094. RELEASE_PEER_LOCK_SHARED();
  5095. //
  5096. // make sure command field is valid, and
  5097. // update statistics on received packets
  5098. //
  5099. if (pih->IH_Command == IPRIP_REQUEST) {
  5100. InterlockedIncrement(&pis->IS_RequestsReceived);
  5101. }
  5102. else
  5103. if (pih->IH_Command == IPRIP_RESPONSE) {
  5104. InterlockedIncrement(&pis->IS_ResponsesReceived);
  5105. }
  5106. else {
  5107. break;
  5108. }
  5109. //
  5110. // allocate and initialize a work-context to be queued
  5111. // and update the receive queue size
  5112. //
  5113. pwc = RIP_ALLOC(sizeof(INPUT_CONTEXT));
  5114. if (pwc == NULL) {
  5115. lpszAddr = INET_NTOA(paddr->IA_Address);
  5116. if (lpszAddr != NULL) {
  5117. TRACE4(
  5118. RECEIVE,
  5119. "error %d allocating %d bytes for packet on interface %d (%s)",
  5120. GetLastError(), sizeof(INPUT_CONTEXT), pite->ITE_Index,
  5121. lpszAddr
  5122. );
  5123. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  5124. }
  5125. break;
  5126. }
  5127. pwc->IC_InterfaceIndex = pite->ITE_Index;
  5128. pwc->IC_AddrIndex = dwAddrIndex;
  5129. pwc->IC_InputSource = sinInputSource;
  5130. pwc->IC_InputLength = iInputLength;
  5131. pwc->IC_InputPacket = pkt;
  5132. //
  5133. // enqueue the packet and source-address as a recv-queue entry
  5134. //
  5135. ACQUIRE_GLOBAL_LOCK_SHARED();
  5136. ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
  5137. dwErr = EnqueueRecvEntry(
  5138. ig.IG_RecvQueue, pih->IH_Command, (PBYTE)pwc
  5139. );
  5140. RELEASE_LIST_LOCK(ig.IG_RecvQueue);
  5141. RELEASE_GLOBAL_LOCK_SHARED();
  5142. if (dwErr != NO_ERROR) {
  5143. lpszAddr = INET_NTOA(paddr->IA_Address);
  5144. if (lpszAddr != NULL) {
  5145. TRACE4(
  5146. RECEIVE,
  5147. "error %d queueing data for packet from %s on interface %d (%s)",
  5148. dwErr, szSrcaddr, pite->ITE_Index, lpszAddr
  5149. );
  5150. }
  5151. break;
  5152. }
  5153. //
  5154. // enqueue the work-item to process the packet
  5155. //
  5156. dwErr = QueueRipWorker(WorkerFunctionProcessInput, NULL);
  5157. if (dwErr != NO_ERROR) {
  5158. PLIST_ENTRY phead;
  5159. lpszAddr = INET_NTOA(paddr->IA_Address);
  5160. if (lpszAddr != NULL) {
  5161. TRACE4(
  5162. RECEIVE,
  5163. "error %d queueing work-item for packet from %s on interface %d (%s)",
  5164. dwErr, szSrcaddr, pite->ITE_Index, lpszAddr
  5165. );
  5166. LOGERR0(QUEUE_WORKER_FAILED, dwErr);
  5167. }
  5168. //
  5169. // remove the data that was queued for processing
  5170. //
  5171. ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
  5172. phead = &ig.IG_RecvQueue->LL_Head;
  5173. RemoveTailList(phead);
  5174. ig.IG_RecvQueueSize -= sizeof(RECV_QUEUE_ENTRY);
  5175. RELEASE_LIST_LOCK(ig.IG_RecvQueue);
  5176. break;
  5177. }
  5178. return;
  5179. } while(FALSE);
  5180. //
  5181. // some cleanup is required if an error brought us here
  5182. //
  5183. if (pwc != NULL) { RIP_FREE(pwc); }
  5184. return;
  5185. }
  5186. DWORD
  5187. ProcessRtmNotification(
  5188. RTM_ENTITY_HANDLE hRtmHandle, // not used
  5189. RTM_EVENT_TYPE retEventType,
  5190. PVOID pvContext1, // not used
  5191. PVOID pvContext2 // not used
  5192. ) {
  5193. DWORD dwErr;
  5194. TRACE1(ROUTE, "ENTERED ProcessRtmNotification, event %d", retEventType );
  5195. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  5196. //
  5197. // only route change notifications are processed
  5198. //
  5199. if (retEventType == RTM_CHANGE_NOTIFICATION) {
  5200. QueueRipWorker(WorkerFunctionProcessRtmMessage, (PVOID)retEventType);
  5201. dwErr = NO_ERROR;
  5202. }
  5203. else {
  5204. dwErr = ERROR_NOT_SUPPORTED;
  5205. }
  5206. LEAVE_RIP_API();
  5207. TRACE1(ROUTE, "LEAVING ProcessRtmNotification %d", dwErr);
  5208. return dwErr;
  5209. }
  5210. DWORD
  5211. BlockDeleteRoutesOnInterface (
  5212. IN HANDLE hRtmHandle,
  5213. IN DWORD dwIfIndex
  5214. )
  5215. /*++
  5216. Routine Description :
  5217. This routine deletes all the routes learnt by the protocol
  5218. over the specified interface.
  5219. Parameters :
  5220. hRtmHandle - Entity registration handle
  5221. dwIfIndex - Interface over which routes are to be deleted
  5222. Return Value :
  5223. --*/
  5224. {
  5225. HANDLE hRtmEnum;
  5226. PHANDLE phRoutes = NULL;
  5227. DWORD dwHandles, dwFlags, i, dwErr;
  5228. dwErr = RtmCreateRouteEnum(
  5229. hRtmHandle, NULL, RTM_VIEW_MASK_ANY, RTM_ENUM_OWN_ROUTES,
  5230. NULL, RTM_MATCH_INTERFACE, NULL, dwIfIndex, &hRtmEnum
  5231. );
  5232. if ( dwErr != NO_ERROR ) {
  5233. TRACE1(
  5234. ANY, "BlockDeleteRoutesOnInterface: Error %d creating handle",
  5235. dwErr
  5236. );
  5237. return dwErr;
  5238. }
  5239. //
  5240. // allocate handle array large enough to hold max handles in an
  5241. // enum
  5242. //
  5243. phRoutes = RIP_ALLOC(ig.IG_RtmProfile.MaxHandlesInEnum * sizeof(HANDLE));
  5244. if ( phRoutes == NULL ) {
  5245. dwErr = GetLastError();
  5246. TRACE2(
  5247. ANY, "BlockDeleteRoutesOnInterface: error %d while "
  5248. "allocating %d bytes to hold max handles in an enum",
  5249. dwErr, ig.IG_RtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  5250. );
  5251. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  5252. return dwErr;
  5253. }
  5254. do {
  5255. dwHandles = ig.IG_RtmProfile.MaxHandlesInEnum;
  5256. dwErr = RtmGetEnumRoutes(
  5257. hRtmHandle, hRtmEnum, &dwHandles, phRoutes
  5258. );
  5259. for ( i = 0; i < dwHandles; i++ )
  5260. {
  5261. if ( RtmDeleteRouteToDest(
  5262. hRtmHandle, phRoutes[i], &dwFlags
  5263. ) != NO_ERROR ) {
  5264. //
  5265. // If delete is successful, this is automatic
  5266. //
  5267. TRACE2(
  5268. ANY, "BlockDeleteRoutesOnInterface : error %d deleting"
  5269. " routes on interface %d", dwErr, dwIfIndex
  5270. );
  5271. dwErr = RtmReleaseRoutes(hRtmHandle, 1, &phRoutes[i]);
  5272. if (dwErr != NO_ERROR) {
  5273. TRACE1(ANY, "error %d releasing route", dwErr);
  5274. }
  5275. }
  5276. }
  5277. } while (dwErr == NO_ERROR);
  5278. //
  5279. // close enum handles
  5280. //
  5281. dwErr = RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
  5282. if (dwErr != NO_ERROR) {
  5283. TRACE1(
  5284. ANY, "BlockDeleteRoutesOnInterface : error %d closing enum handle",
  5285. dwErr
  5286. );
  5287. }
  5288. if ( phRoutes ) {
  5289. RIP_FREE(phRoutes);
  5290. }
  5291. return NO_ERROR;
  5292. }