Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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