Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3808 lines
88 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: table.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin Aug-8-1995 Created.
  8. //
  9. // V Raman Oct-3-1996
  10. // Added code to create/delete/wait on
  11. // ITE_DeactivateEvent. Also added code to set
  12. // ITE_Flags when deactivate is pending.
  13. //
  14. // V Raman Oct-27-1996
  15. // Removed deactivate event and made
  16. // DeactivateInterface synchronous
  17. //
  18. // interface table and peer table implementation
  19. //============================================================================
  20. #include "pchrip.h"
  21. #pragma hdrstop
  22. DWORD CreateIfSocket(PIF_TABLE_ENTRY pITE);
  23. DWORD DeleteIfSocket(PIF_TABLE_ENTRY pITE);
  24. DWORD InsertIfByAddress(PIF_TABLE pTable, PIF_TABLE_ENTRY pITE);
  25. DWORD InsertPeerByAddress(PPEER_TABLE pTable, PPEER_TABLE_ENTRY pPTE);
  26. DWORD AddNeighborToIfConfig(DWORD dwRemoteAddress, PIF_TABLE_ENTRY pite);
  27. //----------------------------------------------------------------------------
  28. // Function: CreateIfTable
  29. //
  30. // initializes an interface table
  31. //----------------------------------------------------------------------------
  32. DWORD
  33. CreateIfTable(
  34. PIF_TABLE pTable
  35. ) {
  36. DWORD dwErr;
  37. PLIST_ENTRY phead, plstart, plend;
  38. //
  39. // initialize the multiple-reader/single-writer synchronization object
  40. //
  41. dwErr = CreateReadWriteLock(&pTable->IT_RWL);
  42. if (dwErr != NO_ERROR) {
  43. TRACE1(IF, "error %d creating read-write-lock", dwErr);
  44. return dwErr;
  45. }
  46. //
  47. // initialize the hash table
  48. //
  49. plstart = pTable->IT_HashTableByIndex;
  50. plend = plstart + IF_HASHTABLE_SIZE;
  51. for (phead = plstart; phead < plend; phead++) {
  52. InitializeListHead(phead);
  53. }
  54. //
  55. // initialize the lists ordered by address and by index
  56. //
  57. InitializeListHead(&pTable->IT_ListByAddress);
  58. InitializeListHead(&pTable->IT_ListByIndex);
  59. //
  60. // initialize the table's critical section
  61. //
  62. try {
  63. InitializeCriticalSection(&pTable->IT_CS);
  64. }
  65. except(EXCEPTION_EXECUTE_HANDLER) {
  66. dwErr = GetExceptionCode();
  67. }
  68. //
  69. // Create timers for full updates and for triggered updates
  70. //
  71. if (!CreateTimerQueueTimer(
  72. &pTable->IT_FinishFullUpdateTimer,
  73. ig.IG_TimerQueueHandle,
  74. WorkerFunctionFinishFullUpdate, NULL,
  75. 10000000, 10000000, 0
  76. )) {
  77. dwErr = GetLastError();
  78. TRACE1(IF, "error %d creating finish full update timer", dwErr);
  79. return dwErr;
  80. }
  81. if (!CreateTimerQueueTimer(
  82. &pTable->IT_FinishTriggeredUpdateTimer,
  83. ig.IG_TimerQueueHandle,
  84. WorkerFunctionFinishTriggeredUpdate, NULL,
  85. 10000000, 10000000, 0
  86. )) {
  87. dwErr = GetLastError();
  88. TRACE1(IF, "error %d creating finish triggered update timer", dwErr);
  89. return dwErr;
  90. }
  91. //
  92. // initialize remainder of struct
  93. //
  94. if (dwErr == NO_ERROR) {
  95. pTable->IT_Created = 0x12345678;
  96. pTable->IT_Flags = 0;
  97. pTable->IT_LastUpdateTime.LowPart =
  98. pTable->IT_LastUpdateTime.HighPart = 0;
  99. }
  100. return dwErr;
  101. }
  102. //----------------------------------------------------------------------------
  103. // Function: DeleteIfTable
  104. //
  105. // frees resources used by an interface table.
  106. // this assumes the table is locked for writing
  107. //----------------------------------------------------------------------------
  108. DWORD
  109. DeleteIfTable(
  110. PIF_TABLE pTable
  111. ) {
  112. DWORD dwIndex;
  113. PIF_TABLE_ENTRY pite;
  114. PLIST_ENTRY ple, plend, phead;
  115. //
  116. // free memory for all existing interfaces
  117. //
  118. plend = pTable->IT_HashTableByIndex + IF_HASHTABLE_SIZE;
  119. for (ple = plend - IF_HASHTABLE_SIZE; ple < plend; ple++) {
  120. while (!IsListEmpty(ple)) {
  121. phead = RemoveHeadList(ple);
  122. pite = CONTAINING_RECORD(phead, IF_TABLE_ENTRY, ITE_HTLinkByIndex);
  123. if (IF_IS_BOUND(pite)) {
  124. DeleteIfSocket(pite);
  125. if (IF_IS_ENABLED(pite)) {
  126. RemoveEntryList(&pite->ITE_LinkByAddress);
  127. }
  128. RIP_FREE(pite->ITE_Binding);
  129. }
  130. RIP_FREE(pite->ITE_Config);
  131. RIP_FREE(pite);
  132. }
  133. }
  134. //
  135. // delete synchronization objects
  136. //
  137. DeleteCriticalSection(&pTable->IT_CS);
  138. DeleteReadWriteLock(&pTable->IT_RWL);
  139. pTable->IT_Created = 0;
  140. pTable->IT_Flags = 0;
  141. return NO_ERROR;
  142. }
  143. //----------------------------------------------------------------------------
  144. // Function: CreateIfEntry
  145. //
  146. // inserts an entry into the interface table.
  147. // this assumes the table is locked for writing
  148. //----------------------------------------------------------------------------
  149. DWORD
  150. CreateIfEntry(
  151. PIF_TABLE pTable,
  152. DWORD dwIndex,
  153. NET_INTERFACE_TYPE dwIfType,
  154. PIPRIP_IF_CONFIG pConfig,
  155. PIF_TABLE_ENTRY *ppEntry
  156. ) {
  157. DWORD dwErr, dwSize;
  158. PIF_TABLE_ENTRY pite;
  159. PLIST_ENTRY ple, phead;
  160. PIPRIP_IF_CONFIG picsrc, picdst;
  161. if (ppEntry != NULL) { *ppEntry = NULL; }
  162. dwErr = NO_ERROR;
  163. do {
  164. //
  165. // fail if the interface exists
  166. //
  167. pite = GetIfByIndex(pTable, dwIndex);
  168. if (pite != NULL) {
  169. pite = NULL;
  170. TRACE1(IF, "interface %d already exists", dwIndex);
  171. dwErr = ERROR_INVALID_PARAMETER;
  172. break;
  173. }
  174. //
  175. // allocate memory for the new interface
  176. //
  177. pite = RIP_ALLOC(sizeof(IF_TABLE_ENTRY));
  178. if (pite == NULL) {
  179. dwErr = GetLastError();
  180. TRACE3(
  181. ANY, "error %d allocating %d bytes for interface %d",
  182. dwErr, sizeof(IF_TABLE_ENTRY), dwIndex
  183. );
  184. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  185. break;
  186. }
  187. //
  188. // initialize interface fields
  189. //
  190. pite->ITE_Index = dwIndex;
  191. pite->ITE_Type = dwIfType;
  192. //
  193. // Change semantics to come up in UNBOUND-DISABLED state
  194. //
  195. //pite->ITE_Flags = ITEFLAG_ENABLED;
  196. pite-> ITE_Flags = 0;
  197. pite->ITE_Config = NULL;
  198. pite->ITE_Binding = NULL;
  199. pite->ITE_Sockets = NULL;
  200. pite->ITE_FullOrDemandUpdateTimer = NULL;
  201. picsrc = (PIPRIP_IF_CONFIG)pConfig;
  202. dwSize = IPRIP_IF_CONFIG_SIZE(picsrc);
  203. //
  204. // validate the configuration parameters
  205. //
  206. dwErr = ValidateIfConfig(pConfig);
  207. if (dwErr != NO_ERROR) {
  208. TRACE1(IF, "invalid config specified for interface %d", dwIndex);
  209. break;
  210. }
  211. //
  212. // allocate space to hold the interface configuration
  213. //
  214. pite->ITE_Config = picdst = RIP_ALLOC(dwSize);
  215. if (picdst == NULL) {
  216. dwErr = GetLastError();
  217. TRACE3(
  218. IF, "error %d allocating %d bytes for interface %d config",
  219. dwErr, dwSize, dwIndex
  220. );
  221. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  222. break;
  223. }
  224. //
  225. // copy the configuration
  226. //
  227. CopyMemory(picdst, picsrc, dwSize);
  228. //
  229. // initialize the binding information and interface stats
  230. //
  231. pite->ITE_Binding = NULL;
  232. ZeroMemory(&pite->ITE_Stats, sizeof(IPRIP_IF_STATS));
  233. //
  234. // insert the interface in the hash table
  235. //
  236. InsertHeadList(
  237. pTable->IT_HashTableByIndex + IF_HASHVALUE(dwIndex),
  238. &pite->ITE_HTLinkByIndex
  239. );
  240. //
  241. // insert the interface in the list ordered by index
  242. //
  243. phead = &pTable->IT_ListByIndex;
  244. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  245. PIF_TABLE_ENTRY ptemp;
  246. ptemp = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  247. if (pite->ITE_Index < ptemp->ITE_Index) { break; }
  248. }
  249. InsertTailList(ple, &pite->ITE_LinkByIndex);
  250. if (ppEntry != NULL) { *ppEntry = pite; }
  251. } while(FALSE);
  252. if (dwErr != NO_ERROR && pite != NULL) {
  253. if (pite->ITE_Config != NULL) { RIP_FREE(pite->ITE_Config); }
  254. RIP_FREE(pite);
  255. }
  256. return dwErr;
  257. }
  258. //----------------------------------------------------------------------------
  259. // Function: DeleteIfEntry
  260. //
  261. // removes an entry from the interface table.
  262. // this assumes the table is locked for writing
  263. //----------------------------------------------------------------------------
  264. DWORD
  265. DeleteIfEntry(
  266. PIF_TABLE pTable,
  267. DWORD dwIndex
  268. ) {
  269. PIF_TABLE_ENTRY pite;
  270. //
  271. // find the interface if it exists
  272. //
  273. pite = GetIfByIndex(pTable, dwIndex);
  274. if (pite == NULL) {
  275. TRACE1(IF, "could not find interface %d", dwIndex);
  276. return ERROR_INVALID_PARAMETER;
  277. }
  278. //
  279. // cleanup the socket depending on its state
  280. //
  281. if (IF_IS_BOUND(pite)) {
  282. DeleteIfSocket(pite);
  283. if (IF_IS_ENABLED(pite)) {
  284. RemoveEntryList(&pite->ITE_LinkByAddress);
  285. }
  286. RIP_FREE(pite->ITE_Binding);
  287. }
  288. //
  289. // remove it from the list ordered by index
  290. // as well as from the hash table
  291. //
  292. RemoveEntryList(&pite->ITE_LinkByIndex);
  293. RemoveEntryList(&pite->ITE_HTLinkByIndex);
  294. RIP_FREE(pite->ITE_Config);
  295. RIP_FREE(pite);
  296. return NO_ERROR;
  297. }
  298. //----------------------------------------------------------------------------
  299. // Function: ValidateIfConfig
  300. //
  301. // Checks the parameters in an IPRIP_IF_CONFIG structure.
  302. //----------------------------------------------------------------------------
  303. DWORD
  304. ValidateIfConfig(
  305. PIPRIP_IF_CONFIG pic
  306. ) {
  307. CHAR szStr[12];
  308. if (pic->IC_Metric > IPRIP_INFINITE) {
  309. TRACE1(
  310. IF, "Invalid interface metric %d specified",
  311. pic->IC_Metric
  312. );
  313. _ltoa(pic->IC_Metric, szStr, 10);
  314. LOGERR2(
  315. INVALID_IF_CONFIG, "Metric", szStr, ERROR_INVALID_PARAMETER
  316. );
  317. return ERROR_INVALID_PARAMETER;
  318. }
  319. if (pic->IC_UpdateMode != IPRIP_UPDATE_PERIODIC &&
  320. pic->IC_UpdateMode != IPRIP_UPDATE_DEMAND) {
  321. TRACE1(
  322. IF, "Invalid update mode %d specified",
  323. pic->IC_UpdateMode
  324. );
  325. _ltoa(pic->IC_UpdateMode, szStr, 10);
  326. LOGERR2(
  327. INVALID_IF_CONFIG, "Update Mode", szStr,
  328. ERROR_INVALID_PARAMETER
  329. );
  330. return ERROR_INVALID_PARAMETER;
  331. }
  332. if (pic->IC_AcceptMode != IPRIP_ACCEPT_DISABLED &&
  333. pic->IC_AcceptMode != IPRIP_ACCEPT_RIP1 &&
  334. pic->IC_AcceptMode != IPRIP_ACCEPT_RIP1_COMPAT &&
  335. pic->IC_AcceptMode != IPRIP_ACCEPT_RIP2) {
  336. TRACE1(
  337. IF, "Invalid accept mode %d specified",
  338. pic->IC_AcceptMode
  339. );
  340. _ltoa(pic->IC_AcceptMode, szStr, 10);
  341. LOGERR2(
  342. INVALID_IF_CONFIG, "Accept Mode", szStr,
  343. ERROR_INVALID_PARAMETER
  344. );
  345. return ERROR_INVALID_PARAMETER;
  346. }
  347. if (pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED &&
  348. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP1 &&
  349. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP1_COMPAT &&
  350. pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP2) {
  351. TRACE1(
  352. IF, "Invalid announce mode %d specified",
  353. pic->IC_AnnounceMode
  354. );
  355. _ltoa(pic->IC_AnnounceMode, szStr, 10);
  356. LOGERR2(
  357. INVALID_IF_CONFIG, "Announce Mode", szStr,
  358. ERROR_INVALID_PARAMETER
  359. );
  360. return ERROR_INVALID_PARAMETER;
  361. }
  362. if (pic->IC_AuthenticationType != IPRIP_AUTHTYPE_NONE &&
  363. pic->IC_AuthenticationType != IPRIP_AUTHTYPE_SIMPLE_PASSWORD) {
  364. TRACE1(
  365. IF, "Invalid authentication type %d specified",
  366. pic->IC_AuthenticationType
  367. );
  368. _ltoa(pic->IC_AuthenticationType, szStr, 10);
  369. LOGERR2(
  370. INVALID_IF_CONFIG, "Authentication Type", szStr,
  371. ERROR_INVALID_PARAMETER
  372. );
  373. return ERROR_INVALID_PARAMETER;
  374. }
  375. if (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED &&
  376. pic->IC_UnicastPeerMode != IPRIP_PEER_ALSO &&
  377. pic->IC_UnicastPeerMode != IPRIP_PEER_ONLY) {
  378. TRACE1(
  379. IF, "Invalid unicast peer mode %d specified",
  380. pic->IC_UnicastPeerMode
  381. );
  382. _ltoa(pic->IC_UnicastPeerMode, szStr, 10);
  383. LOGERR2(
  384. INVALID_IF_CONFIG, "unicast peer mode", szStr,
  385. ERROR_INVALID_PARAMETER
  386. );
  387. return ERROR_INVALID_PARAMETER;
  388. }
  389. if (pic->IC_AcceptFilterMode != IPRIP_FILTER_DISABLED &&
  390. pic->IC_AcceptFilterMode != IPRIP_FILTER_INCLUDE &&
  391. pic->IC_AcceptFilterMode != IPRIP_FILTER_EXCLUDE) {
  392. TRACE1(
  393. IF, "Invalid accept filter mode %d specified",
  394. pic->IC_AcceptFilterMode
  395. );
  396. _ltoa(pic->IC_AcceptFilterMode, szStr, 10);
  397. LOGERR2(
  398. INVALID_IF_CONFIG, "Accept filter mode", szStr,
  399. ERROR_INVALID_PARAMETER
  400. );
  401. return ERROR_INVALID_PARAMETER;
  402. }
  403. if (pic->IC_AnnounceFilterMode != IPRIP_FILTER_DISABLED &&
  404. pic->IC_AnnounceFilterMode != IPRIP_FILTER_INCLUDE &&
  405. pic->IC_AnnounceFilterMode != IPRIP_FILTER_EXCLUDE) {
  406. TRACE1(
  407. IF, "Invalid announce filter mode %d specified",
  408. pic->IC_AnnounceFilterMode
  409. );
  410. _ltoa(pic->IC_AnnounceFilterMode, szStr, 10);
  411. LOGERR2(
  412. INVALID_IF_CONFIG, "Announce filter mode", szStr,
  413. ERROR_INVALID_PARAMETER
  414. );
  415. return ERROR_INVALID_PARAMETER;
  416. }
  417. return NO_ERROR;
  418. }
  419. //----------------------------------------------------------------------------
  420. // Function: BindIfEntry
  421. //
  422. // Updates the binding information for the specified interface.
  423. // Assumes interface table is locked for writing
  424. //----------------------------------------------------------------------------
  425. DWORD
  426. BindIfEntry(
  427. PIF_TABLE pTable,
  428. DWORD dwIndex,
  429. PIP_ADAPTER_BINDING_INFO pBinding
  430. ) {
  431. DWORD i, j, dwErr = NO_ERROR, dwSize;
  432. PIF_TABLE_ENTRY pite;
  433. PIPRIP_IF_BINDING pib;
  434. PIPRIP_IP_ADDRESS paddr;
  435. PIP_ADAPTER_BINDING_INFO piabi;
  436. BOOL bFound;
  437. pib = NULL;
  438. do {
  439. //
  440. // retrieve the interface entry
  441. //
  442. pite = GetIfByIndex(pTable, dwIndex);
  443. if (pite == NULL) {
  444. dwErr = ERROR_INVALID_PARAMETER;
  445. break;
  446. }
  447. //
  448. // If the interface is already bound, check to see if he is giving
  449. // us a different binding. If he is, then it is an error. Otherwise
  450. // we shall be obliging and not complain too much
  451. //
  452. if (IF_IS_BOUND(pite)) {
  453. TRACE1(IF, "interface %d is already bound", dwIndex);
  454. pib = pite->ITE_Binding;
  455. if(pib->IB_AddrCount != pBinding->AddressCount)
  456. {
  457. TRACE1(IF, "interface %d is bound and has different binding",dwIndex);
  458. dwErr = ERROR_INVALID_PARAMETER;
  459. break;
  460. }
  461. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  462. for(i = 0; i < pBinding->AddressCount; i++)
  463. {
  464. bFound = FALSE;
  465. for(j = 0; j < pib->IB_AddrCount; j++)
  466. {
  467. if((paddr[j].IA_Address == pBinding->Address[i].Address) &&
  468. (paddr[j].IA_Netmask == pBinding->Address[i].Mask))
  469. {
  470. bFound = TRUE;
  471. break;
  472. }
  473. }
  474. if(!bFound)
  475. {
  476. TRACE1(IF,"interface %d is bound and has different binding",dwIndex);
  477. dwErr = ERROR_INVALID_PARAMETER;
  478. break;
  479. }
  480. }
  481. //
  482. // At this time we have dwErr as either NO_ERROR or
  483. // ERROR_INVALID_PARAMETER. Either case we can break here
  484. // since we are done
  485. //
  486. break;
  487. }
  488. //
  489. // make sure there is at least one address
  490. //
  491. if (pBinding->AddressCount == 0) { break; }
  492. dwSize = sizeof(IPRIP_IF_BINDING) +
  493. pBinding->AddressCount * sizeof(IPRIP_IP_ADDRESS);
  494. //
  495. // allocate memory to store the binding
  496. // in our format
  497. //
  498. pib = RIP_ALLOC(dwSize);
  499. if (pib == NULL) {
  500. dwErr = GetLastError();
  501. TRACE3(
  502. IF, "error %d allocating %d bytes for binding on interface %d",
  503. dwErr, dwSize, dwIndex
  504. );
  505. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  506. break;
  507. }
  508. //
  509. // convert the binding into our format
  510. //
  511. pib->IB_AddrCount = pBinding->AddressCount;
  512. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  513. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  514. paddr->IA_Address = pBinding->Address[i].Address;
  515. paddr->IA_Netmask = pBinding->Address[i].Mask;
  516. }
  517. //
  518. // save the binding in the interface entry
  519. //
  520. pite->ITE_Binding = pib;
  521. #if 0
  522. //
  523. // for demand dial interfaces add neighbor
  524. //
  525. if ( pite-> ITE_Type == DEMAND_DIAL ) {
  526. dwErr = AddNeighborToIfConfig( pBinding-> RemoteAddress, pite );
  527. if ( dwErr != NO_ERROR ) { break ; }
  528. }
  529. #endif
  530. //
  531. // create sockets for interface's addresses
  532. //
  533. dwErr = CreateIfSocket(pite);
  534. if (dwErr != NO_ERROR) {
  535. TRACE2(
  536. IF, "error %d creating sockets for interface %d", dwErr, dwIndex
  537. );
  538. break;
  539. }
  540. //
  541. // mark the interface as being bound
  542. //
  543. pite->ITE_Flags |= ITEFLAG_BOUND;
  544. //
  545. // we save the binding information in a private table
  546. // so it can be quickly accessed and searched when we are
  547. // trying to guess subnet masks given IP addresses;
  548. //
  549. ACQUIRE_BINDING_LOCK_EXCLUSIVE();
  550. dwErr = CreateBindingEntry(ig.IG_BindingTable, pib);
  551. RELEASE_BINDING_LOCK_EXCLUSIVE();
  552. //
  553. // if interface is also enabled, it is now active
  554. // so queue activation work-item
  555. //
  556. if (IF_IS_ENABLED(pite)) {
  557. //
  558. // place interface on the list of active interfaces
  559. //
  560. dwErr = InsertIfByAddress(pTable, pite);
  561. if (dwErr != NO_ERROR) {
  562. TRACE2(
  563. IF, "error %d inserting interface %d in active list",
  564. dwErr, dwIndex
  565. );
  566. pite->ITE_Flags &= ~ITEFLAG_BOUND;
  567. DeleteIfSocket(pite);
  568. break;
  569. }
  570. //
  571. // queue the work-item to send initial request
  572. //
  573. dwErr = QueueRipWorker(
  574. WorkerFunctionActivateInterface, (PVOID)UlongToPtr(dwIndex)
  575. );
  576. if (dwErr != NO_ERROR) {
  577. TRACE2(
  578. IF, "error %d queuing work-item for interface %d",
  579. dwErr, dwIndex
  580. );
  581. LOGERR0(QUEUE_WORKER_FAILED, dwErr);
  582. RemoveEntryList(&pite->ITE_LinkByAddress);
  583. pite->ITE_Flags &= ~ITEFLAG_BOUND;
  584. DeleteIfSocket(pite);
  585. break;
  586. }
  587. }
  588. } while(FALSE);
  589. if (dwErr != NO_ERROR) {
  590. if (pib) { RIP_FREE(pib); }
  591. if (pite) { pite->ITE_Binding = NULL; }
  592. }
  593. return dwErr;
  594. }
  595. //----------------------------------------------------------------------------
  596. // Function: UnBindIfEntry
  597. //
  598. // removes the binding for the specified interface.
  599. // assumes the interface table is locked for writing.
  600. //----------------------------------------------------------------------------
  601. DWORD
  602. UnBindIfEntry(
  603. PIF_TABLE pTable,
  604. DWORD dwIndex
  605. ) {
  606. DWORD dwErr;
  607. PIF_TABLE_ENTRY pite;
  608. do {
  609. //
  610. // retrieve the interface specified
  611. //
  612. pite = GetIfByIndex(pTable, dwIndex);
  613. if (pite == NULL) {
  614. dwErr = ERROR_INVALID_PARAMETER;
  615. break;
  616. }
  617. //
  618. // quit if the interface is already unbound
  619. //
  620. if (IF_IS_UNBOUND(pite)) {
  621. dwErr = ERROR_INVALID_PARAMETER;
  622. TRACE1(
  623. IF, "interface %d is already unbound", dwIndex
  624. );
  625. break;
  626. }
  627. //
  628. // clear the "bound" flag
  629. //
  630. pite->ITE_Flags &= ~ITEFLAG_BOUND;
  631. //
  632. // if the interface isn't enabled, close the socket for the interface;
  633. // if the interface is enabled, that means it was active
  634. // and we must queue the deactivation work-item
  635. //
  636. if (!IF_IS_ENABLED(pite)) {
  637. DeleteIfSocket(pite);
  638. ACQUIRE_BINDING_LOCK_EXCLUSIVE();
  639. dwErr = DeleteBindingEntry(ig.IG_BindingTable, pite->ITE_Binding);
  640. RELEASE_BINDING_LOCK_EXCLUSIVE();
  641. RIP_FREE(pite->ITE_Binding);
  642. pite->ITE_Binding = NULL;
  643. }
  644. else {
  645. //
  646. // the interface was active, so deactivate it
  647. //
  648. // remove from active list
  649. //
  650. RemoveEntryList(&pite->ITE_LinkByAddress);
  651. WorkerFunctionDeactivateInterface( (PVOID)UlongToPtr(dwIndex));
  652. //
  653. // close the socket ourselves if required
  654. //
  655. if ( pite-> ITE_Binding ) {
  656. DeleteIfSocket(pite);
  657. ACQUIRE_BINDING_LOCK_EXCLUSIVE();
  658. dwErr = DeleteBindingEntry(
  659. ig.IG_BindingTable, pite->ITE_Binding
  660. );
  661. RELEASE_BINDING_LOCK_EXCLUSIVE();
  662. RIP_FREE(pite->ITE_Binding);
  663. pite->ITE_Binding = NULL;
  664. }
  665. else {
  666. dwErr = NO_ERROR;
  667. }
  668. }
  669. } while(FALSE);
  670. return dwErr;
  671. }
  672. //----------------------------------------------------------------------------
  673. // Function: EnableIfEntry
  674. //
  675. // configures an interface for RIP activity, including setting up
  676. // a socket and linking the interface into the list ordered by address.
  677. // this assumes the table is locked for writing
  678. //----------------------------------------------------------------------------
  679. DWORD
  680. EnableIfEntry(
  681. PIF_TABLE pTable,
  682. DWORD dwIndex
  683. ) {
  684. DWORD dwErr;
  685. PLIST_ENTRY ple, phead;
  686. PIF_TABLE_ENTRY pite;
  687. do {
  688. //
  689. // retrieve the interface
  690. //
  691. pite = GetIfByIndex(pTable, dwIndex);
  692. if (pite == NULL) {
  693. TRACE1(IF, "could not find interface %d",dwIndex);
  694. dwErr = ERROR_INVALID_PARAMETER;
  695. break;
  696. }
  697. //
  698. // quit if the interface is already enabled
  699. //
  700. if (IF_IS_ENABLED(pite)) {
  701. TRACE1(IF, "interface %d is already enabled", dwIndex);
  702. dwErr = NO_ERROR;
  703. break;
  704. }
  705. pite->ITE_Flags |= ITEFLAG_ENABLED;
  706. //
  707. // if interface is already bound, it is now active,
  708. // so queue the interface activation work-item
  709. //
  710. if (IF_IS_BOUND(pite)) {
  711. //
  712. // place interface on the list of active interfaces
  713. //
  714. dwErr = InsertIfByAddress(pTable, pite);
  715. if (dwErr != NO_ERROR) {
  716. TRACE2(
  717. IF, "error %d inserting interface %d in active list",
  718. dwErr, dwIndex
  719. );
  720. pite->ITE_Flags &= ~ITEFLAG_ENABLED;
  721. break;
  722. }
  723. //
  724. // queue the work-item to send initial request
  725. //
  726. dwErr = QueueRipWorker(
  727. WorkerFunctionActivateInterface, (PVOID)UlongToPtr(dwIndex)
  728. );
  729. if (dwErr != NO_ERROR) {
  730. TRACE2(
  731. IF, "error %d queuing work-item for interface %d",
  732. dwErr, dwIndex
  733. );
  734. LOGERR0(QUEUE_WORKER_FAILED, dwErr);
  735. RemoveEntryList(&pite->ITE_LinkByAddress);
  736. pite->ITE_Flags &= ~ITEFLAG_ENABLED;
  737. break;
  738. }
  739. }
  740. dwErr = NO_ERROR;
  741. } while(FALSE);
  742. return dwErr;
  743. }
  744. //----------------------------------------------------------------------------
  745. // Function: ConfigureIfEntry
  746. //
  747. // modifies the configuration for an already-existing interface
  748. // this assumes the table is locked for writing
  749. //----------------------------------------------------------------------------
  750. DWORD
  751. ConfigureIfEntry(
  752. PIF_TABLE pTable,
  753. DWORD dwIndex,
  754. PIPRIP_IF_CONFIG pConfig
  755. ) {
  756. DWORD dwErr, dwSize;
  757. PIF_TABLE_ENTRY pite;
  758. PIPRIP_IF_CONFIG picsrc, picdst;
  759. dwErr = NO_ERROR;
  760. do {
  761. //
  762. // retrieve the interface to be configured
  763. //
  764. pite = GetIfByIndex(pTable, dwIndex);
  765. if (pite == NULL) {
  766. TRACE1(IF, "could not find interface %d", dwIndex);
  767. dwErr = ERROR_INVALID_PARAMETER;
  768. break;
  769. }
  770. //
  771. // get the size of the new configuration
  772. //
  773. picsrc = (PIPRIP_IF_CONFIG)pConfig;
  774. dwSize = IPRIP_IF_CONFIG_SIZE(picsrc);
  775. //
  776. // validate the new configuration
  777. //
  778. dwErr = ValidateIfConfig(picsrc);
  779. if (dwErr != NO_ERROR) {
  780. TRACE1(IF, "invalid config specified for interface %d", dwIndex);
  781. break;
  782. }
  783. //
  784. // allocate space to hold the new configuration
  785. //
  786. picdst = RIP_ALLOC(dwSize);
  787. if (picdst == NULL) {
  788. dwErr = GetLastError();
  789. TRACE3(
  790. IF, "error %d allocating %d bytes for interface %d config",
  791. dwErr, dwSize, dwIndex
  792. );
  793. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  794. break;
  795. }
  796. //
  797. // copy the new configuration, and free the old one
  798. //
  799. CopyMemory(picdst, picsrc, dwSize);
  800. if (pite->ITE_Config != NULL) { RIP_FREE(pite->ITE_Config); }
  801. pite->ITE_Config = picdst;
  802. //
  803. // if the interface is bound, re-initialize the interface
  804. //
  805. if (IF_IS_BOUND(pite)) {
  806. //
  807. // close the sockets and set them up again
  808. //
  809. dwErr = DeleteIfSocket(pite);
  810. dwErr = CreateIfSocket(pite);
  811. if (dwErr != NO_ERROR) {
  812. TRACE2(
  813. IF, "error %d creating sockets for interface %d",
  814. dwErr, dwIndex
  815. );
  816. break;
  817. }
  818. //
  819. // re-activate the interface if it is active
  820. //
  821. if (IF_IS_ENABLED(pite)) {
  822. //
  823. // queue the work-item to activate the interface
  824. //
  825. dwErr = QueueRipWorker(
  826. WorkerFunctionActivateInterface, (PVOID)UlongToPtr(dwIndex)
  827. );
  828. if (dwErr != NO_ERROR) {
  829. TRACE2(
  830. IF, "error %d queueing work-item for interface %d",
  831. dwErr, dwIndex
  832. );
  833. LOGERR0(QUEUE_WORKER_FAILED, dwErr);
  834. break;
  835. }
  836. }
  837. }
  838. dwErr = NO_ERROR;
  839. } while(FALSE);
  840. return dwErr;
  841. }
  842. //----------------------------------------------------------------------------
  843. // Function: DisableIfEntry
  844. //
  845. // stops RIP activity on an interface, removing the interface
  846. // from the list of interfaces ordered by address.
  847. // this assumes the table is locked for writing
  848. //----------------------------------------------------------------------------
  849. DWORD
  850. DisableIfEntry(
  851. PIF_TABLE pTable,
  852. DWORD dwIndex
  853. ) {
  854. DWORD dwErr;
  855. PIF_TABLE_ENTRY pite;
  856. do {
  857. //
  858. // retrieve the interface to be disabled
  859. //
  860. pite = GetIfByIndex(pTable, dwIndex);
  861. if (pite == NULL) {
  862. TRACE1(IF, "could not find interface %d", dwIndex);
  863. dwErr = ERROR_INVALID_PARAMETER;
  864. break;
  865. }
  866. //
  867. // quit if already disabled
  868. //
  869. if (IF_IS_DISABLED(pite)) {
  870. TRACE1(IF, "interface %d is already disabled", dwIndex);
  871. dwErr = ERROR_INVALID_PARAMETER;
  872. break;
  873. }
  874. //
  875. // clear the enabled flag
  876. //
  877. pite->ITE_Flags &= ~ITEFLAG_ENABLED;
  878. //
  879. // if this interface was not bound, clearing the flag is enough;
  880. // if the interface was bound (and therefore active),
  881. // deactivate it here
  882. //
  883. if (IF_IS_BOUND(pite)) {
  884. //
  885. // remove from active list
  886. //
  887. RemoveEntryList(&pite->ITE_LinkByAddress);
  888. //
  889. // execute the work-item to send final updates
  890. //
  891. WorkerFunctionDeactivateInterface( (PVOID) UlongToPtr(dwIndex) );
  892. }
  893. dwErr = NO_ERROR;
  894. } while(FALSE);
  895. return dwErr;
  896. }
  897. //----------------------------------------------------------------------------
  898. // Function: CreateIfSocket
  899. //
  900. // creates sockets for an interface, setting it up according to
  901. // the configuration including in the interface control block.
  902. // this assumes the table containing the interface is locked for writing
  903. //----------------------------------------------------------------------------
  904. DWORD
  905. CreateIfSocket(
  906. PIF_TABLE_ENTRY pite
  907. ) {
  908. SOCKADDR_IN sinsock;
  909. PIPRIP_IF_CONFIG pic;
  910. PIPRIP_IF_BINDING pib;
  911. PIPRIP_IP_ADDRESS paddr;
  912. DWORD i, dwErr, dwOption, dwIndex;
  913. LPSTR lpszAddr;
  914. pic = pite->ITE_Config;
  915. pib = pite->ITE_Binding;
  916. dwIndex = pite->ITE_Index;
  917. //
  918. // allocate an array of sockets
  919. //
  920. pite->ITE_Sockets = RIP_ALLOC(pib->IB_AddrCount * sizeof(SOCKET));
  921. if (pite->ITE_Sockets == NULL) {
  922. dwErr = GetLastError();
  923. TRACE3(
  924. IF, "error %d allocating %d bytes for interface %d sockets",
  925. dwErr, pib->IB_AddrCount * sizeof(SOCKET), dwIndex
  926. );
  927. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  928. return dwErr;
  929. }
  930. //
  931. // initialize the array of sockets
  932. //
  933. for (i = 0; i < pib->IB_AddrCount; i++) {
  934. pite->ITE_Sockets[i] = INVALID_SOCKET;
  935. }
  936. //
  937. // create sockets for each address in the binding
  938. //
  939. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  940. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  941. //
  942. // create the socket
  943. //
  944. pite->ITE_Sockets[i] = WSASocket(
  945. AF_INET, SOCK_DGRAM, 0, NULL, 0, 0
  946. );
  947. if (pite->ITE_Sockets[i] == INVALID_SOCKET) {
  948. dwErr = WSAGetLastError();
  949. lpszAddr = INET_NTOA(paddr->IA_Address);
  950. if (lpszAddr != NULL) {
  951. TRACE3(
  952. IF, "error %d creating socket for interface %d (%s)",
  953. dwErr, dwIndex, lpszAddr
  954. );
  955. LOGERR1(CREATE_SOCKET_FAILED_2, lpszAddr, dwErr);
  956. }
  957. break;
  958. }
  959. //
  960. // try to allow re-use of this address
  961. //
  962. dwOption = 1;
  963. dwErr = setsockopt(
  964. pite->ITE_Sockets[i], SOL_SOCKET, SO_REUSEADDR,
  965. (PBYTE)&dwOption, sizeof(dwOption)
  966. );
  967. if (dwErr == SOCKET_ERROR) {
  968. dwErr = WSAGetLastError();
  969. lpszAddr = INET_NTOA(paddr->IA_Address);
  970. if (lpszAddr != NULL) {
  971. TRACE3(
  972. IF, "error %d setting re-use flag for interface %d (%s)",
  973. dwErr, dwIndex, INET_NTOA(paddr->IA_Address)
  974. );
  975. }
  976. }
  977. //
  978. // enable broadcasting if not exclusively RIP2 mode,
  979. // or if there are any unicast peers configured
  980. //
  981. if (pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1 ||
  982. pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1_COMPAT ||
  983. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1 ||
  984. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1_COMPAT ||
  985. (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED &&
  986. pic->IC_UnicastPeerCount != 0)) {
  987. //
  988. // make sure broadcasting is enabled for this socket
  989. //
  990. dwOption = 1;
  991. dwErr = setsockopt(
  992. pite->ITE_Sockets[i], SOL_SOCKET, SO_BROADCAST,
  993. (PBYTE)&dwOption, sizeof(dwOption)
  994. );
  995. if (dwErr == SOCKET_ERROR) {
  996. dwErr = WSAGetLastError();
  997. lpszAddr = INET_NTOA(paddr->IA_Address);
  998. if (lpszAddr != NULL) {
  999. TRACE3(
  1000. IF, "error %d enabling broadcast on interface %d (%s)",
  1001. dwErr, dwIndex, lpszAddr
  1002. );
  1003. LOGERR1(ENABLE_BROADCAST_FAILED, lpszAddr, dwErr);
  1004. }
  1005. break;
  1006. }
  1007. }
  1008. //
  1009. // bind the socket to the RIP port
  1010. //
  1011. sinsock.sin_family = AF_INET;
  1012. sinsock.sin_port = htons(IPRIP_PORT);
  1013. sinsock.sin_addr.s_addr = paddr->IA_Address;
  1014. dwErr = bind(
  1015. pite->ITE_Sockets[i], (LPSOCKADDR)&sinsock,
  1016. sizeof(SOCKADDR_IN)
  1017. );
  1018. if (dwErr == SOCKET_ERROR) {
  1019. dwErr = WSAGetLastError();
  1020. lpszAddr = INET_NTOA(paddr->IA_Address);
  1021. if (lpszAddr != NULL) {
  1022. TRACE3(
  1023. IF, "error %d binding on socket for interface %d (%s)",
  1024. dwErr, dwIndex, lpszAddr
  1025. );
  1026. LOGERR1(BIND_FAILED, lpszAddr, dwErr);
  1027. }
  1028. break;
  1029. }
  1030. //
  1031. // enable multicasting if not exclusively RIP1/RIP1-compatible mode
  1032. //
  1033. if (pic->IC_AcceptMode == IPRIP_ACCEPT_RIP2 ||
  1034. pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1_COMPAT ||
  1035. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP2) {
  1036. struct ip_mreq imOption;
  1037. //
  1038. // set the interface from which multicasts must be sent
  1039. //
  1040. sinsock.sin_addr.s_addr = paddr->IA_Address;
  1041. dwErr = setsockopt(
  1042. pite->ITE_Sockets[i], IPPROTO_IP, IP_MULTICAST_IF,
  1043. (PBYTE)&sinsock.sin_addr, sizeof(IN_ADDR)
  1044. );
  1045. if (dwErr == SOCKET_ERROR) {
  1046. dwErr = WSAGetLastError();
  1047. lpszAddr = INET_NTOA(paddr->IA_Address);
  1048. if (lpszAddr != NULL) {
  1049. TRACE3(
  1050. IF, "error %d setting interface %d (%s) as multicast",
  1051. dwErr, dwIndex, lpszAddr
  1052. );
  1053. LOGERR1(SET_MCAST_IF_FAILED, lpszAddr, dwErr);
  1054. }
  1055. break;
  1056. }
  1057. //
  1058. // join the IPRIP multicast group
  1059. //
  1060. imOption.imr_multiaddr.s_addr = IPRIP_MULTIADDR;
  1061. imOption.imr_interface.s_addr = paddr->IA_Address;
  1062. dwErr = setsockopt(
  1063. pite->ITE_Sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP,
  1064. (PBYTE)&imOption, sizeof(imOption)
  1065. );
  1066. if (dwErr == SOCKET_ERROR) {
  1067. dwErr = WSAGetLastError();
  1068. lpszAddr = INET_NTOA(paddr->IA_Address);
  1069. if (lpszAddr != NULL) {
  1070. TRACE3(
  1071. IF, "error %d enabling multicast on interface %d (%s)",
  1072. dwErr, dwIndex, lpszAddr
  1073. );
  1074. LOGERR1(JOIN_GROUP_FAILED, lpszAddr, dwErr);
  1075. }
  1076. break;
  1077. }
  1078. }
  1079. dwErr = NO_ERROR;
  1080. }
  1081. if (i < pib->IB_AddrCount) {
  1082. //
  1083. // something failed if we are here
  1084. //
  1085. DeleteIfSocket(pite);
  1086. }
  1087. return dwErr;
  1088. }
  1089. //----------------------------------------------------------------------------
  1090. // Function: DeleteIfSocket
  1091. //
  1092. // closes the sockets used by an interface, if any.
  1093. // assumes that the interface is active, and that the interface table
  1094. // is locked for writing
  1095. //----------------------------------------------------------------------------
  1096. DWORD
  1097. DeleteIfSocket(
  1098. PIF_TABLE_ENTRY pite
  1099. ) {
  1100. DWORD i;
  1101. for (i = 0; i < pite->ITE_Binding->IB_AddrCount; i++) {
  1102. if (pite->ITE_Sockets[i] != INVALID_SOCKET) {
  1103. if (closesocket(pite->ITE_Sockets[i]) == SOCKET_ERROR) {
  1104. TRACE1(IF, "error %d closing socket", WSAGetLastError());
  1105. }
  1106. pite->ITE_Sockets[i] = INVALID_SOCKET;
  1107. }
  1108. }
  1109. RIP_FREE(pite->ITE_Sockets);
  1110. pite->ITE_Sockets = NULL;
  1111. return NO_ERROR;
  1112. }
  1113. //----------------------------------------------------------------------------
  1114. // Function: GetIfByIndex
  1115. //
  1116. // returns the interface with the given index.
  1117. // assumes the table is locked for reading or writing
  1118. //----------------------------------------------------------------------------
  1119. PIF_TABLE_ENTRY
  1120. GetIfByIndex(
  1121. PIF_TABLE pTable,
  1122. DWORD dwIndex
  1123. ) {
  1124. PIF_TABLE_ENTRY pite = NULL;
  1125. PLIST_ENTRY phead, ple;
  1126. phead = pTable->IT_HashTableByIndex + IF_HASHVALUE(dwIndex);
  1127. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  1128. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_HTLinkByIndex);
  1129. if (pite->ITE_Index == dwIndex) {
  1130. break;
  1131. }
  1132. }
  1133. if (ple == phead) { return NULL; }
  1134. else { return pite; }
  1135. }
  1136. //----------------------------------------------------------------------------
  1137. // Function: GetIfByAddress
  1138. //
  1139. // returns the interface bound to the given address.
  1140. // assumes the table is locked for reading or writing
  1141. //----------------------------------------------------------------------------
  1142. PIF_TABLE_ENTRY
  1143. GetIfByAddress(
  1144. PIF_TABLE pTable,
  1145. DWORD dwAddress,
  1146. DWORD dwGetMode,
  1147. PDWORD pdwErr
  1148. ) {
  1149. DWORD i;
  1150. PIPRIP_IF_BINDING pib;
  1151. PLIST_ENTRY phead, pfl;
  1152. PIPRIP_IP_ADDRESS paddr;
  1153. PIF_TABLE_ENTRY pite, piterec;
  1154. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  1155. phead = &pTable->IT_ListByAddress;
  1156. pite = NULL;
  1157. //
  1158. // return record at head of list if mode is GetFirst
  1159. //
  1160. if (dwGetMode == GETMODE_FIRST) {
  1161. if (phead->Flink == phead) {
  1162. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1163. return NULL;
  1164. }
  1165. else {
  1166. pfl = phead->Flink;
  1167. return CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1168. }
  1169. }
  1170. //
  1171. // search for the entry
  1172. //
  1173. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1174. piterec = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1175. pib = piterec->ITE_Binding;
  1176. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  1177. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  1178. if (dwAddress == paddr->IA_Address) { pite = piterec; break; }
  1179. }
  1180. if (pite) { break; }
  1181. }
  1182. //
  1183. // return record after the one found if mode is GetNext
  1184. //
  1185. if (dwGetMode == GETMODE_NEXT && pite != NULL) {
  1186. pfl = &pite->ITE_LinkByAddress;
  1187. //
  1188. // if entry found is last one, return NULL,
  1189. // otherwise, return the following entry
  1190. //
  1191. if (pfl->Flink == phead) {
  1192. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1193. pite = NULL;
  1194. }
  1195. else {
  1196. pfl = pfl->Flink;
  1197. pite = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1198. }
  1199. }
  1200. //
  1201. // if the interface wasn't found, this will still be NULL
  1202. //
  1203. return pite;
  1204. }
  1205. //----------------------------------------------------------------------------
  1206. // Function: GetIfByListIndex
  1207. //
  1208. // This function is similar to GetIfByAddress in that it supports
  1209. // three modes of retrieval, but it is different in that it looks
  1210. // in the list of interfaces sorted by index.
  1211. //----------------------------------------------------------------------------
  1212. PIF_TABLE_ENTRY
  1213. GetIfByListIndex(
  1214. PIF_TABLE pTable,
  1215. DWORD dwIndex,
  1216. DWORD dwGetMode,
  1217. PDWORD pdwErr
  1218. ) {
  1219. PIF_TABLE_ENTRY pite;
  1220. PLIST_ENTRY ple, phead;
  1221. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  1222. phead = &pTable->IT_ListByIndex;
  1223. pite = NULL;
  1224. //
  1225. // return record at head of list if mode is GETMODE_FIRST;
  1226. // if list is empty, return NULL.
  1227. //
  1228. if (dwGetMode == GETMODE_FIRST) {
  1229. if (phead->Flink == phead) {
  1230. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1231. return NULL;
  1232. }
  1233. else {
  1234. ple = phead->Flink;
  1235. return CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  1236. }
  1237. }
  1238. //
  1239. // get the entry requested
  1240. //
  1241. pite = GetIfByIndex(pTable, dwIndex);
  1242. //
  1243. // if mode is GETMODE_NEXT, return the item after the one retrieved
  1244. //
  1245. if (dwGetMode == GETMODE_NEXT && pite != NULL) {
  1246. ple = &pite->ITE_LinkByIndex;
  1247. //
  1248. // if entry found is last one, return NULL,
  1249. // otherwise return the following entry
  1250. //
  1251. if (ple->Flink == phead) {
  1252. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1253. pite = NULL;
  1254. }
  1255. else {
  1256. ple = ple->Flink;
  1257. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  1258. }
  1259. }
  1260. return pite;
  1261. }
  1262. //----------------------------------------------------------------------------
  1263. // Function: InsertIfByAddress
  1264. //
  1265. // inserts the given interface into the list of interfaces sorted by address.
  1266. // assumes the table is locked for writing
  1267. //----------------------------------------------------------------------------
  1268. DWORD
  1269. InsertIfByAddress(
  1270. PIF_TABLE pTable,
  1271. PIF_TABLE_ENTRY pITE
  1272. ) {
  1273. INT cmp;
  1274. PIF_TABLE_ENTRY pite;
  1275. PIPRIP_IP_ADDRESS paddr;
  1276. DWORD dwAddress, dwITEAddress;
  1277. PLIST_ENTRY phead, pfl;
  1278. phead = &pTable->IT_ListByAddress;
  1279. paddr = IPRIP_IF_ADDRESS_TABLE(pITE->ITE_Binding);
  1280. dwAddress = paddr->IA_Address;
  1281. //
  1282. // search for the insertion point
  1283. //
  1284. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1285. pite = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1286. paddr = IPRIP_IF_ADDRESS_TABLE(pite->ITE_Binding);
  1287. dwITEAddress = paddr->IA_Address;
  1288. if (INET_CMP(dwAddress, dwITEAddress, cmp) < 0) { break; }
  1289. else if (cmp == 0) { return ERROR_ALREADY_EXISTS; }
  1290. }
  1291. InsertTailList(pfl, &pITE->ITE_LinkByAddress);
  1292. return NO_ERROR;
  1293. }
  1294. //----------------------------------------------------------------------------
  1295. // Function: AddNeighborToIfConfig
  1296. //
  1297. // Adds a unicast neighbor to an interface config block.
  1298. //----------------------------------------------------------------------------
  1299. DWORD
  1300. AddNeighborToIfConfig(
  1301. DWORD dwRemoteAddress,
  1302. PIF_TABLE_ENTRY pite
  1303. ) {
  1304. BOOL bFound = FALSE;
  1305. DWORD dwErr = (DWORD) -1,
  1306. dwSize = 0,
  1307. dwCnt = 0;
  1308. PDWORD pdwAddr = NULL;
  1309. PIPRIP_IF_CONFIG pic = NULL,
  1310. picNew = NULL;
  1311. do
  1312. {
  1313. pic = pite-> ITE_Config;
  1314. //
  1315. // verify neighbor is not aready present
  1316. //
  1317. pdwAddr = IPRIP_IF_UNICAST_PEER_TABLE( pic );
  1318. for ( dwCnt = 0; dwCnt < pic-> IC_UnicastPeerCount; dwCnt++ )
  1319. {
  1320. if ( dwRemoteAddress == pdwAddr[ dwCnt ] )
  1321. {
  1322. bFound = TRUE;
  1323. break;
  1324. }
  1325. }
  1326. //
  1327. // entry exits, enable unicast peer mode and quit
  1328. //
  1329. if ( bFound )
  1330. {
  1331. LPSTR lpszAddr = INET_NTOA( dwRemoteAddress );
  1332. pic-> IC_UnicastPeerMode = IPRIP_PEER_ALSO;
  1333. dwErr = NO_ERROR;
  1334. if (lpszAddr != NULL) {
  1335. TRACE2(
  1336. IF,
  1337. "Unicast neighbor %s already present in configuration on interface %d",
  1338. lpszAddr, pite-> ITE_Index
  1339. );
  1340. }
  1341. break;
  1342. }
  1343. //
  1344. // allocate new config block
  1345. //
  1346. dwSize = IPRIP_IF_CONFIG_SIZE( pic ) + sizeof( DWORD );
  1347. picNew = RIP_ALLOC( dwSize );
  1348. if ( picNew == NULL )
  1349. {
  1350. dwErr = GetLastError();
  1351. TRACE3(
  1352. IF, "error %d allocating %d bytes for configuration on interface %d",
  1353. dwErr, dwSize, pite-> ITE_Index
  1354. );
  1355. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1356. break;
  1357. }
  1358. //
  1359. // copy base structure
  1360. //
  1361. CopyMemory( picNew, pic, sizeof( IPRIP_IF_CONFIG ) );
  1362. //
  1363. // copy uicast peer table
  1364. //
  1365. CopyMemory(
  1366. IPRIP_IF_UNICAST_PEER_TABLE( picNew ),
  1367. IPRIP_IF_UNICAST_PEER_TABLE( pic ),
  1368. pic-> IC_UnicastPeerCount * sizeof( DWORD )
  1369. );
  1370. //
  1371. // add new neighbor and set unicast neighbor mode
  1372. //
  1373. pdwAddr = IPRIP_IF_UNICAST_PEER_TABLE( picNew );
  1374. pdwAddr[ picNew-> IC_UnicastPeerCount++ ] = dwRemoteAddress;
  1375. picNew-> IC_UnicastPeerMode = IPRIP_PEER_ALSO;
  1376. //
  1377. // Copy accept and annouce filters
  1378. //
  1379. CopyMemory(
  1380. IPRIP_IF_ACCEPT_FILTER_TABLE( picNew ),
  1381. IPRIP_IF_ACCEPT_FILTER_TABLE( pic ),
  1382. pic-> IC_AcceptFilterCount * sizeof( IPRIP_IP_ADDRESS )
  1383. );
  1384. CopyMemory(
  1385. IPRIP_IF_ANNOUNCE_FILTER_TABLE( picNew ),
  1386. IPRIP_IF_ANNOUNCE_FILTER_TABLE( pic ),
  1387. pic-> IC_AnnounceFilterCount * sizeof( IPRIP_IP_ADDRESS )
  1388. );
  1389. //
  1390. // save the new config
  1391. //
  1392. pite-> ITE_Config = picNew;
  1393. RIP_FREE( pic );
  1394. dwErr = NO_ERROR;
  1395. } while ( FALSE );
  1396. return dwErr;
  1397. }
  1398. //----------------------------------------------------------------------------
  1399. // Function: CreatePeerTable
  1400. //
  1401. // initializes the given peer table
  1402. //----------------------------------------------------------------------------
  1403. DWORD
  1404. CreatePeerTable(
  1405. PPEER_TABLE pTable
  1406. ) {
  1407. DWORD dwErr;
  1408. PLIST_ENTRY ple, plstart, plend;
  1409. //
  1410. // initialize the hash table of peers
  1411. //
  1412. plstart = pTable->PT_HashTableByAddress;
  1413. plend = plstart + PEER_HASHTABLE_SIZE;
  1414. for (ple = plstart; ple < plend; ple++) {
  1415. InitializeListHead(ple);
  1416. }
  1417. //
  1418. // initialize the list of peers ordered by address
  1419. //
  1420. InitializeListHead(&pTable->PT_ListByAddress);
  1421. //
  1422. // initialize the multiple-read/single-write synchronization object
  1423. //
  1424. dwErr = CreateReadWriteLock(&pTable->PT_RWL);
  1425. if (dwErr == NO_ERROR) {
  1426. pTable->PT_Created = 0x12345678;
  1427. }
  1428. return dwErr;
  1429. }
  1430. //----------------------------------------------------------------------------
  1431. // Function: DeletePeerTable
  1432. //
  1433. // frees the resources used by the given peer table
  1434. // assumes the table is locked for writing
  1435. //----------------------------------------------------------------------------
  1436. DWORD
  1437. DeletePeerTable(
  1438. PPEER_TABLE pTable
  1439. ) {
  1440. PLIST_ENTRY ple, phead;
  1441. PPEER_TABLE_ENTRY ppte;
  1442. //
  1443. // empty the hash table of peer stats structures
  1444. //
  1445. phead = &pTable->PT_ListByAddress;
  1446. while (!IsListEmpty(phead)) {
  1447. ple = RemoveHeadList(phead);
  1448. ppte = CONTAINING_RECORD(ple, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1449. RIP_FREE(ppte);
  1450. }
  1451. //
  1452. // delete the table's synchronization object
  1453. //
  1454. DeleteReadWriteLock(&pTable->PT_RWL);
  1455. pTable->PT_Created = 0;
  1456. return NO_ERROR;
  1457. }
  1458. //----------------------------------------------------------------------------
  1459. // Function: CreatePeerEntry
  1460. //
  1461. // creates an entry in the given table for a peer with the given address
  1462. // assumes the table is locked for writing
  1463. //----------------------------------------------------------------------------
  1464. DWORD
  1465. CreatePeerEntry(
  1466. PPEER_TABLE pTable,
  1467. DWORD dwAddress,
  1468. PPEER_TABLE_ENTRY *ppEntry
  1469. ) {
  1470. DWORD dwErr;
  1471. PLIST_ENTRY ple, phead;
  1472. PPEER_TABLE_ENTRY ppte;
  1473. if (ppEntry != NULL) { *ppEntry = NULL; }
  1474. //
  1475. // make sure the entry does not already exist
  1476. //
  1477. ppte = GetPeerByAddress(pTable, dwAddress, GETMODE_EXACT, NULL);
  1478. if (ppte != NULL) {
  1479. if (ppEntry != NULL) { *ppEntry = ppte; }
  1480. return NO_ERROR;
  1481. }
  1482. //
  1483. // allocate memory for the new peer entry
  1484. //
  1485. ppte = RIP_ALLOC(sizeof(PEER_TABLE_ENTRY));
  1486. if (ppte == NULL) {
  1487. LPSTR lpszAddr = INET_NTOA(dwAddress);
  1488. dwErr = GetLastError();
  1489. if (lpszAddr != NULL) {
  1490. TRACE3(
  1491. IF, "error %d allocating %d bytes for peer %s entry",
  1492. dwErr, sizeof(PEER_TABLE_ENTRY), lpszAddr
  1493. );
  1494. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1495. }
  1496. return dwErr;
  1497. }
  1498. //
  1499. // initialize the fields
  1500. //
  1501. ppte->PTE_Address = dwAddress;
  1502. ZeroMemory(&ppte->PTE_Stats, sizeof(IPRIP_PEER_STATS));
  1503. //
  1504. // insert the peer stats entry in the hash table
  1505. //
  1506. phead = pTable->PT_HashTableByAddress + PEER_HASHVALUE(dwAddress);
  1507. InsertHeadList(phead, &ppte->PTE_HTLinkByAddress);
  1508. //
  1509. // insert the entry in the list sorted by address
  1510. //
  1511. dwErr = InsertPeerByAddress(pTable, ppte);
  1512. if (ppEntry != NULL) { *ppEntry = ppte; }
  1513. return NO_ERROR;
  1514. }
  1515. //----------------------------------------------------------------------------
  1516. // Function: DeletePeerEntry
  1517. //
  1518. // deletes the entry for the peer with the given address
  1519. // assumes the table is locked for writing
  1520. //----------------------------------------------------------------------------
  1521. DWORD
  1522. DeletePeerEntry(
  1523. PPEER_TABLE pTable,
  1524. DWORD dwAddress
  1525. ) {
  1526. PPEER_TABLE_ENTRY ppte;
  1527. //
  1528. // quit if the entry cannot be found
  1529. //
  1530. ppte = GetPeerByAddress(pTable, dwAddress, GETMODE_EXACT, NULL);
  1531. if (ppte == NULL) { return ERROR_INVALID_PARAMETER; }
  1532. //
  1533. // remove the entry from the hash-table
  1534. // and from the list sorted by address
  1535. //
  1536. RemoveEntryList(&ppte->PTE_LinkByAddress);
  1537. RemoveEntryList(&ppte->PTE_HTLinkByAddress);
  1538. RIP_FREE(ppte);
  1539. return NO_ERROR;
  1540. }
  1541. //----------------------------------------------------------------------------
  1542. // Function: GetPeerByAddress
  1543. //
  1544. // returns the entry for the peer with the given address
  1545. // assumes the table is locked for reading or writing
  1546. //----------------------------------------------------------------------------
  1547. PPEER_TABLE_ENTRY
  1548. GetPeerByAddress(
  1549. PPEER_TABLE pTable,
  1550. DWORD dwAddress,
  1551. DWORD dwGetMode,
  1552. PDWORD pdwErr
  1553. ) {
  1554. PLIST_ENTRY phead, pfl;
  1555. PPEER_TABLE_ENTRY ppte, ppterec;
  1556. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  1557. //
  1558. // return head of list if in GetFirst mode
  1559. //
  1560. if (dwGetMode == GETMODE_FIRST) {
  1561. phead = &pTable->PT_ListByAddress;
  1562. if (phead->Flink == phead) {
  1563. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1564. return NULL;
  1565. }
  1566. else {
  1567. pfl = phead->Flink;
  1568. return CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1569. }
  1570. }
  1571. phead = pTable->PT_HashTableByAddress + PEER_HASHVALUE(dwAddress);
  1572. ppte = NULL;
  1573. //
  1574. // search for the entry
  1575. //
  1576. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1577. ppterec = CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_HTLinkByAddress);
  1578. if (ppterec->PTE_Address == dwAddress) { ppte = ppterec; break; }
  1579. }
  1580. //
  1581. // return entry after the one found if in GetNext mode
  1582. //
  1583. if (dwGetMode == GETMODE_NEXT && ppte != NULL) {
  1584. phead = &pTable->PT_ListByAddress;
  1585. pfl = &ppte->PTE_LinkByAddress;
  1586. //
  1587. // return NULL if entry is last one
  1588. //
  1589. if (pfl->Flink == phead) {
  1590. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1591. return NULL;
  1592. }
  1593. else {
  1594. pfl = pfl->Flink;
  1595. return CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1596. }
  1597. }
  1598. //
  1599. // if the peer wasn't found, this will still be NULL
  1600. //
  1601. return ppte;
  1602. }
  1603. //----------------------------------------------------------------------------
  1604. // Function: InsertPeerByAddress
  1605. //
  1606. // inserts the given entry into the list of peers sorted by address
  1607. // assumes the table is locked for writing
  1608. //----------------------------------------------------------------------------
  1609. DWORD
  1610. InsertPeerByAddress(
  1611. PPEER_TABLE pTable,
  1612. PPEER_TABLE_ENTRY pPTE
  1613. ) {
  1614. INT cmp;
  1615. PPEER_TABLE_ENTRY ppte;
  1616. DWORD dwAddress, dwPTEAddress;
  1617. PLIST_ENTRY phead, pfl;
  1618. dwAddress = pPTE->PTE_Address;
  1619. phead = &pTable->PT_ListByAddress;
  1620. //
  1621. // search for the peer entry
  1622. //
  1623. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1624. ppte = CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1625. dwPTEAddress = ppte->PTE_Address;
  1626. if (INET_CMP(dwAddress, dwPTEAddress, cmp) < 0) { break; }
  1627. else if (cmp == 0) { return ERROR_ALREADY_EXISTS; }
  1628. }
  1629. InsertTailList(pfl, &pPTE->PTE_LinkByAddress);
  1630. return NO_ERROR;
  1631. }
  1632. //----------------------------------------------------------------------------
  1633. // Function: CreateRouteTable
  1634. //
  1635. // Initializes a route table. Note that no synchronization is provided.
  1636. //----------------------------------------------------------------------------
  1637. DWORD
  1638. CreateRouteTable(
  1639. PROUTE_TABLE pTable
  1640. ) {
  1641. PLIST_ENTRY plstart, plend, ple;
  1642. //
  1643. // initialize the hash table buckets
  1644. //
  1645. plstart = pTable->RT_HashTableByNetwork;
  1646. plend = plstart + ROUTE_HASHTABLE_SIZE;
  1647. for (ple = plstart; ple < plend; ple++) {
  1648. InitializeListHead(ple);
  1649. }
  1650. pTable->RT_Created = 0x12345678;
  1651. return NO_ERROR;
  1652. }
  1653. //----------------------------------------------------------------------------
  1654. // Function: DeleteRouteTable
  1655. //
  1656. // Removes all entries from a route table and frees resources used.
  1657. //----------------------------------------------------------------------------
  1658. DWORD
  1659. DeleteRouteTable(
  1660. PROUTE_TABLE pTable
  1661. ) {
  1662. PROUTE_TABLE_ENTRY prte;
  1663. PLIST_ENTRY ple, plend, phead;
  1664. //
  1665. // empty the hash-table buckets
  1666. //
  1667. plend = pTable->RT_HashTableByNetwork + ROUTE_HASHTABLE_SIZE;
  1668. for (ple = plend - ROUTE_HASHTABLE_SIZE; ple < plend; ple++) {
  1669. while (!IsListEmpty(ple)) {
  1670. phead = RemoveHeadList(ple);
  1671. prte = CONTAINING_RECORD(phead, ROUTE_TABLE_ENTRY, RTE_Link);
  1672. RIP_FREE(prte);
  1673. }
  1674. }
  1675. pTable->RT_Created = 0;
  1676. return NO_ERROR;
  1677. }
  1678. //----------------------------------------------------------------------------
  1679. // Function: WriteSummaryRoutes
  1680. //
  1681. // Writes to RTM all entries which are marked as summary routes.
  1682. //----------------------------------------------------------------------------
  1683. DWORD
  1684. WriteSummaryRoutes(
  1685. PROUTE_TABLE pTable,
  1686. HANDLE hRtmHandle
  1687. ) {
  1688. DWORD dwFlags, dwErr;
  1689. PRIP_IP_ROUTE prir;
  1690. PROUTE_TABLE_ENTRY prte;
  1691. PLIST_ENTRY ple, phead, plstart, plend;
  1692. BOOL bRelDest = FALSE, bRelRoute = FALSE;
  1693. RTM_NET_ADDRESS rna;
  1694. RTM_DEST_INFO rdi;
  1695. PRTM_ROUTE_INFO prri;
  1696. CHAR szNetwork[20], szNetmask[20];
  1697. //
  1698. // allocate route info structure
  1699. //
  1700. prri = RIP_ALLOC(
  1701. RTM_SIZE_OF_ROUTE_INFO( ig.IG_RtmProfile.MaxNextHopsInRoute )
  1702. );
  1703. if (prri == NULL)
  1704. {
  1705. dwErr = GetLastError();
  1706. TRACE2(
  1707. ANY, "error %d allocated %d bytes in WriteSummaryRoutes",
  1708. dwErr, RTM_SIZE_OF_ROUTE_INFO(ig.IG_RtmProfile.MaxNextHopsInRoute)
  1709. );
  1710. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1711. return dwErr;
  1712. }
  1713. //
  1714. // go through each bucket writing routes
  1715. //
  1716. plstart = pTable->RT_HashTableByNetwork;
  1717. plend = plstart + ROUTE_HASHTABLE_SIZE;
  1718. for (phead = plstart; phead < plend; phead++) {
  1719. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  1720. prte = CONTAINING_RECORD(ple, ROUTE_TABLE_ENTRY, RTE_Link);
  1721. prir = &prte->RTE_Route;
  1722. bRelDest = bRelRoute = FALSE;
  1723. do {
  1724. //
  1725. // if a valid route exists do not overwrite it with
  1726. // a summary route
  1727. //
  1728. RTM_IPV4_SET_ADDR_AND_MASK(
  1729. &rna, prir-> RR_Network.N_NetNumber,
  1730. prir-> RR_Network.N_NetMask
  1731. );
  1732. dwErr = RtmGetExactMatchDestination(
  1733. hRtmHandle, &rna, RTM_BEST_PROTOCOL,
  1734. RTM_VIEW_MASK_UCAST, &rdi
  1735. );
  1736. if (dwErr == NO_ERROR)
  1737. {
  1738. bRelDest = TRUE;
  1739. //
  1740. // Get info for the best route to this destination
  1741. //
  1742. dwErr = RtmGetRouteInfo(
  1743. hRtmHandle, rdi.ViewInfo[0].Route,
  1744. prri, NULL
  1745. );
  1746. if (dwErr != NO_ERROR)
  1747. {
  1748. TRACE1(
  1749. ANY, "error %d getting route info in"
  1750. "WriteSummaryRoutes", dwErr
  1751. );
  1752. break;
  1753. }
  1754. bRelRoute = TRUE;
  1755. //
  1756. // Check if this route is active. If it is skip
  1757. // adding an inactive summary route
  1758. //
  1759. if (!(prri-> Flags & RTM_ROUTE_FLAGS_INACTIVE)) {
  1760. lstrcpy(szNetwork, INET_NTOA(prir-> RR_Network.N_NetNumber));
  1761. lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask));
  1762. TRACE2(
  1763. ROUTE,
  1764. "Route %s %s not overwritten in summary route addition",
  1765. szNetwork, szNetmask
  1766. );
  1767. break;
  1768. }
  1769. }
  1770. //
  1771. // you reach here only if you don't have an active
  1772. // route to the summary route's destination
  1773. //
  1774. //
  1775. // if this is a summary entry (i.e. is a RIP route
  1776. // with the summary entry set)
  1777. //
  1778. if (prir->RR_RoutingProtocol == PROTO_IP_RIP &&
  1779. GETROUTEFLAG(prir) == ROUTEFLAG_SUMMARY) {
  1780. LPSTR lpszAddr;
  1781. COMPUTE_ROUTE_METRIC(prir);
  1782. dwErr = AddRtmRoute(
  1783. hRtmHandle, prir, NULL, prte->RTE_TTL,
  1784. prte->RTE_HoldTTL, FALSE
  1785. );
  1786. lpszAddr = INET_NTOA(prir-> RR_Network.N_NetNumber);
  1787. if (lpszAddr != NULL) {
  1788. lstrcpy(szNetwork, lpszAddr );
  1789. lpszAddr = INET_NTOA(prir-> RR_Network.N_NetMask);
  1790. if (lpszAddr != NULL) {
  1791. lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask));
  1792. #if ROUTE_DBG
  1793. TRACE2(
  1794. ROUTE, "Adding summary route %s %s", szNetwork,
  1795. szNetmask
  1796. );
  1797. #endif
  1798. if (dwErr != NO_ERROR) {
  1799. LPSTR lpszNexthop =
  1800. INET_NTOA(prir->RR_NextHopAddress.N_NetNumber);
  1801. if (lpszNexthop != NULL) {
  1802. TRACE4(
  1803. ROUTE,
  1804. "error %d writing summary route to %s:%s via %s",
  1805. dwErr, szNetwork, szNetmask, lpszNexthop
  1806. );
  1807. LOGWARN2(
  1808. ADD_ROUTE_FAILED_1, szNetwork, lpszNexthop, dwErr
  1809. );
  1810. }
  1811. }
  1812. }
  1813. }
  1814. }
  1815. } while (FALSE);
  1816. if (dwErr != NO_ERROR) {
  1817. //
  1818. // in case one of the INET_NTOA statements failed above, just
  1819. // trace the fact that there was an error
  1820. //
  1821. TRACE1(
  1822. ROUTE,
  1823. "error %d writing summary route",
  1824. dwErr
  1825. );
  1826. }
  1827. //
  1828. // release handles as required
  1829. //
  1830. if (bRelRoute) {
  1831. dwErr = RtmReleaseRouteInfo(hRtmHandle, prri);
  1832. if (dwErr != NO_ERROR) {
  1833. TRACE1(
  1834. ANY, "error %d releasing route info in"
  1835. " WriteSummaryRoutes", dwErr
  1836. );
  1837. }
  1838. }
  1839. if (bRelDest) {
  1840. dwErr = RtmReleaseDestInfo(hRtmHandle, &rdi);
  1841. if (dwErr != NO_ERROR) {
  1842. TRACE1(
  1843. ANY, "error %d releasing route info in"
  1844. " WriteSummaryRoutes", dwErr
  1845. );
  1846. }
  1847. }
  1848. }
  1849. }
  1850. return NO_ERROR;
  1851. }
  1852. //----------------------------------------------------------------------------
  1853. // Function: CreateRouteEntry
  1854. //
  1855. // Makes an entry in the route table for the given route.
  1856. //----------------------------------------------------------------------------
  1857. DWORD
  1858. CreateRouteEntry(
  1859. PROUTE_TABLE pTable,
  1860. PRIP_IP_ROUTE pRoute,
  1861. DWORD dwTTL,
  1862. DWORD dwHoldTTL
  1863. ) {
  1864. DWORD dwErr;
  1865. PLIST_ENTRY ple;
  1866. PROUTE_TABLE_ENTRY prte;
  1867. //
  1868. // see if the entry exists first
  1869. //
  1870. if ((prte = GetRouteByRoute(pTable, pRoute)) != NULL) {
  1871. //
  1872. // just update the metric if the new route has a lower one
  1873. //
  1874. if (GETROUTEMETRIC(&prte->RTE_Route) > GETROUTEMETRIC(pRoute)) {
  1875. SETROUTEMETRIC(&prte->RTE_Route, GETROUTEMETRIC(pRoute));
  1876. }
  1877. return NO_ERROR;
  1878. }
  1879. //
  1880. // allocate space for the new route
  1881. //
  1882. prte = RIP_ALLOC(sizeof(ROUTE_TABLE_ENTRY));
  1883. if (prte == NULL) {
  1884. dwErr = GetLastError();
  1885. TRACE2(
  1886. ANY, "error %d allocating %d bytes for route table entry",
  1887. dwErr, sizeof(ROUTE_TABLE_ENTRY)
  1888. );
  1889. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1890. return dwErr;
  1891. }
  1892. //
  1893. // initialize the entry's fields and copy the actual route structure
  1894. //
  1895. prte->RTE_TTL = dwTTL;
  1896. prte->RTE_HoldTTL = dwHoldTTL;
  1897. CopyMemory(&prte->RTE_Route, pRoute, sizeof(RIP_IP_ROUTE));
  1898. //
  1899. // insert the route in the hash table
  1900. //
  1901. ple = pTable->RT_HashTableByNetwork +
  1902. ROUTE_HASHVALUE(pRoute->RR_Network.N_NetNumber);
  1903. InsertHeadList(ple, &prte->RTE_Link);
  1904. #if ROUTE_DBG
  1905. {
  1906. LPSTR lpszAddr;
  1907. char szNet[20], szMask[20];
  1908. lpszAddr = INET_NTOA(pRoute-> RR_Network.N_NetNumber);
  1909. if (lpszAddr != NULL) {
  1910. lstrcpy(szNet, lpszAddr);
  1911. lpszAddr = INET_NTOA(pRoute-> RR_Network.N_NetMask);
  1912. if (lpszAddr != NULL) {
  1913. lstrcpy(szMask, lpszAddr);
  1914. lpszAddr = INET_NTOA(pRoute-> RR_NextHopAddress.N_NetNumber);
  1915. if (lpszAddr != NULL) {
  1916. TRACE4(
  1917. ROUTE, "Creating summary route : Route %s %s via %s"
  1918. "on interface %d",
  1919. szNet, szMask, lpszAddr, pRoute-> RR_InterfaceID
  1920. );
  1921. }
  1922. }
  1923. }
  1924. }
  1925. #endif
  1926. return NO_ERROR;
  1927. }
  1928. //----------------------------------------------------------------------------
  1929. // Function: DeleteRouteEntry
  1930. //
  1931. // Remove the entry which matches the given route.
  1932. //----------------------------------------------------------------------------
  1933. DWORD
  1934. DeleteRouteEntry(
  1935. PROUTE_TABLE pTable,
  1936. PRIP_IP_ROUTE pRoute
  1937. ) {
  1938. PROUTE_TABLE_ENTRY prte;
  1939. //
  1940. // find the route to be deleted
  1941. //
  1942. prte = GetRouteByRoute(pTable, pRoute);
  1943. if (prte == NULL) { return ERROR_INVALID_PARAMETER; }
  1944. //
  1945. // remove it from the hash table and free the memory it used
  1946. //
  1947. RemoveEntryList(&prte->RTE_Link);
  1948. RIP_FREE(prte);
  1949. return NO_ERROR;
  1950. }
  1951. //----------------------------------------------------------------------------
  1952. // Function: GetRouteByRoute
  1953. //
  1954. // Searches for the route entry which matches the given route, if any,
  1955. // and returns a pointer to it if it is found.
  1956. //----------------------------------------------------------------------------
  1957. PROUTE_TABLE_ENTRY
  1958. GetRouteByRoute(
  1959. PROUTE_TABLE pTable,
  1960. PRIP_IP_ROUTE pRoute
  1961. ) {
  1962. DWORD dwNetNumber;
  1963. PLIST_ENTRY phead, pfl;
  1964. PROUTE_TABLE_ENTRY prte, prterec;
  1965. //
  1966. // get the net number to be found and find the corresponding bucket
  1967. //
  1968. prte = NULL;
  1969. dwNetNumber = pRoute->RR_Network.N_NetNumber;
  1970. phead = pTable->RT_HashTableByNetwork + ROUTE_HASHVALUE(dwNetNumber);
  1971. //
  1972. // search the bucket for the route
  1973. //
  1974. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1975. prterec = CONTAINING_RECORD(pfl, ROUTE_TABLE_ENTRY, RTE_Link);
  1976. if (prterec->RTE_Route.RR_Network.N_NetNumber == dwNetNumber) {
  1977. prte = prterec; break;
  1978. }
  1979. }
  1980. //
  1981. // if the route wasn't found, this will still be NULL
  1982. //
  1983. return prte;
  1984. }
  1985. //----------------------------------------------------------------------------
  1986. // Function: CreateBindingTable
  1987. //
  1988. // Initializes a table of bindings.
  1989. //----------------------------------------------------------------------------
  1990. DWORD
  1991. CreateBindingTable(
  1992. PBINDING_TABLE pTable
  1993. ) {
  1994. DWORD dwErr;
  1995. PLIST_ENTRY plend, ple;
  1996. //
  1997. // initialize the hash table of bindings
  1998. //
  1999. plend = pTable->BT_HashTableByNetwork + BINDING_HASHTABLE_SIZE;
  2000. for (ple = plend - BINDING_HASHTABLE_SIZE; ple < plend; ple++) {
  2001. InitializeListHead(ple);
  2002. }
  2003. //
  2004. // initialize the table's synchronization object
  2005. //
  2006. dwErr = CreateReadWriteLock(&pTable->BT_RWL);
  2007. if (dwErr == NO_ERROR) {
  2008. pTable->BT_Created = 0x12345678;
  2009. }
  2010. return dwErr;
  2011. }
  2012. //----------------------------------------------------------------------------
  2013. // Function: DeleteBindingTable
  2014. //
  2015. // Cleans up resources used by a binding table.
  2016. //----------------------------------------------------------------------------
  2017. DWORD
  2018. DeleteBindingTable(
  2019. PBINDING_TABLE pTable
  2020. ) {
  2021. PBINDING_TABLE_ENTRY pbte;
  2022. PLIST_ENTRY plend, ple, phead;
  2023. //
  2024. // destroy the synchronization object
  2025. //
  2026. DeleteReadWriteLock(&pTable->BT_RWL);
  2027. //
  2028. // empty the hash-table buckets
  2029. //
  2030. plend = pTable->BT_HashTableByNetwork + BINDING_HASHTABLE_SIZE;
  2031. for (ple = plend - BINDING_HASHTABLE_SIZE; ple < plend; ple++) {
  2032. while (!IsListEmpty(ple)) {
  2033. phead = RemoveHeadList(ple);
  2034. pbte = CONTAINING_RECORD(phead, BINDING_TABLE_ENTRY, BTE_Link);
  2035. RIP_FREE(pbte);
  2036. }
  2037. }
  2038. pTable->BT_Created = 0;
  2039. return NO_ERROR;
  2040. }
  2041. //----------------------------------------------------------------------------
  2042. // Function: CreateBindingEntry
  2043. //
  2044. // Adds a binding to the table.
  2045. // assumes the binding table is locked for writing
  2046. //----------------------------------------------------------------------------
  2047. DWORD
  2048. CreateBindingEntry(
  2049. PBINDING_TABLE pTable,
  2050. PIPRIP_IF_BINDING pib
  2051. ) {
  2052. INT cmp;
  2053. PLIST_ENTRY ple, phead;
  2054. PIPRIP_IP_ADDRESS paddr;
  2055. PBINDING_TABLE_ENTRY pbte;
  2056. DWORD i, dwErr, dwAddress, dwNetmask, dwNetwork;
  2057. //
  2058. // go through the IP addresses in the interface binding,
  2059. // adding each to the binding table
  2060. //
  2061. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  2062. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  2063. dwAddress = paddr->IA_Address;
  2064. dwNetmask = paddr->IA_Netmask;
  2065. //
  2066. // compute the network part of the binding
  2067. //
  2068. dwNetwork = (dwAddress & NETCLASS_MASK(dwAddress));
  2069. //
  2070. // get the hash bucket to which the binding belongs,
  2071. // and find the insertion point in the bucket
  2072. //
  2073. phead = pTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork);
  2074. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  2075. pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link);
  2076. INET_CMP(dwNetwork, pbte->BTE_Network, cmp);
  2077. if (cmp < 0) { break; }
  2078. else
  2079. if (cmp > 0) { continue; }
  2080. //
  2081. // the network parts are equal; further compare
  2082. // against the IP address fields
  2083. //
  2084. INET_CMP(dwAddress, pbte->BTE_Address, cmp);
  2085. if (cmp < 0) { break; }
  2086. else
  2087. if (cmp > 0) { continue; }
  2088. //
  2089. // the addresses are also equal; return an error
  2090. //
  2091. return ERROR_ALREADY_EXISTS;
  2092. }
  2093. //
  2094. // we now have the insertion point, so create the new item
  2095. //
  2096. pbte = RIP_ALLOC(sizeof(BINDING_TABLE_ENTRY));
  2097. if (pbte == NULL) {
  2098. dwErr = GetLastError();
  2099. TRACE2(
  2100. IF, "error %d allocating %d bytes for binding entry",
  2101. dwErr, sizeof(BINDING_TABLE_ENTRY)
  2102. );
  2103. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  2104. return dwErr;
  2105. }
  2106. pbte->BTE_Address = dwAddress;
  2107. pbte->BTE_Network = dwNetwork;
  2108. pbte->BTE_Netmask = dwNetmask;
  2109. //
  2110. // insert the entry
  2111. //
  2112. InsertTailList(ple, &pbte->BTE_Link);
  2113. }
  2114. return NO_ERROR;
  2115. }
  2116. //----------------------------------------------------------------------------
  2117. // Function: DeleteBindingEntry
  2118. //
  2119. // Removes a binding from the table.
  2120. // assumes the binding table is locked for writing
  2121. //----------------------------------------------------------------------------
  2122. DWORD
  2123. DeleteBindingEntry(
  2124. PBINDING_TABLE pTable,
  2125. PIPRIP_IF_BINDING pib
  2126. ) {
  2127. PLIST_ENTRY ple, phead;
  2128. PIPRIP_IP_ADDRESS paddr;
  2129. PBINDING_TABLE_ENTRY pbte;
  2130. DWORD i, dwNetwork, dwAddress, dwNetmask;
  2131. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  2132. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  2133. dwAddress = paddr->IA_Address;
  2134. dwNetmask = paddr->IA_Netmask;
  2135. //
  2136. // get the hash bucket to be searched
  2137. //
  2138. dwNetwork = (dwAddress & NETCLASS_MASK(dwAddress));
  2139. phead = pTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork);
  2140. //
  2141. // search the bucket for the binding specified
  2142. //
  2143. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  2144. pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link);
  2145. if (dwAddress != pbte->BTE_Address ||
  2146. dwNetmask != pbte->BTE_Netmask) {
  2147. continue;
  2148. }
  2149. //
  2150. // the entry to be deleted has been found;
  2151. // remove it from the list and free its memory
  2152. //
  2153. RemoveEntryList(&pbte->BTE_Link);
  2154. RIP_FREE(pbte);
  2155. break;
  2156. }
  2157. }
  2158. return NO_ERROR;
  2159. }
  2160. //---------------------------------------------------------------------------
  2161. // Function: GuessSubnetMask
  2162. //
  2163. // This function attempts to deduce the subnet mask of an IP address
  2164. // based on the configured addresses and masks on the local host.
  2165. // assumes the binding table is locked for reading or writing
  2166. //---------------------------------------------------------------------------
  2167. DWORD
  2168. GuessSubnetMask(
  2169. DWORD dwAddress,
  2170. PDWORD pdwNetclassMask
  2171. ) {
  2172. INT cmp;
  2173. PLIST_ENTRY ple, phead;
  2174. PBINDING_TABLE_ENTRY pbte;
  2175. DWORD dwNetwork, dwNetmask, dwGuessMask;
  2176. //
  2177. // the mask for a default route (0.0.0.0) is zero
  2178. //
  2179. if (dwAddress == 0) {
  2180. if (pdwNetclassMask != NULL) { *pdwNetclassMask = 0; }
  2181. return 0;
  2182. }
  2183. //
  2184. // the mask for the broadcast route is all-ones (255.255.255.255)
  2185. //
  2186. if (dwAddress == INADDR_BROADCAST) {
  2187. if (pdwNetclassMask != NULL) { *pdwNetclassMask = INADDR_BROADCAST; }
  2188. return INADDR_BROADCAST;
  2189. }
  2190. //
  2191. // otherwise, we start with the network-class mask
  2192. //
  2193. dwGuessMask = dwNetmask = NETCLASS_MASK(dwAddress);
  2194. if (pdwNetclassMask != NULL) { *pdwNetclassMask = dwNetmask; }
  2195. //
  2196. // if the route is a network route, we're done
  2197. //
  2198. if ((dwAddress & ~dwNetmask) == 0) { return dwNetmask; }
  2199. //
  2200. // otherwise, search through the bindings table
  2201. // to see if one is on the same network as this address
  2202. //
  2203. dwNetwork = (dwAddress & dwNetmask);
  2204. phead = ig.IG_BindingTable->BT_HashTableByNetwork +
  2205. BINDING_HASHVALUE(dwNetwork);
  2206. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  2207. pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link);
  2208. INET_CMP(dwNetwork, pbte->BTE_Network, cmp);
  2209. if (cmp < 0) { break; }
  2210. else
  2211. if (cmp > 0) { continue; }
  2212. //
  2213. // this entry is on the same network as the address passed in
  2214. // so see if the entry's netmask matches the address;
  2215. // if it does, we're done; otherwise, save this mask
  2216. // as a guess, and keep looking.
  2217. // note that this exhaustive search is the only way we can
  2218. // reliably guess masks for supernets
  2219. //
  2220. if ((dwAddress & pbte->BTE_Netmask) ==
  2221. (pbte->BTE_Address & pbte->BTE_Netmask)) {
  2222. return pbte->BTE_Netmask;
  2223. }
  2224. dwGuessMask = pbte->BTE_Netmask;
  2225. }
  2226. //
  2227. // return whatever has been our best guess so far
  2228. //
  2229. return dwGuessMask;
  2230. }
  2231. DWORD
  2232. AddRtmRoute(
  2233. RTM_ENTITY_HANDLE hRtmHandle,
  2234. PRIP_IP_ROUTE prir,
  2235. RTM_NEXTHOP_HANDLE hNextHop OPTIONAL,
  2236. DWORD dwTimeOut,
  2237. DWORD dwHoldTime,
  2238. BOOL bActive
  2239. )
  2240. /*++
  2241. Routine Description :
  2242. This function adds a route to the RTMv2 database. In addition it
  2243. creates the nexthop if one is not specified (via hNextHop), based
  2244. on the next hop i/f and address specified in the RIP route.
  2245. Parameters :
  2246. hRtmHandle - Entity registration handle
  2247. prir - RIP route to be added
  2248. hNextHop - Handle to the next hop to be used for the route
  2249. dwTimeout - Route timeout interval
  2250. dwHoldTime - Route holddown interval (after delete)
  2251. bActive - TRUE if the route being added is an active route,
  2252. FALSE otherwise (in RIP's case for summary routes)
  2253. Return Value :
  2254. NO_ERROR - Success
  2255. Rtm error code - Otherwise
  2256. Environment :
  2257. Invoked from ProcessRouteEntry and WriteSummaryRoutes
  2258. --*/
  2259. {
  2260. BOOL bRelDest = FALSE;
  2261. DWORD dwErr, dwChangeFlags = 0;
  2262. RTM_DEST_INFO rdi;
  2263. RTM_NEXTHOP_INFO rni;
  2264. RTM_ROUTE_INFO rri;
  2265. RTM_NET_ADDRESS rna;
  2266. CHAR szNetwork[20], szNetmask[20], szNextHop[20], szNextHopmask[20];
  2267. do {
  2268. //
  2269. // char strings used to print IP address/mask info
  2270. // Used in error cases only
  2271. //
  2272. lstrcpy(szNetwork, INET_NTOA(prir-> RR_Network.N_NetNumber));
  2273. lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask));
  2274. lstrcpy(szNextHop, INET_NTOA(prir-> RR_NextHopAddress.N_NetNumber));
  2275. lstrcpy(szNextHopmask, INET_NTOA(prir-> RR_NextHopAddress.N_NetMask));
  2276. //
  2277. // Zero out the next hop and route memory
  2278. //
  2279. ZeroMemory(&rni, sizeof(RTM_NEXTHOP_INFO));
  2280. ZeroMemory(&rri, sizeof(RTM_ROUTE_INFO));
  2281. if (hNextHop == NULL) {
  2282. //
  2283. // Find next hop.
  2284. //
  2285. rni.InterfaceIndex = prir-> RR_InterfaceID;
  2286. RTM_IPV4_SET_ADDR_AND_MASK(
  2287. &rni.NextHopAddress, prir-> RR_NextHopAddress.N_NetNumber,
  2288. IPV4_SOURCE_MASK
  2289. );
  2290. //
  2291. // Save the nexthop mask in the entity specific info
  2292. //
  2293. *((PDWORD)&rni.EntitySpecificInfo) = prir-> RR_NextHopAddress.N_NetMask;
  2294. rni.NextHopOwner = hRtmHandle;
  2295. dwErr = RtmFindNextHop(hRtmHandle, &rni, &hNextHop, NULL);
  2296. if (dwErr == ERROR_NOT_FOUND) {
  2297. //
  2298. // Next hop not found. Create one
  2299. //
  2300. dwErr = RtmAddNextHop(
  2301. hRtmHandle, &rni, &hNextHop, &dwChangeFlags
  2302. );
  2303. if (dwErr != NO_ERROR) {
  2304. TRACE3(
  2305. ROUTE, "error %d creating next hop %s %s",
  2306. dwErr, szNextHop, szNextHopmask
  2307. );
  2308. break;
  2309. }
  2310. }
  2311. else if (dwErr != NO_ERROR) {
  2312. TRACE3(
  2313. ANY, "error %d finding next hop %s %s", dwErr,
  2314. szNextHop, szNextHopmask
  2315. );
  2316. break;
  2317. }
  2318. }
  2319. //
  2320. // Build route info structure
  2321. //
  2322. RTM_IPV4_SET_ADDR_AND_MASK(
  2323. &rna, prir-> RR_Network.N_NetNumber, prir-> RR_Network.N_NetMask
  2324. );
  2325. rri.PrefInfo.Metric = prir-> RR_FamilySpecificData.FSD_Metric1;
  2326. rri.BelongsToViews = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST;
  2327. //
  2328. // set entity specific info
  2329. //
  2330. SETRIPTAG(&rri, GETROUTETAG(prir));
  2331. SETRIPFLAG(&rri, GETROUTEFLAG(prir));
  2332. //
  2333. // Set next hop info
  2334. //
  2335. rri.NextHopsList.NumNextHops = 1;
  2336. rri.NextHopsList.NextHops[0] = hNextHop;
  2337. rri.Neighbour = hNextHop;
  2338. //
  2339. // Call into router manager to set preference info
  2340. //
  2341. ig.IG_SupportFunctions.ValidateRoute(PROTO_IP_RIP, &rri, &rna);
  2342. //
  2343. // if this is an inactive route,
  2344. // - set route flag to inactive.
  2345. // - set the views for route to none
  2346. //
  2347. if ( !bActive ) {
  2348. rri.Flags1 = 0;
  2349. rri.Flags = RTM_ROUTE_FLAGS_INACTIVE;
  2350. rri.BelongsToViews = 0;
  2351. }
  2352. //
  2353. // Add route to dest, convert timeout to milliseconds
  2354. //
  2355. dwChangeFlags = RTM_ROUTE_CHANGE_FIRST;
  2356. dwErr = RtmAddRouteToDest(
  2357. hRtmHandle, NULL, &rna, &rri, dwTimeOut * 1000, NULL,
  2358. 0, NULL, &dwChangeFlags
  2359. );
  2360. if ( dwErr != NO_ERROR ) {
  2361. TRACE4(
  2362. ANY, "error %d adding route %s %s via %s",
  2363. dwErr, szNetwork, szNetmask, szNextHop
  2364. );
  2365. break;
  2366. }
  2367. if ( bActive )
  2368. {
  2369. //
  2370. // Hold destination if this is an active route
  2371. //
  2372. dwErr = RtmGetExactMatchDestination(
  2373. hRtmHandle, &rna, RTM_BEST_PROTOCOL,
  2374. RTM_VIEW_MASK_UCAST, &rdi
  2375. );
  2376. if ( dwErr != NO_ERROR ) {
  2377. TRACE3(
  2378. ANY, "error %d getting just added destination %s:%s",
  2379. dwErr, szNetwork, szNetmask
  2380. );
  2381. break;
  2382. }
  2383. bRelDest = TRUE;
  2384. dwErr = RtmHoldDestination(
  2385. hRtmHandle, rdi.DestHandle, RTM_VIEW_MASK_UCAST,
  2386. dwHoldTime * 1000
  2387. );
  2388. if ( dwErr != NO_ERROR ) {
  2389. TRACE3(
  2390. ANY, "error %d failed to hold destination %s %s",
  2391. dwErr, szNetwork, szNetmask
  2392. );
  2393. break;
  2394. }
  2395. }
  2396. } while(FALSE);
  2397. //
  2398. // release acquired handles
  2399. //
  2400. if ( bRelDest ) {
  2401. dwErr = RtmReleaseDestInfo( hRtmHandle, &rdi );
  2402. if ( dwErr != NO_ERROR ) {
  2403. TRACE3(
  2404. ANY, "error %d failed to relase just added destination %s %s",
  2405. dwErr, szNetwork, szNetmask
  2406. );
  2407. }
  2408. }
  2409. return dwErr;
  2410. }
  2411. DWORD
  2412. GetRouteInfo(
  2413. IN RTM_ROUTE_HANDLE hRoute,
  2414. IN PRTM_ROUTE_INFO pInRouteInfo OPTIONAL,
  2415. IN PRTM_DEST_INFO pInDestInfo OPTIONAL,
  2416. OUT PRIP_IP_ROUTE pRoute
  2417. )
  2418. /*++
  2419. Routine Description:
  2420. Wrapper for filling out the OSPF_RTMv2_ROUTE by retrieving various
  2421. RTM infos.
  2422. Arguments:
  2423. hRoute
  2424. pInRouteInfo
  2425. pInDestInfo
  2426. pRoute
  2427. Return Value:
  2428. RTM error code
  2429. --*/
  2430. {
  2431. DWORD dwErr;
  2432. RTM_ROUTE_INFO RouteInfo, *pRouteInfo;
  2433. RTM_ENTITY_INFO EntityInfo, *pEntityInfo;
  2434. RTM_DEST_INFO DestInfo, *pDestInfo;
  2435. RTM_NEXTHOP_INFO NextHopInfo, *pNextHopInfo;
  2436. pRouteInfo = NULL;
  2437. pEntityInfo = NULL;
  2438. pDestInfo = NULL;
  2439. pNextHopInfo = NULL;
  2440. do
  2441. {
  2442. ZeroMemory(pRoute, sizeof(RIP_IP_ROUTE));
  2443. //
  2444. // If the user hasnt already given us the route info, get it
  2445. //
  2446. if ( pInRouteInfo == NULL )
  2447. {
  2448. dwErr = RtmGetRouteInfo(
  2449. ig.IG_RtmHandle, hRoute, &RouteInfo, NULL
  2450. );
  2451. if ( dwErr != NO_ERROR )
  2452. {
  2453. TRACE1(
  2454. ANY, "GetRouteInfo: Error %d from RtmGetRouteInfo\n", dwErr
  2455. );
  2456. break;
  2457. }
  2458. pRouteInfo = &RouteInfo;
  2459. }
  2460. else
  2461. {
  2462. pRouteInfo = pInRouteInfo;
  2463. }
  2464. //
  2465. // If the user hasnt given us the dest info, get it
  2466. //
  2467. if ( pInDestInfo == NULL )
  2468. {
  2469. dwErr = RtmGetDestInfo(
  2470. ig.IG_RtmHandle, pRouteInfo->DestHandle,
  2471. 0, RTM_VIEW_MASK_UCAST, &DestInfo
  2472. );
  2473. if ( dwErr != NO_ERROR )
  2474. {
  2475. TRACE1(
  2476. ANY, "GetRouteInfo: Error %d from RtmGetDestInfo\n", dwErr
  2477. );
  2478. break;
  2479. }
  2480. pDestInfo = &DestInfo;
  2481. }
  2482. else
  2483. {
  2484. pDestInfo = pInDestInfo;
  2485. }
  2486. //
  2487. // Get owner info if the protocol is not us
  2488. //
  2489. if ( pRouteInfo-> RouteOwner != ig.IG_RtmHandle )
  2490. {
  2491. dwErr = RtmGetEntityInfo(
  2492. ig.IG_RtmHandle, pRouteInfo->RouteOwner, &EntityInfo
  2493. );
  2494. if ( dwErr != NO_ERROR )
  2495. {
  2496. TRACE1(
  2497. ANY, "GetRouteInfo: Error %d from RtmGetEntityInfo\n",
  2498. dwErr
  2499. );
  2500. break;
  2501. }
  2502. pEntityInfo = &EntityInfo;
  2503. }
  2504. //
  2505. // Get the info about the first next hop
  2506. //
  2507. dwErr = RtmGetNextHopInfo(
  2508. ig.IG_RtmHandle,
  2509. pRouteInfo->NextHopsList.NextHops[0],
  2510. &NextHopInfo
  2511. );
  2512. if ( dwErr != NO_ERROR )
  2513. {
  2514. TRACE1(
  2515. ANY, "GetRouteInfo: Error %d from RtmGetEntityInfo\n",
  2516. dwErr
  2517. );
  2518. break;
  2519. }
  2520. pNextHopInfo = &NextHopInfo;
  2521. //
  2522. // Now copy out all the info.
  2523. // First, the route info
  2524. //
  2525. pRoute-> RR_FamilySpecificData.FSD_Metric1 =
  2526. pRoute-> RR_FamilySpecificData.FSD_Metric =
  2527. pRouteInfo-> PrefInfo.Metric;
  2528. //
  2529. // copy out the protocol id from the entity info
  2530. //
  2531. if ( pEntityInfo != NULL )
  2532. {
  2533. pRoute-> RR_RoutingProtocol = pEntityInfo->EntityId.EntityProtocolId;
  2534. }
  2535. else
  2536. {
  2537. //
  2538. // this is a RIP route
  2539. //
  2540. pRoute-> RR_RoutingProtocol = PROTO_IP_RIP;
  2541. SETROUTEFLAG(pRoute, GETRIPFLAG(pRouteInfo));
  2542. SETROUTETAG(pRoute, GETRIPTAG(pRouteInfo));
  2543. }
  2544. //
  2545. // Copy out the dest info
  2546. //
  2547. RTM_IPV4_GET_ADDR_AND_MASK(
  2548. pRoute->RR_Network.N_NetNumber,
  2549. pRoute->RR_Network.N_NetMask,
  2550. &(pDestInfo->DestAddress)
  2551. );
  2552. pRoute-> hDest = pDestInfo-> DestHandle;
  2553. //
  2554. // Copy out the next hop info
  2555. //
  2556. RTM_IPV4_GET_ADDR_AND_MASK(
  2557. pRoute->RR_NextHopAddress.N_NetNumber,
  2558. pRoute->RR_NextHopAddress.N_NetMask,
  2559. &(pNextHopInfo->NextHopAddress)
  2560. );
  2561. //
  2562. // retrive saved next hop mask
  2563. //
  2564. pRoute-> RR_NextHopAddress.N_NetMask =
  2565. *((PDWORD)&pNextHopInfo-> EntitySpecificInfo);
  2566. pRoute-> RR_InterfaceID = pNextHopInfo->InterfaceIndex;
  2567. #if 0
  2568. {
  2569. char szNet[20], szMask[20], szNextHop[20], szNextHopMask[20];
  2570. lstrcpy(szNet, INET_NTOA(pRoute-> RR_Network.N_NetNumber));
  2571. lstrcpy(szMask, INET_NTOA(pRoute-> RR_Network.N_NetMask));
  2572. lstrcpy(szNextHop, INET_NTOA(pRoute-> RR_NextHopAddress.N_NetNumber));
  2573. lstrcpy(szNextHopMask, INET_NTOA(pRoute-> RR_NextHopAddress.N_NetMask));
  2574. TRACE5(
  2575. ROUTE, "GetRouteInfo : Route %s %s via %s %s on interface %d",
  2576. szNet, szMask, szNextHop, szNextHopMask,
  2577. pRoute-> RR_InterfaceID
  2578. );
  2579. TRACE3(
  2580. ROUTE, "Has metric %d, flag %x, tag %d",
  2581. GETROUTEMETRIC(pRoute), GETROUTEFLAG(pRoute),
  2582. GETROUTETAG(pRoute)
  2583. );
  2584. TRACE2(
  2585. ROUTE, "Protocol %d, original flag %d",
  2586. pRoute-> RR_RoutingProtocol, GETRIPFLAG(pRouteInfo)
  2587. );
  2588. }
  2589. #endif
  2590. } while( FALSE );
  2591. //
  2592. // Release the relevant infos
  2593. //
  2594. if ( pNextHopInfo != NULL )
  2595. {
  2596. RtmReleaseNextHopInfo( ig.IG_RtmHandle, pNextHopInfo );
  2597. }
  2598. if ( pEntityInfo != NULL )
  2599. {
  2600. RtmReleaseEntityInfo( ig.IG_RtmHandle, pEntityInfo );
  2601. }
  2602. //
  2603. // Release the route and dest infos only if we were not passed them
  2604. // in AND we successfully retrieved them
  2605. //
  2606. if ( ( pInDestInfo == NULL ) && ( pDestInfo != NULL ) )
  2607. {
  2608. RtmReleaseDestInfo( ig.IG_RtmHandle, pDestInfo );
  2609. }
  2610. if( ( pInRouteInfo == NULL ) && ( pRouteInfo != NULL ) )
  2611. {
  2612. RtmReleaseRouteInfo( ig.IG_RtmHandle, pRouteInfo );
  2613. }
  2614. return NO_ERROR;
  2615. }