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.

3833 lines
93 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 increase the recv buffer size
  961. //
  962. dwOption = RIPRECVBUFFERSIZE;
  963. dwErr = setsockopt(
  964. pite->ITE_Sockets[i], SOL_SOCKET, SO_RCVBUF,
  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 SO_RCVBUF for interface %d (%s)",
  973. dwErr, dwIndex, INET_NTOA(paddr->IA_Address)
  974. );
  975. }
  976. }
  977. //
  978. // try to allow re-use of this address
  979. //
  980. dwOption = 1;
  981. dwErr = setsockopt(
  982. pite->ITE_Sockets[i], SOL_SOCKET, SO_REUSEADDR,
  983. (PBYTE)&dwOption, sizeof(dwOption)
  984. );
  985. if (dwErr == SOCKET_ERROR) {
  986. dwErr = WSAGetLastError();
  987. lpszAddr = INET_NTOA(paddr->IA_Address);
  988. if (lpszAddr != NULL) {
  989. TRACE3(
  990. IF, "error %d setting re-use flag for interface %d (%s)",
  991. dwErr, dwIndex, INET_NTOA(paddr->IA_Address)
  992. );
  993. }
  994. }
  995. //
  996. // enable broadcasting if not exclusively RIP2 mode,
  997. // or if there are any unicast peers configured
  998. //
  999. if (pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1 ||
  1000. pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1_COMPAT ||
  1001. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1 ||
  1002. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1_COMPAT ||
  1003. (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED &&
  1004. pic->IC_UnicastPeerCount != 0)) {
  1005. //
  1006. // make sure broadcasting is enabled for this socket
  1007. //
  1008. dwOption = 1;
  1009. dwErr = setsockopt(
  1010. pite->ITE_Sockets[i], SOL_SOCKET, SO_BROADCAST,
  1011. (PBYTE)&dwOption, sizeof(dwOption)
  1012. );
  1013. if (dwErr == SOCKET_ERROR) {
  1014. dwErr = WSAGetLastError();
  1015. lpszAddr = INET_NTOA(paddr->IA_Address);
  1016. if (lpszAddr != NULL) {
  1017. TRACE3(
  1018. IF, "error %d enabling broadcast on interface %d (%s)",
  1019. dwErr, dwIndex, lpszAddr
  1020. );
  1021. LOGERR1(ENABLE_BROADCAST_FAILED, lpszAddr, dwErr);
  1022. }
  1023. break;
  1024. }
  1025. }
  1026. //
  1027. // bind the socket to the RIP port
  1028. //
  1029. sinsock.sin_family = AF_INET;
  1030. sinsock.sin_port = htons(IPRIP_PORT);
  1031. sinsock.sin_addr.s_addr = paddr->IA_Address;
  1032. dwErr = bind(
  1033. pite->ITE_Sockets[i], (LPSOCKADDR)&sinsock,
  1034. sizeof(SOCKADDR_IN)
  1035. );
  1036. if (dwErr == SOCKET_ERROR) {
  1037. dwErr = WSAGetLastError();
  1038. lpszAddr = INET_NTOA(paddr->IA_Address);
  1039. if (lpszAddr != NULL) {
  1040. TRACE3(
  1041. IF, "error %d binding on socket for interface %d (%s)",
  1042. dwErr, dwIndex, lpszAddr
  1043. );
  1044. LOGERR1(BIND_FAILED, lpszAddr, dwErr);
  1045. }
  1046. break;
  1047. }
  1048. //
  1049. // enable multicasting if not exclusively RIP1/RIP1-compatible mode
  1050. //
  1051. if (pic->IC_AcceptMode == IPRIP_ACCEPT_RIP2 ||
  1052. pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1_COMPAT ||
  1053. pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP2) {
  1054. struct ip_mreq imOption;
  1055. //
  1056. // set the interface from which multicasts must be sent
  1057. //
  1058. sinsock.sin_addr.s_addr = paddr->IA_Address;
  1059. dwErr = setsockopt(
  1060. pite->ITE_Sockets[i], IPPROTO_IP, IP_MULTICAST_IF,
  1061. (PBYTE)&sinsock.sin_addr, sizeof(IN_ADDR)
  1062. );
  1063. if (dwErr == SOCKET_ERROR) {
  1064. dwErr = WSAGetLastError();
  1065. lpszAddr = INET_NTOA(paddr->IA_Address);
  1066. if (lpszAddr != NULL) {
  1067. TRACE3(
  1068. IF, "error %d setting interface %d (%s) as multicast",
  1069. dwErr, dwIndex, lpszAddr
  1070. );
  1071. LOGERR1(SET_MCAST_IF_FAILED, lpszAddr, dwErr);
  1072. }
  1073. break;
  1074. }
  1075. //
  1076. // join the IPRIP multicast group
  1077. //
  1078. imOption.imr_multiaddr.s_addr = IPRIP_MULTIADDR;
  1079. imOption.imr_interface.s_addr = paddr->IA_Address;
  1080. dwErr = setsockopt(
  1081. pite->ITE_Sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP,
  1082. (PBYTE)&imOption, sizeof(imOption)
  1083. );
  1084. if (dwErr == SOCKET_ERROR) {
  1085. dwErr = WSAGetLastError();
  1086. lpszAddr = INET_NTOA(paddr->IA_Address);
  1087. if (lpszAddr != NULL) {
  1088. TRACE3(
  1089. IF, "error %d enabling multicast on interface %d (%s)",
  1090. dwErr, dwIndex, lpszAddr
  1091. );
  1092. LOGERR1(JOIN_GROUP_FAILED, lpszAddr, dwErr);
  1093. }
  1094. break;
  1095. }
  1096. }
  1097. dwErr = NO_ERROR;
  1098. }
  1099. if (i < pib->IB_AddrCount) {
  1100. //
  1101. // something failed if we are here
  1102. //
  1103. DeleteIfSocket(pite);
  1104. }
  1105. return dwErr;
  1106. }
  1107. //----------------------------------------------------------------------------
  1108. // Function: DeleteIfSocket
  1109. //
  1110. // closes the sockets used by an interface, if any.
  1111. // assumes that the interface is active, and that the interface table
  1112. // is locked for writing
  1113. //----------------------------------------------------------------------------
  1114. DWORD
  1115. DeleteIfSocket(
  1116. PIF_TABLE_ENTRY pite
  1117. ) {
  1118. DWORD i;
  1119. for (i = 0; i < pite->ITE_Binding->IB_AddrCount; i++) {
  1120. if (pite->ITE_Sockets[i] != INVALID_SOCKET) {
  1121. if (closesocket(pite->ITE_Sockets[i]) == SOCKET_ERROR) {
  1122. TRACE1(IF, "error %d closing socket", WSAGetLastError());
  1123. }
  1124. pite->ITE_Sockets[i] = INVALID_SOCKET;
  1125. }
  1126. }
  1127. RIP_FREE(pite->ITE_Sockets);
  1128. pite->ITE_Sockets = NULL;
  1129. return NO_ERROR;
  1130. }
  1131. //----------------------------------------------------------------------------
  1132. // Function: GetIfByIndex
  1133. //
  1134. // returns the interface with the given index.
  1135. // assumes the table is locked for reading or writing
  1136. //----------------------------------------------------------------------------
  1137. PIF_TABLE_ENTRY
  1138. GetIfByIndex(
  1139. PIF_TABLE pTable,
  1140. DWORD dwIndex
  1141. ) {
  1142. PIF_TABLE_ENTRY pite = NULL;
  1143. PLIST_ENTRY phead, ple;
  1144. phead = pTable->IT_HashTableByIndex + IF_HASHVALUE(dwIndex);
  1145. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  1146. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_HTLinkByIndex);
  1147. if (pite->ITE_Index == dwIndex) {
  1148. break;
  1149. }
  1150. }
  1151. if (ple == phead) { return NULL; }
  1152. else { return pite; }
  1153. }
  1154. //----------------------------------------------------------------------------
  1155. // Function: GetIfByAddress
  1156. //
  1157. // returns the interface bound to the given address.
  1158. // assumes the table is locked for reading or writing
  1159. //----------------------------------------------------------------------------
  1160. PIF_TABLE_ENTRY
  1161. GetIfByAddress(
  1162. PIF_TABLE pTable,
  1163. DWORD dwAddress,
  1164. DWORD dwGetMode,
  1165. PDWORD pdwErr
  1166. ) {
  1167. DWORD i;
  1168. PIPRIP_IF_BINDING pib;
  1169. PLIST_ENTRY phead, pfl;
  1170. PIPRIP_IP_ADDRESS paddr;
  1171. PIF_TABLE_ENTRY pite, piterec;
  1172. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  1173. phead = &pTable->IT_ListByAddress;
  1174. pite = NULL;
  1175. //
  1176. // return record at head of list if mode is GetFirst
  1177. //
  1178. if (dwGetMode == GETMODE_FIRST) {
  1179. if (phead->Flink == phead) {
  1180. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1181. return NULL;
  1182. }
  1183. else {
  1184. pfl = phead->Flink;
  1185. return CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1186. }
  1187. }
  1188. //
  1189. // search for the entry
  1190. //
  1191. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1192. piterec = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1193. pib = piterec->ITE_Binding;
  1194. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  1195. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  1196. if (dwAddress == paddr->IA_Address) { pite = piterec; break; }
  1197. }
  1198. if (pite) { break; }
  1199. }
  1200. //
  1201. // return record after the one found if mode is GetNext
  1202. //
  1203. if (dwGetMode == GETMODE_NEXT && pite != NULL) {
  1204. pfl = &pite->ITE_LinkByAddress;
  1205. //
  1206. // if entry found is last one, return NULL,
  1207. // otherwise, return the following entry
  1208. //
  1209. if (pfl->Flink == phead) {
  1210. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1211. pite = NULL;
  1212. }
  1213. else {
  1214. pfl = pfl->Flink;
  1215. pite = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1216. }
  1217. }
  1218. //
  1219. // if the interface wasn't found, this will still be NULL
  1220. //
  1221. return pite;
  1222. }
  1223. //----------------------------------------------------------------------------
  1224. // Function: GetIfByListIndex
  1225. //
  1226. // This function is similar to GetIfByAddress in that it supports
  1227. // three modes of retrieval, but it is different in that it looks
  1228. // in the list of interfaces sorted by index.
  1229. //----------------------------------------------------------------------------
  1230. PIF_TABLE_ENTRY
  1231. GetIfByListIndex(
  1232. PIF_TABLE pTable,
  1233. DWORD dwIndex,
  1234. DWORD dwGetMode,
  1235. PDWORD pdwErr
  1236. ) {
  1237. PIF_TABLE_ENTRY pite;
  1238. PLIST_ENTRY ple, phead;
  1239. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  1240. phead = &pTable->IT_ListByIndex;
  1241. pite = NULL;
  1242. //
  1243. // return record at head of list if mode is GETMODE_FIRST;
  1244. // if list is empty, return NULL.
  1245. //
  1246. if (dwGetMode == GETMODE_FIRST) {
  1247. if (phead->Flink == phead) {
  1248. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1249. return NULL;
  1250. }
  1251. else {
  1252. ple = phead->Flink;
  1253. return CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  1254. }
  1255. }
  1256. //
  1257. // get the entry requested
  1258. //
  1259. pite = GetIfByIndex(pTable, dwIndex);
  1260. //
  1261. // if mode is GETMODE_NEXT, return the item after the one retrieved
  1262. //
  1263. if (dwGetMode == GETMODE_NEXT && pite != NULL) {
  1264. ple = &pite->ITE_LinkByIndex;
  1265. //
  1266. // if entry found is last one, return NULL,
  1267. // otherwise return the following entry
  1268. //
  1269. if (ple->Flink == phead) {
  1270. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1271. pite = NULL;
  1272. }
  1273. else {
  1274. ple = ple->Flink;
  1275. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  1276. }
  1277. }
  1278. return pite;
  1279. }
  1280. //----------------------------------------------------------------------------
  1281. // Function: InsertIfByAddress
  1282. //
  1283. // inserts the given interface into the list of interfaces sorted by address.
  1284. // assumes the table is locked for writing
  1285. //----------------------------------------------------------------------------
  1286. DWORD
  1287. InsertIfByAddress(
  1288. PIF_TABLE pTable,
  1289. PIF_TABLE_ENTRY pITE
  1290. ) {
  1291. INT cmp;
  1292. PIF_TABLE_ENTRY pite;
  1293. PIPRIP_IP_ADDRESS paddr;
  1294. DWORD dwAddress, dwITEAddress;
  1295. PLIST_ENTRY phead, pfl;
  1296. phead = &pTable->IT_ListByAddress;
  1297. paddr = IPRIP_IF_ADDRESS_TABLE(pITE->ITE_Binding);
  1298. dwAddress = paddr->IA_Address;
  1299. //
  1300. // search for the insertion point
  1301. //
  1302. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1303. pite = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress);
  1304. paddr = IPRIP_IF_ADDRESS_TABLE(pite->ITE_Binding);
  1305. dwITEAddress = paddr->IA_Address;
  1306. if (INET_CMP(dwAddress, dwITEAddress, cmp) < 0) { break; }
  1307. else if (cmp == 0) { return ERROR_ALREADY_EXISTS; }
  1308. }
  1309. InsertTailList(pfl, &pITE->ITE_LinkByAddress);
  1310. return NO_ERROR;
  1311. }
  1312. //----------------------------------------------------------------------------
  1313. // Function: AddNeighborToIfConfig
  1314. //
  1315. // Adds a unicast neighbor to an interface config block.
  1316. //----------------------------------------------------------------------------
  1317. DWORD
  1318. AddNeighborToIfConfig(
  1319. DWORD dwRemoteAddress,
  1320. PIF_TABLE_ENTRY pite
  1321. ) {
  1322. BOOL bFound = FALSE;
  1323. DWORD dwErr = (DWORD) -1,
  1324. dwSize = 0,
  1325. dwCnt = 0;
  1326. PDWORD pdwAddr = NULL;
  1327. PIPRIP_IF_CONFIG pic = NULL,
  1328. picNew = NULL;
  1329. do
  1330. {
  1331. pic = pite-> ITE_Config;
  1332. //
  1333. // verify neighbor is not aready present
  1334. //
  1335. pdwAddr = IPRIP_IF_UNICAST_PEER_TABLE( pic );
  1336. for ( dwCnt = 0; dwCnt < pic-> IC_UnicastPeerCount; dwCnt++ )
  1337. {
  1338. if ( dwRemoteAddress == pdwAddr[ dwCnt ] )
  1339. {
  1340. bFound = TRUE;
  1341. break;
  1342. }
  1343. }
  1344. //
  1345. // entry exits, enable unicast peer mode and quit
  1346. //
  1347. if ( bFound )
  1348. {
  1349. LPSTR lpszAddr = INET_NTOA( dwRemoteAddress );
  1350. pic-> IC_UnicastPeerMode = IPRIP_PEER_ALSO;
  1351. dwErr = NO_ERROR;
  1352. if (lpszAddr != NULL) {
  1353. TRACE2(
  1354. IF,
  1355. "Unicast neighbor %s already present in configuration on interface %d",
  1356. lpszAddr, pite-> ITE_Index
  1357. );
  1358. }
  1359. break;
  1360. }
  1361. //
  1362. // allocate new config block
  1363. //
  1364. dwSize = IPRIP_IF_CONFIG_SIZE( pic ) + sizeof( DWORD );
  1365. picNew = RIP_ALLOC( dwSize );
  1366. if ( picNew == NULL )
  1367. {
  1368. dwErr = GetLastError();
  1369. TRACE3(
  1370. IF, "error %d allocating %d bytes for configuration on interface %d",
  1371. dwErr, dwSize, pite-> ITE_Index
  1372. );
  1373. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1374. break;
  1375. }
  1376. //
  1377. // copy base structure
  1378. //
  1379. CopyMemory( picNew, pic, sizeof( IPRIP_IF_CONFIG ) );
  1380. //
  1381. // copy uicast peer table
  1382. //
  1383. CopyMemory(
  1384. IPRIP_IF_UNICAST_PEER_TABLE( picNew ),
  1385. IPRIP_IF_UNICAST_PEER_TABLE( pic ),
  1386. pic-> IC_UnicastPeerCount * sizeof( DWORD )
  1387. );
  1388. //
  1389. // add new neighbor and set unicast neighbor mode
  1390. //
  1391. pdwAddr = IPRIP_IF_UNICAST_PEER_TABLE( picNew );
  1392. pdwAddr[ picNew-> IC_UnicastPeerCount++ ] = dwRemoteAddress;
  1393. picNew-> IC_UnicastPeerMode = IPRIP_PEER_ALSO;
  1394. //
  1395. // Copy accept and annouce filters
  1396. //
  1397. CopyMemory(
  1398. IPRIP_IF_ACCEPT_FILTER_TABLE( picNew ),
  1399. IPRIP_IF_ACCEPT_FILTER_TABLE( pic ),
  1400. pic-> IC_AcceptFilterCount * sizeof( IPRIP_IP_ADDRESS )
  1401. );
  1402. CopyMemory(
  1403. IPRIP_IF_ANNOUNCE_FILTER_TABLE( picNew ),
  1404. IPRIP_IF_ANNOUNCE_FILTER_TABLE( pic ),
  1405. pic-> IC_AnnounceFilterCount * sizeof( IPRIP_IP_ADDRESS )
  1406. );
  1407. //
  1408. // save the new config
  1409. //
  1410. pite-> ITE_Config = picNew;
  1411. RIP_FREE( pic );
  1412. dwErr = NO_ERROR;
  1413. } while ( FALSE );
  1414. return dwErr;
  1415. }
  1416. //----------------------------------------------------------------------------
  1417. // Function: CreatePeerTable
  1418. //
  1419. // initializes the given peer table
  1420. //----------------------------------------------------------------------------
  1421. DWORD
  1422. CreatePeerTable(
  1423. PPEER_TABLE pTable
  1424. ) {
  1425. DWORD dwErr;
  1426. PLIST_ENTRY ple, plstart, plend;
  1427. //
  1428. // initialize the hash table of peers
  1429. //
  1430. plstart = pTable->PT_HashTableByAddress;
  1431. plend = plstart + PEER_HASHTABLE_SIZE;
  1432. for (ple = plstart; ple < plend; ple++) {
  1433. InitializeListHead(ple);
  1434. }
  1435. //
  1436. // initialize the list of peers ordered by address
  1437. //
  1438. InitializeListHead(&pTable->PT_ListByAddress);
  1439. //
  1440. // initialize the multiple-read/single-write synchronization object
  1441. //
  1442. dwErr = CreateReadWriteLock(&pTable->PT_RWL);
  1443. if (dwErr == NO_ERROR) {
  1444. pTable->PT_Created = 0x12345678;
  1445. }
  1446. return dwErr;
  1447. }
  1448. //----------------------------------------------------------------------------
  1449. // Function: DeletePeerTable
  1450. //
  1451. // frees the resources used by the given peer table
  1452. // assumes the table is locked for writing
  1453. //----------------------------------------------------------------------------
  1454. DWORD
  1455. DeletePeerTable(
  1456. PPEER_TABLE pTable
  1457. ) {
  1458. PLIST_ENTRY ple, phead;
  1459. PPEER_TABLE_ENTRY ppte;
  1460. //
  1461. // empty the hash table of peer stats structures
  1462. //
  1463. phead = &pTable->PT_ListByAddress;
  1464. while (!IsListEmpty(phead)) {
  1465. ple = RemoveHeadList(phead);
  1466. ppte = CONTAINING_RECORD(ple, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1467. RIP_FREE(ppte);
  1468. }
  1469. //
  1470. // delete the table's synchronization object
  1471. //
  1472. DeleteReadWriteLock(&pTable->PT_RWL);
  1473. pTable->PT_Created = 0;
  1474. return NO_ERROR;
  1475. }
  1476. //----------------------------------------------------------------------------
  1477. // Function: CreatePeerEntry
  1478. //
  1479. // creates an entry in the given table for a peer with the given address
  1480. // assumes the table is locked for writing
  1481. //----------------------------------------------------------------------------
  1482. DWORD
  1483. CreatePeerEntry(
  1484. PPEER_TABLE pTable,
  1485. DWORD dwAddress,
  1486. PPEER_TABLE_ENTRY *ppEntry
  1487. ) {
  1488. DWORD dwErr;
  1489. PLIST_ENTRY ple, phead;
  1490. PPEER_TABLE_ENTRY ppte;
  1491. if (ppEntry != NULL) { *ppEntry = NULL; }
  1492. //
  1493. // make sure the entry does not already exist
  1494. //
  1495. ppte = GetPeerByAddress(pTable, dwAddress, GETMODE_EXACT, NULL);
  1496. if (ppte != NULL) {
  1497. if (ppEntry != NULL) { *ppEntry = ppte; }
  1498. return NO_ERROR;
  1499. }
  1500. //
  1501. // allocate memory for the new peer entry
  1502. //
  1503. ppte = RIP_ALLOC(sizeof(PEER_TABLE_ENTRY));
  1504. if (ppte == NULL) {
  1505. LPSTR lpszAddr = INET_NTOA(dwAddress);
  1506. dwErr = GetLastError();
  1507. if (lpszAddr != NULL) {
  1508. TRACE3(
  1509. IF, "error %d allocating %d bytes for peer %s entry",
  1510. dwErr, sizeof(PEER_TABLE_ENTRY), lpszAddr
  1511. );
  1512. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1513. }
  1514. return dwErr;
  1515. }
  1516. //
  1517. // initialize the fields
  1518. //
  1519. ppte->PTE_Address = dwAddress;
  1520. ZeroMemory(&ppte->PTE_Stats, sizeof(IPRIP_PEER_STATS));
  1521. //
  1522. // insert the peer stats entry in the hash table
  1523. //
  1524. phead = pTable->PT_HashTableByAddress + PEER_HASHVALUE(dwAddress);
  1525. InsertHeadList(phead, &ppte->PTE_HTLinkByAddress);
  1526. //
  1527. // insert the entry in the list sorted by address
  1528. //
  1529. dwErr = InsertPeerByAddress(pTable, ppte);
  1530. if (ppEntry != NULL) { *ppEntry = ppte; }
  1531. return NO_ERROR;
  1532. }
  1533. //----------------------------------------------------------------------------
  1534. // Function: DeletePeerEntry
  1535. //
  1536. // deletes the entry for the peer with the given address
  1537. // assumes the table is locked for writing
  1538. //----------------------------------------------------------------------------
  1539. DWORD
  1540. DeletePeerEntry(
  1541. PPEER_TABLE pTable,
  1542. DWORD dwAddress
  1543. ) {
  1544. PPEER_TABLE_ENTRY ppte;
  1545. //
  1546. // quit if the entry cannot be found
  1547. //
  1548. ppte = GetPeerByAddress(pTable, dwAddress, GETMODE_EXACT, NULL);
  1549. if (ppte == NULL) { return ERROR_INVALID_PARAMETER; }
  1550. //
  1551. // remove the entry from the hash-table
  1552. // and from the list sorted by address
  1553. //
  1554. RemoveEntryList(&ppte->PTE_LinkByAddress);
  1555. RemoveEntryList(&ppte->PTE_HTLinkByAddress);
  1556. RIP_FREE(ppte);
  1557. return NO_ERROR;
  1558. }
  1559. //----------------------------------------------------------------------------
  1560. // Function: GetPeerByAddress
  1561. //
  1562. // returns the entry for the peer with the given address
  1563. // assumes the table is locked for reading or writing
  1564. //----------------------------------------------------------------------------
  1565. PPEER_TABLE_ENTRY
  1566. GetPeerByAddress(
  1567. PPEER_TABLE pTable,
  1568. DWORD dwAddress,
  1569. DWORD dwGetMode,
  1570. PDWORD pdwErr
  1571. ) {
  1572. PLIST_ENTRY phead, pfl;
  1573. PPEER_TABLE_ENTRY ppte, ppterec;
  1574. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  1575. //
  1576. // return head of list if in GetFirst mode
  1577. //
  1578. if (dwGetMode == GETMODE_FIRST) {
  1579. phead = &pTable->PT_ListByAddress;
  1580. if (phead->Flink == phead) {
  1581. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1582. return NULL;
  1583. }
  1584. else {
  1585. pfl = phead->Flink;
  1586. return CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1587. }
  1588. }
  1589. phead = pTable->PT_HashTableByAddress + PEER_HASHVALUE(dwAddress);
  1590. ppte = NULL;
  1591. //
  1592. // search for the entry
  1593. //
  1594. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1595. ppterec = CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_HTLinkByAddress);
  1596. if (ppterec->PTE_Address == dwAddress) { ppte = ppterec; break; }
  1597. }
  1598. //
  1599. // return entry after the one found if in GetNext mode
  1600. //
  1601. if (dwGetMode == GETMODE_NEXT && ppte != NULL) {
  1602. phead = &pTable->PT_ListByAddress;
  1603. pfl = &ppte->PTE_LinkByAddress;
  1604. //
  1605. // return NULL if entry is last one
  1606. //
  1607. if (pfl->Flink == phead) {
  1608. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  1609. return NULL;
  1610. }
  1611. else {
  1612. pfl = pfl->Flink;
  1613. return CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1614. }
  1615. }
  1616. //
  1617. // if the peer wasn't found, this will still be NULL
  1618. //
  1619. return ppte;
  1620. }
  1621. //----------------------------------------------------------------------------
  1622. // Function: InsertPeerByAddress
  1623. //
  1624. // inserts the given entry into the list of peers sorted by address
  1625. // assumes the table is locked for writing
  1626. //----------------------------------------------------------------------------
  1627. DWORD
  1628. InsertPeerByAddress(
  1629. PPEER_TABLE pTable,
  1630. PPEER_TABLE_ENTRY pPTE
  1631. ) {
  1632. INT cmp;
  1633. PPEER_TABLE_ENTRY ppte;
  1634. DWORD dwAddress, dwPTEAddress;
  1635. PLIST_ENTRY phead, pfl;
  1636. dwAddress = pPTE->PTE_Address;
  1637. phead = &pTable->PT_ListByAddress;
  1638. //
  1639. // search for the peer entry
  1640. //
  1641. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1642. ppte = CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress);
  1643. dwPTEAddress = ppte->PTE_Address;
  1644. if (INET_CMP(dwAddress, dwPTEAddress, cmp) < 0) { break; }
  1645. else if (cmp == 0) { return ERROR_ALREADY_EXISTS; }
  1646. }
  1647. InsertTailList(pfl, &pPTE->PTE_LinkByAddress);
  1648. return NO_ERROR;
  1649. }
  1650. //----------------------------------------------------------------------------
  1651. // Function: CreateRouteTable
  1652. //
  1653. // Initializes a route table. Note that no synchronization is provided.
  1654. //----------------------------------------------------------------------------
  1655. DWORD
  1656. CreateRouteTable(
  1657. PROUTE_TABLE pTable
  1658. ) {
  1659. PLIST_ENTRY plstart, plend, ple;
  1660. //
  1661. // initialize the hash table buckets
  1662. //
  1663. plstart = pTable->RT_HashTableByNetwork;
  1664. plend = plstart + ROUTE_HASHTABLE_SIZE;
  1665. for (ple = plstart; ple < plend; ple++) {
  1666. InitializeListHead(ple);
  1667. }
  1668. pTable->RT_Created = 0x12345678;
  1669. return NO_ERROR;
  1670. }
  1671. //----------------------------------------------------------------------------
  1672. // Function: DeleteRouteTable
  1673. //
  1674. // Removes all entries from a route table and frees resources used.
  1675. //----------------------------------------------------------------------------
  1676. DWORD
  1677. DeleteRouteTable(
  1678. PROUTE_TABLE pTable
  1679. ) {
  1680. PROUTE_TABLE_ENTRY prte;
  1681. PLIST_ENTRY ple, plend, phead;
  1682. //
  1683. // empty the hash-table buckets
  1684. //
  1685. plend = pTable->RT_HashTableByNetwork + ROUTE_HASHTABLE_SIZE;
  1686. for (ple = plend - ROUTE_HASHTABLE_SIZE; ple < plend; ple++) {
  1687. while (!IsListEmpty(ple)) {
  1688. phead = RemoveHeadList(ple);
  1689. prte = CONTAINING_RECORD(phead, ROUTE_TABLE_ENTRY, RTE_Link);
  1690. RIP_FREE(prte);
  1691. }
  1692. }
  1693. pTable->RT_Created = 0;
  1694. return NO_ERROR;
  1695. }
  1696. //----------------------------------------------------------------------------
  1697. // Function: WriteSummaryRoutes
  1698. //
  1699. // Writes to RTM all entries which are marked as summary routes.
  1700. //----------------------------------------------------------------------------
  1701. DWORD
  1702. WriteSummaryRoutes(
  1703. PROUTE_TABLE pTable,
  1704. HANDLE hRtmHandle
  1705. ) {
  1706. DWORD dwFlags, dwErr;
  1707. PRIP_IP_ROUTE prir;
  1708. PROUTE_TABLE_ENTRY prte;
  1709. PLIST_ENTRY ple, phead, plstart, plend;
  1710. BOOL bRelDest = FALSE, bRelRoute = FALSE;
  1711. RTM_NET_ADDRESS rna;
  1712. RTM_DEST_INFO rdi;
  1713. PRTM_ROUTE_INFO prri;
  1714. CHAR szNetwork[20], szNetmask[20];
  1715. //
  1716. // allocate route info structure
  1717. //
  1718. prri = RIP_ALLOC(
  1719. RTM_SIZE_OF_ROUTE_INFO( ig.IG_RtmProfile.MaxNextHopsInRoute )
  1720. );
  1721. if (prri == NULL)
  1722. {
  1723. dwErr = GetLastError();
  1724. TRACE2(
  1725. ANY, "error %d allocated %d bytes in WriteSummaryRoutes",
  1726. dwErr, RTM_SIZE_OF_ROUTE_INFO(ig.IG_RtmProfile.MaxNextHopsInRoute)
  1727. );
  1728. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1729. return dwErr;
  1730. }
  1731. //
  1732. // go through each bucket writing routes
  1733. //
  1734. plstart = pTable->RT_HashTableByNetwork;
  1735. plend = plstart + ROUTE_HASHTABLE_SIZE;
  1736. for (phead = plstart; phead < plend; phead++) {
  1737. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  1738. prte = CONTAINING_RECORD(ple, ROUTE_TABLE_ENTRY, RTE_Link);
  1739. prir = &prte->RTE_Route;
  1740. bRelDest = bRelRoute = FALSE;
  1741. do {
  1742. //
  1743. // if a valid route exists do not overwrite it with
  1744. // a summary route
  1745. //
  1746. RTM_IPV4_SET_ADDR_AND_MASK(
  1747. &rna, prir-> RR_Network.N_NetNumber,
  1748. prir-> RR_Network.N_NetMask
  1749. );
  1750. dwErr = RtmGetExactMatchDestination(
  1751. hRtmHandle, &rna, RTM_BEST_PROTOCOL,
  1752. RTM_VIEW_MASK_UCAST, &rdi
  1753. );
  1754. if (dwErr == NO_ERROR)
  1755. {
  1756. bRelDest = TRUE;
  1757. //
  1758. // Get info for the best route to this destination
  1759. //
  1760. dwErr = RtmGetRouteInfo(
  1761. hRtmHandle, rdi.ViewInfo[0].Route,
  1762. prri, NULL
  1763. );
  1764. if (dwErr != NO_ERROR)
  1765. {
  1766. TRACE1(
  1767. ANY, "error %d getting route info in"
  1768. "WriteSummaryRoutes", dwErr
  1769. );
  1770. break;
  1771. }
  1772. bRelRoute = TRUE;
  1773. //
  1774. // Check if this route is active. If it is skip
  1775. // adding an inactive summary route
  1776. //
  1777. if (!(prri-> Flags & RTM_ROUTE_FLAGS_INACTIVE)) {
  1778. lstrcpy(szNetwork, INET_NTOA(prir-> RR_Network.N_NetNumber));
  1779. lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask));
  1780. TRACE2(
  1781. ROUTE,
  1782. "Route %s %s not overwritten in summary route addition",
  1783. szNetwork, szNetmask
  1784. );
  1785. break;
  1786. }
  1787. }
  1788. //
  1789. // you reach here only if you don't have an active
  1790. // route to the summary route's destination
  1791. //
  1792. //
  1793. // if this is a summary entry (i.e. is a RIP route
  1794. // with the summary entry set)
  1795. //
  1796. if (prir->RR_RoutingProtocol == PROTO_IP_RIP &&
  1797. GETROUTEFLAG(prir) == ROUTEFLAG_SUMMARY) {
  1798. LPSTR lpszAddr;
  1799. COMPUTE_ROUTE_METRIC(prir);
  1800. dwErr = AddRtmRoute(
  1801. hRtmHandle, prir, NULL, prte->RTE_TTL,
  1802. prte->RTE_HoldTTL, FALSE
  1803. );
  1804. lpszAddr = INET_NTOA(prir-> RR_Network.N_NetNumber);
  1805. if (lpszAddr != NULL) {
  1806. lstrcpy(szNetwork, lpszAddr );
  1807. lpszAddr = INET_NTOA(prir-> RR_Network.N_NetMask);
  1808. if (lpszAddr != NULL) {
  1809. lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask));
  1810. #if ROUTE_DBG
  1811. TRACE2(
  1812. ROUTE, "Adding summary route %s %s", szNetwork,
  1813. szNetmask
  1814. );
  1815. #endif
  1816. if (dwErr != NO_ERROR) {
  1817. LPSTR lpszNexthop =
  1818. INET_NTOA(prir->RR_NextHopAddress.N_NetNumber);
  1819. if (lpszNexthop != NULL) {
  1820. TRACE4(
  1821. ROUTE,
  1822. "error %d writing summary route to %s:%s via %s",
  1823. dwErr, szNetwork, szNetmask, lpszNexthop
  1824. );
  1825. LOGWARN2(
  1826. ADD_ROUTE_FAILED_1, szNetwork, lpszNexthop, dwErr
  1827. );
  1828. }
  1829. }
  1830. }
  1831. }
  1832. }
  1833. } while (FALSE);
  1834. if (dwErr != NO_ERROR) {
  1835. //
  1836. // in case one of the INET_NTOA statements failed above, just
  1837. // trace the fact that there was an error
  1838. //
  1839. TRACE1(
  1840. ROUTE,
  1841. "error %d writing summary route",
  1842. dwErr
  1843. );
  1844. }
  1845. //
  1846. // release handles as required
  1847. //
  1848. if (bRelRoute) {
  1849. dwErr = RtmReleaseRouteInfo(hRtmHandle, prri);
  1850. if (dwErr != NO_ERROR) {
  1851. TRACE1(
  1852. ANY, "error %d releasing route info in"
  1853. " WriteSummaryRoutes", dwErr
  1854. );
  1855. }
  1856. }
  1857. if (bRelDest) {
  1858. dwErr = RtmReleaseDestInfo(hRtmHandle, &rdi);
  1859. if (dwErr != NO_ERROR) {
  1860. TRACE1(
  1861. ANY, "error %d releasing route info in"
  1862. " WriteSummaryRoutes", dwErr
  1863. );
  1864. }
  1865. }
  1866. }
  1867. }
  1868. if (prri) { RIP_FREE(prri); }
  1869. return NO_ERROR;
  1870. }
  1871. //----------------------------------------------------------------------------
  1872. // Function: CreateRouteEntry
  1873. //
  1874. // Makes an entry in the route table for the given route.
  1875. //----------------------------------------------------------------------------
  1876. DWORD
  1877. CreateRouteEntry(
  1878. PROUTE_TABLE pTable,
  1879. PRIP_IP_ROUTE pRoute,
  1880. DWORD dwTTL,
  1881. DWORD dwHoldTTL
  1882. ) {
  1883. DWORD dwErr;
  1884. PLIST_ENTRY ple;
  1885. PROUTE_TABLE_ENTRY prte;
  1886. //
  1887. // see if the entry exists first
  1888. //
  1889. if ((prte = GetRouteByRoute(pTable, pRoute)) != NULL) {
  1890. //
  1891. // just update the metric if the new route has a lower one
  1892. //
  1893. if (GETROUTEMETRIC(&prte->RTE_Route) > GETROUTEMETRIC(pRoute)) {
  1894. SETROUTEMETRIC(&prte->RTE_Route, GETROUTEMETRIC(pRoute));
  1895. }
  1896. return NO_ERROR;
  1897. }
  1898. //
  1899. // allocate space for the new route
  1900. //
  1901. prte = RIP_ALLOC(sizeof(ROUTE_TABLE_ENTRY));
  1902. if (prte == NULL) {
  1903. dwErr = GetLastError();
  1904. TRACE2(
  1905. ANY, "error %d allocating %d bytes for route table entry",
  1906. dwErr, sizeof(ROUTE_TABLE_ENTRY)
  1907. );
  1908. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1909. return dwErr;
  1910. }
  1911. //
  1912. // initialize the entry's fields and copy the actual route structure
  1913. //
  1914. prte->RTE_TTL = dwTTL;
  1915. prte->RTE_HoldTTL = dwHoldTTL;
  1916. CopyMemory(&prte->RTE_Route, pRoute, sizeof(RIP_IP_ROUTE));
  1917. //
  1918. // insert the route in the hash table
  1919. //
  1920. ple = pTable->RT_HashTableByNetwork +
  1921. ROUTE_HASHVALUE(pRoute->RR_Network.N_NetNumber);
  1922. InsertHeadList(ple, &prte->RTE_Link);
  1923. #if ROUTE_DBG
  1924. {
  1925. LPSTR lpszAddr;
  1926. char szNet[20], szMask[20];
  1927. lpszAddr = INET_NTOA(pRoute-> RR_Network.N_NetNumber);
  1928. if (lpszAddr != NULL) {
  1929. lstrcpy(szNet, lpszAddr);
  1930. lpszAddr = INET_NTOA(pRoute-> RR_Network.N_NetMask);
  1931. if (lpszAddr != NULL) {
  1932. lstrcpy(szMask, lpszAddr);
  1933. lpszAddr = INET_NTOA(pRoute-> RR_NextHopAddress.N_NetNumber);
  1934. if (lpszAddr != NULL) {
  1935. TRACE4(
  1936. ROUTE, "Creating summary route : Route %s %s via %s"
  1937. "on interface %d",
  1938. szNet, szMask, lpszAddr, pRoute-> RR_InterfaceID
  1939. );
  1940. }
  1941. }
  1942. }
  1943. }
  1944. #endif
  1945. return NO_ERROR;
  1946. }
  1947. //----------------------------------------------------------------------------
  1948. // Function: DeleteRouteEntry
  1949. //
  1950. // Remove the entry which matches the given route.
  1951. //----------------------------------------------------------------------------
  1952. DWORD
  1953. DeleteRouteEntry(
  1954. PROUTE_TABLE pTable,
  1955. PRIP_IP_ROUTE pRoute
  1956. ) {
  1957. PROUTE_TABLE_ENTRY prte;
  1958. //
  1959. // find the route to be deleted
  1960. //
  1961. prte = GetRouteByRoute(pTable, pRoute);
  1962. if (prte == NULL) { return ERROR_INVALID_PARAMETER; }
  1963. //
  1964. // remove it from the hash table and free the memory it used
  1965. //
  1966. RemoveEntryList(&prte->RTE_Link);
  1967. RIP_FREE(prte);
  1968. return NO_ERROR;
  1969. }
  1970. //----------------------------------------------------------------------------
  1971. // Function: GetRouteByRoute
  1972. //
  1973. // Searches for the route entry which matches the given route, if any,
  1974. // and returns a pointer to it if it is found.
  1975. //----------------------------------------------------------------------------
  1976. PROUTE_TABLE_ENTRY
  1977. GetRouteByRoute(
  1978. PROUTE_TABLE pTable,
  1979. PRIP_IP_ROUTE pRoute
  1980. ) {
  1981. DWORD dwNetNumber;
  1982. PLIST_ENTRY phead, pfl;
  1983. PROUTE_TABLE_ENTRY prte, prterec;
  1984. //
  1985. // get the net number to be found and find the corresponding bucket
  1986. //
  1987. prte = NULL;
  1988. dwNetNumber = pRoute->RR_Network.N_NetNumber;
  1989. phead = pTable->RT_HashTableByNetwork + ROUTE_HASHVALUE(dwNetNumber);
  1990. //
  1991. // search the bucket for the route
  1992. //
  1993. for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) {
  1994. prterec = CONTAINING_RECORD(pfl, ROUTE_TABLE_ENTRY, RTE_Link);
  1995. if (prterec->RTE_Route.RR_Network.N_NetNumber == dwNetNumber) {
  1996. prte = prterec; break;
  1997. }
  1998. }
  1999. //
  2000. // if the route wasn't found, this will still be NULL
  2001. //
  2002. return prte;
  2003. }
  2004. //----------------------------------------------------------------------------
  2005. // Function: CreateBindingTable
  2006. //
  2007. // Initializes a table of bindings.
  2008. //----------------------------------------------------------------------------
  2009. DWORD
  2010. CreateBindingTable(
  2011. PBINDING_TABLE pTable
  2012. ) {
  2013. DWORD dwErr;
  2014. PLIST_ENTRY plend, ple;
  2015. //
  2016. // initialize the hash table of bindings
  2017. //
  2018. plend = pTable->BT_HashTableByNetwork + BINDING_HASHTABLE_SIZE;
  2019. for (ple = plend - BINDING_HASHTABLE_SIZE; ple < plend; ple++) {
  2020. InitializeListHead(ple);
  2021. }
  2022. //
  2023. // initialize the table's synchronization object
  2024. //
  2025. dwErr = CreateReadWriteLock(&pTable->BT_RWL);
  2026. if (dwErr == NO_ERROR) {
  2027. pTable->BT_Created = 0x12345678;
  2028. }
  2029. return dwErr;
  2030. }
  2031. //----------------------------------------------------------------------------
  2032. // Function: DeleteBindingTable
  2033. //
  2034. // Cleans up resources used by a binding table.
  2035. //----------------------------------------------------------------------------
  2036. DWORD
  2037. DeleteBindingTable(
  2038. PBINDING_TABLE pTable
  2039. ) {
  2040. PBINDING_TABLE_ENTRY pbte;
  2041. PLIST_ENTRY plend, ple, phead;
  2042. //
  2043. // destroy the synchronization object
  2044. //
  2045. DeleteReadWriteLock(&pTable->BT_RWL);
  2046. //
  2047. // empty the hash-table buckets
  2048. //
  2049. plend = pTable->BT_HashTableByNetwork + BINDING_HASHTABLE_SIZE;
  2050. for (ple = plend - BINDING_HASHTABLE_SIZE; ple < plend; ple++) {
  2051. while (!IsListEmpty(ple)) {
  2052. phead = RemoveHeadList(ple);
  2053. pbte = CONTAINING_RECORD(phead, BINDING_TABLE_ENTRY, BTE_Link);
  2054. RIP_FREE(pbte);
  2055. }
  2056. }
  2057. pTable->BT_Created = 0;
  2058. return NO_ERROR;
  2059. }
  2060. //----------------------------------------------------------------------------
  2061. // Function: CreateBindingEntry
  2062. //
  2063. // Adds a binding to the table.
  2064. // assumes the binding table is locked for writing
  2065. //----------------------------------------------------------------------------
  2066. DWORD
  2067. CreateBindingEntry(
  2068. PBINDING_TABLE pTable,
  2069. PIPRIP_IF_BINDING pib
  2070. ) {
  2071. INT cmp;
  2072. PLIST_ENTRY ple, phead;
  2073. PIPRIP_IP_ADDRESS paddr;
  2074. PBINDING_TABLE_ENTRY pbte;
  2075. DWORD i, dwErr, dwAddress, dwNetmask, dwNetwork;
  2076. //
  2077. // go through the IP addresses in the interface binding,
  2078. // adding each to the binding table
  2079. //
  2080. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  2081. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  2082. dwAddress = paddr->IA_Address;
  2083. dwNetmask = paddr->IA_Netmask;
  2084. //
  2085. // compute the network part of the binding
  2086. //
  2087. dwNetwork = (dwAddress & NETCLASS_MASK(dwAddress));
  2088. //
  2089. // get the hash bucket to which the binding belongs,
  2090. // and find the insertion point in the bucket
  2091. //
  2092. phead = pTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork);
  2093. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  2094. pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link);
  2095. INET_CMP(dwNetwork, pbte->BTE_Network, cmp);
  2096. if (cmp < 0) { break; }
  2097. else
  2098. if (cmp > 0) { continue; }
  2099. //
  2100. // the network parts are equal; further compare
  2101. // against the IP address fields
  2102. //
  2103. INET_CMP(dwAddress, pbte->BTE_Address, cmp);
  2104. if (cmp < 0) { break; }
  2105. else
  2106. if (cmp > 0) { continue; }
  2107. //
  2108. // the addresses are also equal; return an error
  2109. //
  2110. return ERROR_ALREADY_EXISTS;
  2111. }
  2112. //
  2113. // we now have the insertion point, so create the new item
  2114. //
  2115. pbte = RIP_ALLOC(sizeof(BINDING_TABLE_ENTRY));
  2116. if (pbte == NULL) {
  2117. dwErr = GetLastError();
  2118. TRACE2(
  2119. IF, "error %d allocating %d bytes for binding entry",
  2120. dwErr, sizeof(BINDING_TABLE_ENTRY)
  2121. );
  2122. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  2123. return dwErr;
  2124. }
  2125. pbte->BTE_Address = dwAddress;
  2126. pbte->BTE_Network = dwNetwork;
  2127. pbte->BTE_Netmask = dwNetmask;
  2128. //
  2129. // insert the entry
  2130. //
  2131. InsertTailList(ple, &pbte->BTE_Link);
  2132. }
  2133. return NO_ERROR;
  2134. }
  2135. //----------------------------------------------------------------------------
  2136. // Function: DeleteBindingEntry
  2137. //
  2138. // Removes a binding from the table.
  2139. // assumes the binding table is locked for writing
  2140. //----------------------------------------------------------------------------
  2141. DWORD
  2142. DeleteBindingEntry(
  2143. PBINDING_TABLE pTable,
  2144. PIPRIP_IF_BINDING pib
  2145. ) {
  2146. PLIST_ENTRY ple, phead;
  2147. PIPRIP_IP_ADDRESS paddr;
  2148. PBINDING_TABLE_ENTRY pbte;
  2149. DWORD i, dwNetwork, dwAddress, dwNetmask;
  2150. paddr = IPRIP_IF_ADDRESS_TABLE(pib);
  2151. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  2152. dwAddress = paddr->IA_Address;
  2153. dwNetmask = paddr->IA_Netmask;
  2154. //
  2155. // get the hash bucket to be searched
  2156. //
  2157. dwNetwork = (dwAddress & NETCLASS_MASK(dwAddress));
  2158. phead = pTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork);
  2159. //
  2160. // search the bucket for the binding specified
  2161. //
  2162. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  2163. pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link);
  2164. if (dwAddress != pbte->BTE_Address ||
  2165. dwNetmask != pbte->BTE_Netmask) {
  2166. continue;
  2167. }
  2168. //
  2169. // the entry to be deleted has been found;
  2170. // remove it from the list and free its memory
  2171. //
  2172. RemoveEntryList(&pbte->BTE_Link);
  2173. RIP_FREE(pbte);
  2174. break;
  2175. }
  2176. }
  2177. return NO_ERROR;
  2178. }
  2179. //---------------------------------------------------------------------------
  2180. // Function: GuessSubnetMask
  2181. //
  2182. // This function attempts to deduce the subnet mask of an IP address
  2183. // based on the configured addresses and masks on the local host.
  2184. // assumes the binding table is locked for reading or writing
  2185. //---------------------------------------------------------------------------
  2186. DWORD
  2187. GuessSubnetMask(
  2188. DWORD dwAddress,
  2189. PDWORD pdwNetclassMask
  2190. ) {
  2191. INT cmp;
  2192. PLIST_ENTRY ple, phead;
  2193. PBINDING_TABLE_ENTRY pbte;
  2194. DWORD dwNetwork, dwNetmask, dwGuessMask;
  2195. //
  2196. // the mask for a default route (0.0.0.0) is zero
  2197. //
  2198. if (dwAddress == 0) {
  2199. if (pdwNetclassMask != NULL) { *pdwNetclassMask = 0; }
  2200. return 0;
  2201. }
  2202. //
  2203. // the mask for the broadcast route is all-ones (255.255.255.255)
  2204. //
  2205. if (dwAddress == INADDR_BROADCAST) {
  2206. if (pdwNetclassMask != NULL) { *pdwNetclassMask = INADDR_BROADCAST; }
  2207. return INADDR_BROADCAST;
  2208. }
  2209. //
  2210. // otherwise, we start with the network-class mask
  2211. //
  2212. dwGuessMask = dwNetmask = NETCLASS_MASK(dwAddress);
  2213. if (pdwNetclassMask != NULL) { *pdwNetclassMask = dwNetmask; }
  2214. //
  2215. // if the route is a network route, we're done
  2216. //
  2217. if ((dwAddress & ~dwNetmask) == 0) { return dwNetmask; }
  2218. //
  2219. // otherwise, search through the bindings table
  2220. // to see if one is on the same network as this address
  2221. //
  2222. dwNetwork = (dwAddress & dwNetmask);
  2223. phead = ig.IG_BindingTable->BT_HashTableByNetwork +
  2224. BINDING_HASHVALUE(dwNetwork);
  2225. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  2226. pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link);
  2227. INET_CMP(dwNetwork, pbte->BTE_Network, cmp);
  2228. if (cmp < 0) { break; }
  2229. else
  2230. if (cmp > 0) { continue; }
  2231. //
  2232. // this entry is on the same network as the address passed in
  2233. // so see if the entry's netmask matches the address;
  2234. // if it does, we're done; otherwise, save this mask
  2235. // as a guess, and keep looking.
  2236. // note that this exhaustive search is the only way we can
  2237. // reliably guess masks for supernets
  2238. //
  2239. if ((dwAddress & pbte->BTE_Netmask) ==
  2240. (pbte->BTE_Address & pbte->BTE_Netmask)) {
  2241. return pbte->BTE_Netmask;
  2242. }
  2243. dwGuessMask = pbte->BTE_Netmask;
  2244. }
  2245. //
  2246. // return whatever has been our best guess so far
  2247. //
  2248. return dwGuessMask;
  2249. }
  2250. DWORD
  2251. AddRtmRoute(
  2252. RTM_ENTITY_HANDLE hRtmHandle,
  2253. PRIP_IP_ROUTE prir,
  2254. RTM_NEXTHOP_HANDLE hNextHop OPTIONAL,
  2255. DWORD dwTimeOut,
  2256. DWORD dwHoldTime,
  2257. BOOL bActive
  2258. )
  2259. /*++
  2260. Routine Description :
  2261. This function adds a route to the RTMv2 database. In addition it
  2262. creates the nexthop if one is not specified (via hNextHop), based
  2263. on the next hop i/f and address specified in the RIP route.
  2264. Parameters :
  2265. hRtmHandle - Entity registration handle
  2266. prir - RIP route to be added
  2267. hNextHop - Handle to the next hop to be used for the route
  2268. dwTimeout - Route timeout interval
  2269. dwHoldTime - Route holddown interval (after delete)
  2270. bActive - TRUE if the route being added is an active route,
  2271. FALSE otherwise (in RIP's case for summary routes)
  2272. Return Value :
  2273. NO_ERROR - Success
  2274. Rtm error code - Otherwise
  2275. Environment :
  2276. Invoked from ProcessRouteEntry and WriteSummaryRoutes
  2277. --*/
  2278. {
  2279. BOOL bRelDest = FALSE;
  2280. DWORD dwErr, dwChangeFlags = 0;
  2281. RTM_DEST_INFO rdi;
  2282. RTM_NEXTHOP_INFO rni;
  2283. RTM_ROUTE_INFO rri;
  2284. RTM_NET_ADDRESS rna;
  2285. CHAR szNetwork[20], szNetmask[20], szNextHop[20], szNextHopmask[20];
  2286. do {
  2287. //
  2288. // char strings used to print IP address/mask info
  2289. // Used in error cases only
  2290. //
  2291. lstrcpy(szNetwork, INET_NTOA(prir-> RR_Network.N_NetNumber));
  2292. lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask));
  2293. lstrcpy(szNextHop, INET_NTOA(prir-> RR_NextHopAddress.N_NetNumber));
  2294. lstrcpy(szNextHopmask, INET_NTOA(prir-> RR_NextHopAddress.N_NetMask));
  2295. //
  2296. // Zero out the next hop and route memory
  2297. //
  2298. ZeroMemory(&rni, sizeof(RTM_NEXTHOP_INFO));
  2299. ZeroMemory(&rri, sizeof(RTM_ROUTE_INFO));
  2300. if (hNextHop == NULL) {
  2301. //
  2302. // Find next hop.
  2303. //
  2304. rni.InterfaceIndex = prir-> RR_InterfaceID;
  2305. RTM_IPV4_SET_ADDR_AND_MASK(
  2306. &rni.NextHopAddress, prir-> RR_NextHopAddress.N_NetNumber,
  2307. IPV4_SOURCE_MASK
  2308. );
  2309. //
  2310. // Save the nexthop mask in the entity specific info
  2311. //
  2312. *((PDWORD)&rni.EntitySpecificInfo) = prir-> RR_NextHopAddress.N_NetMask;
  2313. rni.NextHopOwner = hRtmHandle;
  2314. dwErr = RtmFindNextHop(hRtmHandle, &rni, &hNextHop, NULL);
  2315. if (dwErr == ERROR_NOT_FOUND) {
  2316. //
  2317. // Next hop not found. Create one
  2318. //
  2319. dwErr = RtmAddNextHop(
  2320. hRtmHandle, &rni, &hNextHop, &dwChangeFlags
  2321. );
  2322. if (dwErr != NO_ERROR) {
  2323. TRACE3(
  2324. ROUTE, "error %d creating next hop %s %s",
  2325. dwErr, szNextHop, szNextHopmask
  2326. );
  2327. break;
  2328. }
  2329. }
  2330. else if (dwErr != NO_ERROR) {
  2331. TRACE3(
  2332. ANY, "error %d finding next hop %s %s", dwErr,
  2333. szNextHop, szNextHopmask
  2334. );
  2335. break;
  2336. }
  2337. }
  2338. //
  2339. // Build route info structure
  2340. //
  2341. RTM_IPV4_SET_ADDR_AND_MASK(
  2342. &rna, prir-> RR_Network.N_NetNumber, prir-> RR_Network.N_NetMask
  2343. );
  2344. rri.PrefInfo.Metric = prir-> RR_FamilySpecificData.FSD_Metric1;
  2345. rri.BelongsToViews = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST;
  2346. //
  2347. // set entity specific info
  2348. //
  2349. SETRIPTAG(&rri, GETROUTETAG(prir));
  2350. SETRIPFLAG(&rri, GETROUTEFLAG(prir));
  2351. //
  2352. // Set next hop info
  2353. //
  2354. rri.NextHopsList.NumNextHops = 1;
  2355. rri.NextHopsList.NextHops[0] = hNextHop;
  2356. rri.Neighbour = hNextHop;
  2357. //
  2358. // Call into router manager to set preference info
  2359. //
  2360. ig.IG_SupportFunctions.ValidateRoute(PROTO_IP_RIP, &rri, &rna);
  2361. //
  2362. // if this is an inactive route,
  2363. // - set route flag to inactive.
  2364. // - set the views for route to none
  2365. //
  2366. if ( !bActive ) {
  2367. rri.Flags1 = 0;
  2368. rri.Flags = RTM_ROUTE_FLAGS_INACTIVE;
  2369. rri.BelongsToViews = 0;
  2370. }
  2371. //
  2372. // Add route to dest, convert timeout to milliseconds
  2373. //
  2374. dwChangeFlags = RTM_ROUTE_CHANGE_FIRST;
  2375. dwErr = RtmAddRouteToDest(
  2376. hRtmHandle, NULL, &rna, &rri, dwTimeOut * 1000, NULL,
  2377. 0, NULL, &dwChangeFlags
  2378. );
  2379. if ( dwErr != NO_ERROR ) {
  2380. TRACE4(
  2381. ANY, "error %d adding route %s %s via %s",
  2382. dwErr, szNetwork, szNetmask, szNextHop
  2383. );
  2384. break;
  2385. }
  2386. if ( bActive )
  2387. {
  2388. //
  2389. // Hold destination if this is an active route
  2390. //
  2391. dwErr = RtmGetExactMatchDestination(
  2392. hRtmHandle, &rna, RTM_BEST_PROTOCOL,
  2393. RTM_VIEW_MASK_UCAST, &rdi
  2394. );
  2395. if ( dwErr != NO_ERROR ) {
  2396. TRACE3(
  2397. ANY, "error %d getting just added destination %s:%s",
  2398. dwErr, szNetwork, szNetmask
  2399. );
  2400. break;
  2401. }
  2402. bRelDest = TRUE;
  2403. dwErr = RtmHoldDestination(
  2404. hRtmHandle, rdi.DestHandle, RTM_VIEW_MASK_UCAST,
  2405. dwHoldTime * 1000
  2406. );
  2407. if ( dwErr != NO_ERROR ) {
  2408. TRACE3(
  2409. ANY, "error %d failed to hold destination %s %s",
  2410. dwErr, szNetwork, szNetmask
  2411. );
  2412. break;
  2413. }
  2414. }
  2415. } while(FALSE);
  2416. //
  2417. // release acquired handles
  2418. //
  2419. if ( bRelDest ) {
  2420. dwErr = RtmReleaseDestInfo( hRtmHandle, &rdi );
  2421. if ( dwErr != NO_ERROR ) {
  2422. TRACE3(
  2423. ANY, "error %d failed to relase just added destination %s %s",
  2424. dwErr, szNetwork, szNetmask
  2425. );
  2426. }
  2427. }
  2428. return dwErr;
  2429. }
  2430. DWORD
  2431. GetRouteInfo(
  2432. IN RTM_ROUTE_HANDLE hRoute,
  2433. IN PRTM_ROUTE_INFO pInRouteInfo OPTIONAL,
  2434. IN PRTM_DEST_INFO pInDestInfo OPTIONAL,
  2435. OUT PRIP_IP_ROUTE pRoute
  2436. )
  2437. /*++
  2438. Routine Description:
  2439. Wrapper for filling out the OSPF_RTMv2_ROUTE by retrieving various
  2440. RTM infos.
  2441. Arguments:
  2442. hRoute
  2443. pInRouteInfo
  2444. pInDestInfo
  2445. pRoute
  2446. Return Value:
  2447. RTM error code
  2448. --*/
  2449. {
  2450. DWORD dwErr;
  2451. RTM_ROUTE_INFO RouteInfo, *pRouteInfo;
  2452. RTM_ENTITY_INFO EntityInfo, *pEntityInfo;
  2453. RTM_DEST_INFO DestInfo, *pDestInfo;
  2454. RTM_NEXTHOP_INFO NextHopInfo, *pNextHopInfo;
  2455. pRouteInfo = NULL;
  2456. pEntityInfo = NULL;
  2457. pDestInfo = NULL;
  2458. pNextHopInfo = NULL;
  2459. do
  2460. {
  2461. ZeroMemory(pRoute, sizeof(RIP_IP_ROUTE));
  2462. //
  2463. // If the user hasnt already given us the route info, get it
  2464. //
  2465. if ( pInRouteInfo == NULL )
  2466. {
  2467. dwErr = RtmGetRouteInfo(
  2468. ig.IG_RtmHandle, hRoute, &RouteInfo, NULL
  2469. );
  2470. if ( dwErr != NO_ERROR )
  2471. {
  2472. TRACE1(
  2473. ANY, "GetRouteInfo: Error %d from RtmGetRouteInfo\n", dwErr
  2474. );
  2475. break;
  2476. }
  2477. pRouteInfo = &RouteInfo;
  2478. }
  2479. else
  2480. {
  2481. pRouteInfo = pInRouteInfo;
  2482. }
  2483. //
  2484. // If the user hasnt given us the dest info, get it
  2485. //
  2486. if ( pInDestInfo == NULL )
  2487. {
  2488. dwErr = RtmGetDestInfo(
  2489. ig.IG_RtmHandle, pRouteInfo->DestHandle,
  2490. 0, RTM_VIEW_MASK_UCAST, &DestInfo
  2491. );
  2492. if ( dwErr != NO_ERROR )
  2493. {
  2494. TRACE1(
  2495. ANY, "GetRouteInfo: Error %d from RtmGetDestInfo\n", dwErr
  2496. );
  2497. break;
  2498. }
  2499. pDestInfo = &DestInfo;
  2500. }
  2501. else
  2502. {
  2503. pDestInfo = pInDestInfo;
  2504. }
  2505. //
  2506. // Get owner info if the protocol is not us
  2507. //
  2508. if ( pRouteInfo-> RouteOwner != ig.IG_RtmHandle )
  2509. {
  2510. dwErr = RtmGetEntityInfo(
  2511. ig.IG_RtmHandle, pRouteInfo->RouteOwner, &EntityInfo
  2512. );
  2513. if ( dwErr != NO_ERROR )
  2514. {
  2515. TRACE1(
  2516. ANY, "GetRouteInfo: Error %d from RtmGetEntityInfo\n",
  2517. dwErr
  2518. );
  2519. break;
  2520. }
  2521. pEntityInfo = &EntityInfo;
  2522. }
  2523. //
  2524. // Get the info about the first next hop
  2525. //
  2526. dwErr = RtmGetNextHopInfo(
  2527. ig.IG_RtmHandle,
  2528. pRouteInfo->NextHopsList.NextHops[0],
  2529. &NextHopInfo
  2530. );
  2531. if ( dwErr != NO_ERROR )
  2532. {
  2533. TRACE1(
  2534. ANY, "GetRouteInfo: Error %d from RtmGetEntityInfo\n",
  2535. dwErr
  2536. );
  2537. break;
  2538. }
  2539. pNextHopInfo = &NextHopInfo;
  2540. //
  2541. // Now copy out all the info.
  2542. // First, the route info
  2543. //
  2544. pRoute-> RR_FamilySpecificData.FSD_Metric1 =
  2545. pRoute-> RR_FamilySpecificData.FSD_Metric =
  2546. pRouteInfo-> PrefInfo.Metric;
  2547. //
  2548. // copy out the protocol id from the entity info
  2549. //
  2550. if ( pEntityInfo != NULL )
  2551. {
  2552. pRoute-> RR_RoutingProtocol = pEntityInfo->EntityId.EntityProtocolId;
  2553. }
  2554. else
  2555. {
  2556. //
  2557. // this is a RIP route
  2558. //
  2559. pRoute-> RR_RoutingProtocol = PROTO_IP_RIP;
  2560. SETROUTEFLAG(pRoute, GETRIPFLAG(pRouteInfo));
  2561. SETROUTETAG(pRoute, GETRIPTAG(pRouteInfo));
  2562. }
  2563. //
  2564. // Copy out the dest info
  2565. //
  2566. RTM_IPV4_GET_ADDR_AND_MASK(
  2567. pRoute->RR_Network.N_NetNumber,
  2568. pRoute->RR_Network.N_NetMask,
  2569. &(pDestInfo->DestAddress)
  2570. );
  2571. pRoute-> hDest = pDestInfo-> DestHandle;
  2572. //
  2573. // Copy out the next hop info
  2574. //
  2575. RTM_IPV4_GET_ADDR_AND_MASK(
  2576. pRoute->RR_NextHopAddress.N_NetNumber,
  2577. pRoute->RR_NextHopAddress.N_NetMask,
  2578. &(pNextHopInfo->NextHopAddress)
  2579. );
  2580. //
  2581. // retrive saved next hop mask
  2582. //
  2583. pRoute-> RR_NextHopAddress.N_NetMask =
  2584. *((PDWORD)&pNextHopInfo-> EntitySpecificInfo);
  2585. pRoute-> RR_InterfaceID = pNextHopInfo->InterfaceIndex;
  2586. #if 0
  2587. {
  2588. char szNet[20], szMask[20], szNextHop[20], szNextHopMask[20];
  2589. lstrcpy(szNet, INET_NTOA(pRoute-> RR_Network.N_NetNumber));
  2590. lstrcpy(szMask, INET_NTOA(pRoute-> RR_Network.N_NetMask));
  2591. lstrcpy(szNextHop, INET_NTOA(pRoute-> RR_NextHopAddress.N_NetNumber));
  2592. lstrcpy(szNextHopMask, INET_NTOA(pRoute-> RR_NextHopAddress.N_NetMask));
  2593. TRACE5(
  2594. ROUTE, "GetRouteInfo : Route %s %s via %s %s on interface %d",
  2595. szNet, szMask, szNextHop, szNextHopMask,
  2596. pRoute-> RR_InterfaceID
  2597. );
  2598. TRACE3(
  2599. ROUTE, "Has metric %d, flag %x, tag %d",
  2600. GETROUTEMETRIC(pRoute), GETROUTEFLAG(pRoute),
  2601. GETROUTETAG(pRoute)
  2602. );
  2603. TRACE2(
  2604. ROUTE, "Protocol %d, original flag %d",
  2605. pRoute-> RR_RoutingProtocol, GETRIPFLAG(pRouteInfo)
  2606. );
  2607. }
  2608. #endif
  2609. } while( FALSE );
  2610. //
  2611. // Release the relevant infos
  2612. //
  2613. if ( pNextHopInfo != NULL )
  2614. {
  2615. RtmReleaseNextHopInfo( ig.IG_RtmHandle, pNextHopInfo );
  2616. }
  2617. if ( pEntityInfo != NULL )
  2618. {
  2619. RtmReleaseEntityInfo( ig.IG_RtmHandle, pEntityInfo );
  2620. }
  2621. //
  2622. // Release the route and dest infos only if we were not passed them
  2623. // in AND we successfully retrieved them
  2624. //
  2625. if ( ( pInDestInfo == NULL ) && ( pDestInfo != NULL ) )
  2626. {
  2627. RtmReleaseDestInfo( ig.IG_RtmHandle, pDestInfo );
  2628. }
  2629. if( ( pInRouteInfo == NULL ) && ( pRouteInfo != NULL ) )
  2630. {
  2631. RtmReleaseRouteInfo( ig.IG_RtmHandle, pRouteInfo );
  2632. }
  2633. return NO_ERROR;
  2634. }