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.

1631 lines
37 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: route.c
  5. //
  6. // History:
  7. // V Raman Feb-5-1998 Created.
  8. //
  9. // Routines that manipulate routes entries
  10. //============================================================================
  11. #include "pchmgm.h"
  12. #pragma hdrstop
  13. //----------------------------------------------------------------------------
  14. //
  15. // Route reference operations
  16. //
  17. //----------------------------------------------------------------------------
  18. //----------------------------------------------------------------------------
  19. // AddSourceGroupToRouteRefList
  20. //
  21. // This function inserts a reference for each MFE that uses this route
  22. // for it RPF check. It is invoked by the new packet function on creation
  23. // of an MFE.
  24. //----------------------------------------------------------------------------
  25. VOID
  26. AddSourceGroupToRouteRefList(
  27. DWORD dwSourceAddr,
  28. DWORD dwSourceMask,
  29. DWORD dwGroupAddr,
  30. DWORD dwGroupMask,
  31. HANDLE hNextHop,
  32. PBYTE pbBuffer
  33. )
  34. {
  35. BOOL bUnLock = FALSE, bMark = FALSE;
  36. DWORD dwErr;
  37. PMGM_LOCKED_LIST pmllMfeList;
  38. PBYTE pbOpaqueInfo = NULL;
  39. PRTM_DEST_INFO prdi = (PRTM_DEST_INFO) pbBuffer;
  40. PROUTE_REFERENCE_ENTRY prre = NULL, prreNew = NULL;
  41. TRACEROUTE0( ROUTE, "ENTERED AddSourceGroupToRouteRefList" );
  42. do
  43. {
  44. //
  45. // Create a route reference entry
  46. //
  47. prre = MGM_ALLOC( sizeof( ROUTE_REFERENCE_ENTRY ) );
  48. if ( prre == NULL )
  49. {
  50. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  51. TRACE1(
  52. ANY, "Failed to allocate %d bytes",
  53. sizeof( ROUTE_REFERENCE_ENTRY )
  54. );
  55. break;
  56. }
  57. prre-> dwSourceAddr = dwSourceAddr;
  58. prre-> dwSourceMask = dwSourceMask;
  59. prre-> dwGroupAddr = dwGroupAddr;
  60. prre-> dwGroupMask = dwGroupMask;
  61. prre-> hNextHop = hNextHop;
  62. InitializeListHead ( &prre-> leRefList );
  63. //
  64. // Lock the dest
  65. //
  66. dwErr = RtmLockDestination(
  67. g_hRtmHandle, prdi-> DestHandle, TRUE, TRUE
  68. );
  69. if ( dwErr != NO_ERROR )
  70. {
  71. TRACE1( ANY, "Failed to lock dest %x", dwErr );
  72. break;
  73. }
  74. bUnLock = TRUE;
  75. //
  76. // Get the opaque pointer
  77. //
  78. dwErr = RtmGetOpaqueInformationPointer(
  79. g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo
  80. );
  81. if ( dwErr != NO_ERROR )
  82. {
  83. TRACE1( ANY, "Failed to retrieve opaque pointer %x", dwErr );
  84. break;
  85. }
  86. if ( *( ( PBYTE * ) pbOpaqueInfo ) == NULL )
  87. {
  88. //
  89. // NULL opaque pointer implies this is the first MFe that
  90. // depends on this route
  91. //
  92. //
  93. // create a locked list
  94. //
  95. pmllMfeList = MGM_ALLOC( sizeof( MGM_LOCKED_LIST ) );
  96. if ( pmllMfeList == NULL )
  97. {
  98. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  99. TRACE1(
  100. ANY, "AddSourceGroupToRouteRefList : "
  101. "Failed to allocate route ref list %x", dwErr
  102. );
  103. break;
  104. }
  105. CREATE_LOCKED_LIST( pmllMfeList );
  106. //
  107. // insert the element into the list
  108. //
  109. InsertTailList(
  110. &( pmllMfeList-> leHead ), &( prre-> leRefList )
  111. );
  112. //
  113. // set the opaque pointer
  114. //
  115. *( ( PBYTE *) pbOpaqueInfo ) = (PBYTE) pmllMfeList;
  116. //
  117. // Mark the destination
  118. //
  119. bMark = TRUE;
  120. }
  121. else
  122. {
  123. pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE *) pbOpaqueInfo );
  124. //
  125. // Acquire the list lock
  126. //
  127. ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  128. //
  129. // release the dest lock
  130. //
  131. bUnLock = FALSE;
  132. dwErr = RtmLockDestination(
  133. g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE
  134. );
  135. if ( dwErr != NO_ERROR )
  136. {
  137. TRACE1( ANY, "Failed to release dest %x", dwErr );
  138. }
  139. //
  140. // Insert the rre into the list (in its appropriate place)
  141. //
  142. if ( !FindRouteRefEntry(
  143. &pmllMfeList-> leHead, dwSourceAddr, dwSourceMask,
  144. dwGroupAddr, dwGroupMask, &prreNew
  145. ) )
  146. {
  147. InsertTailList(
  148. ( prreNew ) ? &prreNew-> leRefList :
  149. &pmllMfeList-> leHead,
  150. &prre-> leRefList
  151. );
  152. }
  153. else
  154. {
  155. TRACE1(
  156. ANY, "Reference already exists for source %x", dwSourceAddr
  157. );
  158. MGM_FREE( prre );
  159. }
  160. //
  161. // release the list lock
  162. //
  163. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  164. dwErr = NO_ERROR;
  165. }
  166. } while ( FALSE );
  167. //
  168. // In case of error , free the allocation for route reference
  169. //
  170. if ( ( dwErr != NO_ERROR ) && ( prre != NULL ) )
  171. {
  172. MGM_FREE( prre );
  173. }
  174. //
  175. // release the dest lock
  176. //
  177. if ( bUnLock )
  178. {
  179. dwErr = RtmLockDestination(
  180. g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE
  181. );
  182. if ( dwErr != NO_ERROR )
  183. {
  184. TRACE1( ANY, "Failed to release dest %x", dwErr );
  185. }
  186. }
  187. //
  188. // mark dest if required
  189. //
  190. if ( bMark )
  191. {
  192. dwErr = RtmMarkDestForChangeNotification(
  193. g_hRtmHandle, g_hNotificationHandle,
  194. prdi-> DestHandle, TRUE
  195. );
  196. if ( dwErr != NO_ERROR )
  197. {
  198. TRACE1( ANY, "Failed to mark destination %x:", dwErr );
  199. }
  200. }
  201. TRACEROUTE0( ROUTE, "LEAVING AddSourceGroupToRouteRefList" );
  202. }
  203. //----------------------------------------------------------------------------
  204. // FindRouteRefEntry
  205. //
  206. // Finds a specified (source, group ) entry in the MFE reference list
  207. // for a route.
  208. //
  209. // If the entry is found a pointer to the entry is returned in the parameter
  210. // pprre.
  211. // If the entry is not found a pointer to the "next" entry is returned.
  212. //----------------------------------------------------------------------------
  213. BOOL
  214. FindRouteRefEntry(
  215. PLIST_ENTRY pleRefList,
  216. DWORD dwSourceAddr,
  217. DWORD dwSourceMask,
  218. DWORD dwGroupAddr,
  219. DWORD dwGroupMask,
  220. PROUTE_REFERENCE_ENTRY * pprre
  221. )
  222. {
  223. BOOL bFound = FALSE;
  224. INT iCmp;
  225. PLIST_ENTRY pleRef;
  226. PROUTE_REFERENCE_ENTRY prre;
  227. TRACEROUTE0( ROUTE, "ENTERED RouteRefEntry" );
  228. do
  229. {
  230. *pprre = NULL;
  231. pleRef = pleRefList-> Flink;
  232. while ( pleRef != pleRefList )
  233. {
  234. prre = CONTAINING_RECORD(
  235. pleRef, ROUTE_REFERENCE_ENTRY, leRefList
  236. );
  237. //
  238. // is same group
  239. //
  240. if ( INET_CMP( prre-> dwGroupAddr, dwGroupAddr, iCmp ) < 0 )
  241. {
  242. pleRef = pleRef-> Flink;
  243. continue;
  244. }
  245. else if ( iCmp > 0 )
  246. {
  247. //
  248. // past possible group entry
  249. //
  250. *pprre = prre;
  251. break;
  252. }
  253. //
  254. // same group, now look for source
  255. //
  256. if ( INET_CMP( prre-> dwSourceAddr, dwSourceAddr, iCmp ) < 0 )
  257. {
  258. pleRef = pleRef-> Flink;
  259. continue;
  260. }
  261. else if ( iCmp > 0 )
  262. {
  263. //
  264. // past possible source entry
  265. //
  266. *pprre = prre;
  267. break;
  268. }
  269. //
  270. // found entry
  271. //
  272. *pprre = prre;
  273. bFound = TRUE;
  274. break;
  275. }
  276. } while ( FALSE );
  277. TRACEROUTE1( ROUTE, "LEAVING RouteRefEntry : %d", bFound );
  278. return bFound;
  279. }
  280. //----------------------------------------------------------------------------
  281. // DeletRouteRef
  282. //
  283. //----------------------------------------------------------------------------
  284. VOID
  285. DeleteRouteRef(
  286. PROUTE_REFERENCE_ENTRY prre
  287. )
  288. {
  289. TRACEROUTE0( ROUTE, "ENTERED DeleteRefEntry" );
  290. RemoveEntryList( &prre-> leRefList );
  291. MGM_FREE( prre );
  292. TRACEROUTE0( ROUTE, "LEAVING DeleteRefEntry" );
  293. }
  294. DWORD
  295. WINAPI
  296. RtmChangeNotificationCallback(
  297. RTM_ENTITY_HANDLE hRtmHandle,
  298. RTM_EVENT_TYPE retEventType,
  299. PVOID pvContext1,
  300. PVOID pvContext2
  301. )
  302. {
  303. DWORD dwErr = NO_ERROR;
  304. if ( !ENTER_MGM_API() )
  305. {
  306. TRACE0( ANY, "RtmChangeNotificationCallback : Failed to enter" );
  307. return ERROR_CAN_NOT_COMPLETE;
  308. }
  309. TRACE0( ROUTE, "ENTERED RtmChangeNotificationCallback" );
  310. do
  311. {
  312. //
  313. // Ignore all notifications except change notifications
  314. //
  315. if ( retEventType != RTM_CHANGE_NOTIFICATION )
  316. {
  317. break;
  318. }
  319. //
  320. // Queue work function to process changed destinations
  321. //
  322. dwErr = QueueMgmWorker(
  323. WorkerFunctionProcessRtmChangeNotification, NULL
  324. );
  325. if ( dwErr != NO_ERROR )
  326. {
  327. TRACE1( ANY, "Failed to queue work item", dwErr );
  328. }
  329. } while ( FALSE );
  330. LEAVE_MGM_API();
  331. TRACE1( ROUTE, "LEAVING RtmChangeNotificationCallback : %d", dwErr );
  332. return dwErr;
  333. }
  334. VOID
  335. WorkerFunctionProcessRtmChangeNotification(
  336. PVOID pvContext
  337. )
  338. {
  339. BOOL bMarked = FALSE, bDone = FALSE;
  340. DWORD dwErr, dwNumDests;
  341. RTM_DEST_INFO rdi;
  342. if ( !ENTER_MGM_WORKER() )
  343. {
  344. TRACE0(
  345. ANY, "WorkerFunctionProcessRtmChangeNotification : Failed to enter"
  346. );
  347. return;
  348. }
  349. TRACE0( ROUTE, "ENTERED WorkerFunctionRtmChangeNotification" );
  350. do
  351. {
  352. //
  353. // Get route changes one at a time
  354. //
  355. dwNumDests = 1;
  356. dwErr = RtmGetChangedDests(
  357. g_hRtmHandle, g_hNotificationHandle, &dwNumDests, &rdi
  358. );
  359. if ( ( dwErr != NO_ERROR ) && ( dwErr != ERROR_NO_MORE_ITEMS ) )
  360. {
  361. TRACE1(
  362. ANY, "RtmGetChangedDests failed with error : %x",
  363. dwErr
  364. );
  365. break;
  366. }
  367. //
  368. // if there are no changed dests, quit.
  369. //
  370. if ( dwNumDests == 0 )
  371. {
  372. TRACE0( ANY, "RtmGetChangedDests returns 0 dests" );
  373. break;
  374. }
  375. //
  376. // There are dests. Check if there are no more dests.
  377. // If so set a flag to quit processing after this one
  378. //
  379. if ( dwErr == ERROR_NO_MORE_ITEMS )
  380. {
  381. bDone = TRUE;
  382. }
  383. //
  384. // Check if there any routes for this destination
  385. //
  386. if ( rdi.ViewInfo[ 0 ].Route == NULL )
  387. {
  388. //
  389. // No routes, assume this to be a delete
  390. //
  391. dwErr = ProcessRouteDelete( &rdi );
  392. }
  393. else
  394. {
  395. //
  396. // Check if dest is marked for change notification
  397. //
  398. dwErr = RtmIsMarkedForChangeNotification(
  399. g_hRtmHandle, g_hNotificationHandle, rdi.DestHandle,
  400. &bMarked
  401. );
  402. if ( dwErr != NO_ERROR )
  403. {
  404. TRACE1(
  405. ANY, "RtmIsMarkedForChangeNotification failed with error : %x",
  406. dwErr
  407. );
  408. break;
  409. }
  410. //
  411. // Process this destination
  412. //
  413. ( bMarked ) ? ProcessRouteUpdate( &rdi ) :
  414. ProcessUnMarkedDestination( &rdi );
  415. } while ( FALSE );
  416. //
  417. // Release changed destinations
  418. //
  419. dwErr = RtmReleaseChangedDests(
  420. g_hRtmHandle, g_hNotificationHandle, 1, &rdi
  421. );
  422. if ( dwErr != NO_ERROR )
  423. {
  424. TRACE1( ANY, "Failed to released destination", dwErr );
  425. }
  426. } while ( !bDone );
  427. LEAVE_MGM_WORKER();
  428. TRACE0( ROUTE, "LEAVING WorkerFunctionRtmChangeNotification" );
  429. }
  430. DWORD
  431. ProcessUnMarkedDestination(
  432. PRTM_DEST_INFO prdi
  433. )
  434. {
  435. BOOL bRelDest = FALSE, bMarked = FALSE, bUnLock = FALSE,
  436. bRelRouteRef = FALSE, bUnMark = FALSE;
  437. DWORD dwErr, dwDestMask;
  438. PBYTE pbOpaqueInfo = NULL;
  439. PLIST_ENTRY ple, pleTemp;
  440. PROUTE_REFERENCE_ENTRY prre;
  441. PMGM_LOCKED_LIST pmllMfeList = NULL;
  442. RTM_DEST_INFO rdiLessSpecificDest;
  443. do
  444. {
  445. //
  446. // Get next less specific destination
  447. //
  448. dwErr = RtmGetLessSpecificDestination(
  449. g_hRtmHandle, prdi-> DestHandle, RTM_BEST_PROTOCOL,
  450. RTM_VIEW_MASK_MCAST, &rdiLessSpecificDest
  451. );
  452. if ( dwErr != NO_ERROR )
  453. {
  454. TRACE1( ANY, "Failed to get less specific destination", dwErr );
  455. break;
  456. }
  457. bRelDest = TRUE;
  458. //
  459. // Check if it is marked
  460. //
  461. dwErr = RtmIsMarkedForChangeNotification(
  462. g_hRtmHandle, g_hNotificationHandle,
  463. rdiLessSpecificDest.DestHandle, &bMarked
  464. );
  465. if ( dwErr != NO_ERROR )
  466. {
  467. TRACE1( ANY, "Failed to check if dest is marked", dwErr );
  468. break;
  469. }
  470. //
  471. // if marked
  472. //
  473. if ( bMarked )
  474. {
  475. //
  476. // it is marked. Lock it
  477. //
  478. dwErr = RtmLockDestination(
  479. g_hRtmHandle,
  480. rdiLessSpecificDest.DestHandle,
  481. TRUE, TRUE
  482. );
  483. if ( dwErr != NO_ERROR )
  484. {
  485. TRACE1( ANY, "Failed to lock less specific dest : %x", dwErr );
  486. break;
  487. }
  488. bUnLock = TRUE;
  489. //
  490. // Get its opaque pointer
  491. //
  492. dwErr = RtmGetOpaqueInformationPointer(
  493. g_hRtmHandle, rdiLessSpecificDest.DestHandle,
  494. &pbOpaqueInfo
  495. );
  496. if ( dwErr != NO_ERROR )
  497. {
  498. TRACE1(
  499. ANY, "Failed to opaque ptr for less specific dest : %x",
  500. dwErr
  501. );
  502. break;
  503. }
  504. //
  505. // Check if it is NULL
  506. //
  507. if ( *( ( PBYTE * ) pbOpaqueInfo ) == NULL )
  508. {
  509. bUnMark = TRUE;
  510. break;
  511. }
  512. pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE * ) pbOpaqueInfo );
  513. //
  514. // lock the route reference list
  515. //
  516. ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  517. bRelRouteRef = TRUE;
  518. //
  519. // Unlock the dest
  520. //
  521. bUnLock = FALSE;
  522. dwErr = RtmLockDestination(
  523. g_hRtmHandle,
  524. rdiLessSpecificDest.DestHandle,
  525. TRUE, FALSE
  526. );
  527. if ( dwErr != NO_ERROR )
  528. {
  529. TRACE1( ANY, "Failed to unlock less specific dest : %x", dwErr );
  530. break;
  531. }
  532. //
  533. // Create MASK for new dest. from len
  534. //
  535. dwDestMask = RTM_IPV4_MASK_FROM_LEN(
  536. prdi-> DestAddress.NumBits
  537. );
  538. //
  539. // For each reference
  540. //
  541. for ( ple = pmllMfeList-> leHead.Flink;
  542. ple != &pmllMfeList-> leHead; )
  543. {
  544. prre = CONTAINING_RECORD(
  545. ple, ROUTE_REFERENCE_ENTRY, leRefList
  546. );
  547. //
  548. // Check if this MFE would fall under the
  549. // more specific route
  550. //
  551. if ( ( prre-> dwSourceAddr & dwDestMask ) ==
  552. (( * ( PDWORD ) prdi-> DestAddress.AddrBits ) & dwDestMask) )
  553. {
  554. //
  555. // if it does, delete the MFE. This will force its
  556. // recreation, at which time it will be made dependent
  557. // on the more specific route
  558. //
  559. pleTemp = ple-> Flink;
  560. RemoveEntryList( ple );
  561. DeleteMfeAndRefs( ple );
  562. ple = pleTemp;
  563. }
  564. else
  565. {
  566. ple = ple-> Flink;
  567. }
  568. }
  569. //
  570. // if Ref list is empty, it needs to be deleted too.
  571. //
  572. if ( IsListEmpty( &pmllMfeList-> leHead ) )
  573. {
  574. //
  575. // to delete the opaque pointer, the dest needs to be locked
  576. // (via RtmLockDestination)
  577. //
  578. // the dest lock is held before locking the route reference
  579. // list ( via ACQUIRE_ROUTE_LOCK_EXCLUSIVE )
  580. //
  581. // At this point in the code, the route reference is locked
  582. // but the dest is not locked.
  583. //
  584. // To lock it, the route reference lock is first released
  585. // (via RELEASE_ROUTE_LOCK_EXCLUSIVE).
  586. //
  587. // The opaque pointer is then acquired, route ref list locked,
  588. // and double checked for emptiness. This round-about ensures
  589. // that the route ref is not deleted while there are threads
  590. // waiting on its lock. This can happen since the dest lock
  591. // is not held for most of the operations here
  592. //
  593. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  594. bRelRouteRef = FALSE;
  595. //
  596. // Lock dest
  597. //
  598. dwErr = RtmLockDestination(
  599. g_hRtmHandle,
  600. rdiLessSpecificDest.DestHandle,
  601. TRUE, TRUE
  602. );
  603. if ( dwErr != NO_ERROR )
  604. {
  605. TRACE1( ANY, "Failed to lock dest : %x", dwErr );
  606. break;
  607. }
  608. bUnLock = TRUE;
  609. //
  610. // Get Opaque pointer again
  611. //
  612. dwErr = RtmGetOpaqueInformationPointer(
  613. g_hRtmHandle, rdiLessSpecificDest.DestHandle,
  614. &pbOpaqueInfo
  615. );
  616. if ( dwErr != NO_ERROR || ((* ((PBYTE *)pbOpaqueInfo) == NULL)) )
  617. {
  618. TRACE1( ANY, "Failed to get opaque ptr : %x", dwErr );
  619. break;
  620. }
  621. //
  622. // Get ref. list and lock it.
  623. //
  624. pmllMfeList = ( PMGM_LOCKED_LIST ) * ( ( PBYTE * ) pbOpaqueInfo );
  625. ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  626. bRelRouteRef = TRUE;
  627. //
  628. // If list is still empty
  629. //
  630. if ( IsListEmpty( &pmllMfeList-> leHead ) )
  631. {
  632. //
  633. // Clear opaque pointer info
  634. //
  635. * ( PBYTE * )pbOpaqueInfo = NULL;
  636. //
  637. // release list lock
  638. //
  639. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  640. bRelRouteRef = FALSE;
  641. MGM_FREE( pmllMfeList );
  642. //
  643. // unmark the dest. Change notifications for this
  644. // dest are no longer required.
  645. //
  646. bUnMark = TRUE;
  647. }
  648. }
  649. else
  650. {
  651. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  652. bRelRouteRef = FALSE;
  653. }
  654. }
  655. } while ( FALSE );
  656. //
  657. // release route ref list lock
  658. //
  659. if ( bRelRouteRef )
  660. {
  661. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  662. }
  663. //
  664. // Unlock dest
  665. //
  666. if ( bUnLock )
  667. {
  668. dwErr = RtmLockDestination(
  669. g_hRtmHandle,
  670. rdiLessSpecificDest.DestHandle,
  671. TRUE, FALSE
  672. );
  673. if ( dwErr != NO_ERROR )
  674. {
  675. TRACE1( ANY, "Failed to lock dest : %x", dwErr );
  676. }
  677. }
  678. //
  679. // Unmark dest
  680. //
  681. if ( bUnMark )
  682. {
  683. dwErr = RtmMarkDestForChangeNotification(
  684. g_hRtmHandle, g_hNotificationHandle,
  685. rdiLessSpecificDest.DestHandle, FALSE
  686. );
  687. if ( dwErr != NO_ERROR )
  688. {
  689. TRACE1( ANY, "Failed to unmark DEST: %x", dwErr );
  690. }
  691. }
  692. return dwErr;
  693. }
  694. DWORD
  695. ProcessRouteDelete(
  696. PRTM_DEST_INFO prdi
  697. )
  698. {
  699. BOOL bMark = FALSE;
  700. DWORD dwErr;
  701. PMGM_LOCKED_LIST pmllMfeList;
  702. PBYTE pbOpaqueInfo = NULL;
  703. PLIST_ENTRY ple;
  704. do
  705. {
  706. //
  707. // Cannot lock dest. Is that OK ?
  708. //
  709. //
  710. // Check if this is a marked destination
  711. // Only marked destinations are processed
  712. //
  713. dwErr = RtmIsMarkedForChangeNotification(
  714. g_hRtmHandle, g_hNotificationHandle,
  715. prdi-> DestHandle, &bMark
  716. );
  717. if ( dwErr != NO_ERROR )
  718. {
  719. TRACE1( ANY, "Failed to check if dest marked", dwErr );
  720. break;
  721. }
  722. if ( !bMark )
  723. {
  724. TRACE0(
  725. ANY, "Ignoring change notification for unmarked destination"
  726. );
  727. break;
  728. }
  729. //
  730. // Get Opaque pointer & the list of MFEs dependent
  731. // on this dest
  732. //
  733. dwErr = RtmGetOpaqueInformationPointer(
  734. g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo
  735. );
  736. if ( (dwErr != NO_ERROR) || ((* ((PBYTE *)pbOpaqueInfo) == NULL)) )
  737. {
  738. TRACE1( ANY, "Failed to get opaque ptr", dwErr );
  739. break;
  740. }
  741. //
  742. // Clear out the opaque pointer
  743. //
  744. pmllMfeList = (PMGM_LOCKED_LIST) *( ( PBYTE * ) pbOpaqueInfo );
  745. *( ( PBYTE * ) pbOpaqueInfo ) = NULL;
  746. //
  747. // Cannot unlock dest. Is that ok ?
  748. //
  749. //
  750. // Check if the opaque pointer is NULL
  751. //
  752. if ( pmllMfeList == NULL )
  753. {
  754. TRACE0( ANY, "Opaque pointer is NULL" );
  755. break;
  756. }
  757. //
  758. // Delete all the MFEs
  759. //
  760. ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  761. while ( !IsListEmpty( &pmllMfeList-> leHead ) )
  762. {
  763. ple = RemoveHeadList( &pmllMfeList-> leHead );
  764. DeleteMfeAndRefs( ple );
  765. }
  766. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  767. MGM_FREE( pmllMfeList );
  768. dwErr = NO_ERROR;
  769. } while ( FALSE );
  770. return dwErr;
  771. }
  772. DWORD
  773. ProcessRouteUpdate(
  774. PRTM_DEST_INFO prdi
  775. )
  776. {
  777. BOOL bUnLock = FALSE, bUnMark = FALSE,
  778. bFound = FALSE;
  779. DWORD dwSize, dwErr, dwInd;
  780. PBYTE pbOpaqueInfo = NULL;
  781. PMGM_LOCKED_LIST pmllMfeList;
  782. PLIST_ENTRY ple, pleTemp;
  783. PROUTE_REFERENCE_ENTRY prre;
  784. PRTM_ROUTE_INFO prri;
  785. //
  786. // the processing goes as follows :
  787. //
  788. do
  789. {
  790. //
  791. // Allocate route info structure
  792. //
  793. dwSize = sizeof ( RTM_ROUTE_INFO ) +
  794. ( g_rrpRtmProfile.MaxNextHopsInRoute - 1 ) *
  795. sizeof( RTM_NEXTHOP_HANDLE );
  796. prri = MGM_ALLOC( dwSize );
  797. if ( prri == NULL )
  798. {
  799. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  800. TRACE1( ANY, "Failed to allocate route info, size : %x", dwSize );
  801. break;
  802. }
  803. //
  804. // Lock destination
  805. //
  806. dwErr = RtmLockDestination(
  807. g_hRtmHandle, prdi-> DestHandle, TRUE, TRUE
  808. );
  809. if ( dwErr != NO_ERROR )
  810. {
  811. TRACE1( ANY, "Failed to lock dest : %x", dwErr );
  812. break;
  813. }
  814. bUnLock = TRUE;
  815. //
  816. // Get Opaque pointer
  817. //
  818. dwErr = RtmGetOpaqueInformationPointer(
  819. g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo
  820. );
  821. if ( dwErr != NO_ERROR )
  822. {
  823. TRACE1( ANY, "Failed to get opaque ptr : %x", dwErr );
  824. break;
  825. }
  826. //
  827. // Unmark dest if there are no MFEs that depend on it.
  828. //
  829. if ( *( ( PBYTE * ) pbOpaqueInfo ) == NULL )
  830. {
  831. bUnMark = TRUE;
  832. break;
  833. }
  834. pmllMfeList = (PMGM_LOCKED_LIST) *( ( PBYTE * ) pbOpaqueInfo );
  835. //
  836. // get route ref list lock
  837. //
  838. ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  839. //
  840. // Unlock dest
  841. //
  842. bUnLock = FALSE;
  843. dwErr = RtmLockDestination(
  844. g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE
  845. );
  846. if ( dwErr != NO_ERROR )
  847. {
  848. TRACE1( ANY, "Failed to lock dest : %x", dwErr );
  849. break;
  850. }
  851. //
  852. // Get the route info for the best UNICAST route on dest
  853. //
  854. dwErr = RtmGetRouteInfo(
  855. g_hRtmHandle, prdi ->ViewInfo[ 0 ].Route, prri, NULL);
  856. if ( dwErr != NO_ERROR )
  857. {
  858. TRACE1( ANY, "Failed route info : %x", dwErr);
  859. break;
  860. }
  861. //
  862. // For each Reference, check if NEXTHOP is still present
  863. //
  864. for ( ple = pmllMfeList-> leHead.Flink;
  865. ple != &pmllMfeList-> leHead; )
  866. {
  867. prre = CONTAINING_RECORD( ple, ROUTE_REFERENCE_ENTRY, leRefList );
  868. for ( dwInd = 0; dwInd < prri-> NextHopsList.NumNextHops; dwInd++ )
  869. {
  870. bFound = FALSE;
  871. if ( prre-> hNextHop == prri-> NextHopsList.NextHops[ dwInd ] )
  872. {
  873. //
  874. // OK next hop still present, nothing further needs
  875. // to be done
  876. //
  877. bFound = TRUE;
  878. break;
  879. }
  880. }
  881. //
  882. // if NEXTHOP is not present
  883. //
  884. if ( !bFound )
  885. {
  886. pleTemp = ple-> Flink;
  887. //
  888. // Delete the reference and the corresponding MFE
  889. //
  890. RemoveEntryList( ple );
  891. DeleteMfeAndRefs( ple );
  892. ple = pleTemp;
  893. }
  894. else
  895. {
  896. ple = ple-> Flink;
  897. }
  898. }
  899. //
  900. // Release the route info
  901. //
  902. dwErr = RtmReleaseRouteInfo( g_hRtmHandle, prri );
  903. if ( dwErr != NO_ERROR )
  904. {
  905. TRACE1( ANY, "Failed to release route info : %x", dwErr );
  906. }
  907. //
  908. // if Ref list is empty, it needs to be deleted too.
  909. //
  910. if ( IsListEmpty( &pmllMfeList-> leHead ) )
  911. {
  912. //
  913. // to delete the opaque pointer, the dest needs to be locked
  914. // (via RtmLockDestination)
  915. //
  916. // the dest lock is held before locking the route reference
  917. // list ( via ACQUIRE_ROUTE_LOCK_EXCLUSIVE )
  918. //
  919. // At this point in the code, the route reference is locked
  920. // but the dest is not locked.
  921. //
  922. // To lock it, the route reference lock is first released
  923. // (via RELEASE_ROUTE_LOCK_EXCLUSIVE).
  924. //
  925. // The opaque pointer is then acquired, route ref list locked,
  926. // and double checked for emptiness. This round-about ensures
  927. // that the route ref is not deleted while there are threads
  928. // waiting on its lock. This can happen since the dest lock
  929. // is not held for most of the operations here
  930. //
  931. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  932. //
  933. // Lock dest
  934. //
  935. dwErr = RtmLockDestination(
  936. g_hRtmHandle, prdi-> DestHandle, TRUE, TRUE
  937. );
  938. if ( dwErr != NO_ERROR )
  939. {
  940. TRACE1( ANY, "Failed to lock dest : %x", dwErr );
  941. break;
  942. }
  943. bUnLock = TRUE;
  944. //
  945. // Get Opaque pointer again
  946. //
  947. dwErr = RtmGetOpaqueInformationPointer(
  948. g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo
  949. );
  950. if ( dwErr != NO_ERROR || ((* ((PBYTE *)pbOpaqueInfo) == NULL)) )
  951. {
  952. TRACE1( ANY, "Failed to get opaque ptr : %x", dwErr );
  953. break;
  954. }
  955. //
  956. // Get ref. list and lock it.
  957. //
  958. pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE * ) pbOpaqueInfo );
  959. //
  960. // Ensure that the list still exists. it is possible (though
  961. // the chances are small) that this list may have been freed
  962. //
  963. if ( pmllMfeList == NULL )
  964. {
  965. TRACE0(
  966. ANY, "ProcessRouteUpdate : Route ref list already freed"
  967. );
  968. break;
  969. }
  970. ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  971. //
  972. // If list is still empty
  973. //
  974. if ( IsListEmpty( &pmllMfeList-> leHead ) )
  975. {
  976. //
  977. // Clear opaque pointer info
  978. //
  979. *( ( PBYTE * ) pbOpaqueInfo ) = NULL;
  980. //
  981. // release list lock
  982. //
  983. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  984. MGM_FREE( pmllMfeList );
  985. //
  986. // unmark the dest. Change notifications for this
  987. // dest are no longer required.
  988. //
  989. bUnMark = TRUE;
  990. }
  991. else
  992. {
  993. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  994. }
  995. }
  996. else
  997. {
  998. RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
  999. }
  1000. } while ( FALSE );
  1001. //
  1002. // Unlock dest
  1003. //
  1004. if ( bUnLock )
  1005. {
  1006. dwErr = RtmLockDestination(
  1007. g_hRtmHandle, prdi-> DestHandle,
  1008. TRUE, FALSE
  1009. );
  1010. if ( dwErr != NO_ERROR )
  1011. {
  1012. TRACE1( ANY, "Failed to lock dest : %x", dwErr );
  1013. }
  1014. }
  1015. //
  1016. // Unmark dest
  1017. //
  1018. if ( bUnMark )
  1019. {
  1020. dwErr = RtmMarkDestForChangeNotification(
  1021. g_hRtmHandle, g_hNotificationHandle,
  1022. prdi-> DestHandle, FALSE
  1023. );
  1024. if ( dwErr != NO_ERROR )
  1025. {
  1026. TRACE1( ANY, "Failed to unmark DEST: %x", dwErr );
  1027. }
  1028. }
  1029. //
  1030. // Free allocations
  1031. //
  1032. if ( prri )
  1033. {
  1034. MGM_FREE( prri );
  1035. }
  1036. return dwErr;
  1037. }
  1038. VOID
  1039. DeleteMfeAndRefs(
  1040. PLIST_ENTRY ple
  1041. )
  1042. {
  1043. DWORD dwInIfIndex = 0, dwInIfNextHopAddr = 0, dwIfBucket;
  1044. PROUTE_REFERENCE_ENTRY prre;
  1045. PIF_ENTRY pie = NULL;
  1046. PIF_REFERENCE_ENTRY pire = NULL;
  1047. //
  1048. // Get the reference entry
  1049. //
  1050. prre = CONTAINING_RECORD(
  1051. ple, ROUTE_REFERENCE_ENTRY, leRefList
  1052. );
  1053. //
  1054. // Look up and delete the MFE
  1055. //
  1056. LookupAndDeleteYourMfe(
  1057. prre-> dwSourceAddr, prre-> dwSourceMask,
  1058. prre-> dwGroupAddr, prre-> dwGroupMask,
  1059. TRUE, &dwInIfIndex, &dwInIfNextHopAddr
  1060. );
  1061. //
  1062. // Find incoming interface and delete ref from there too.
  1063. //
  1064. if ( dwInIfIndex != 0 )
  1065. {
  1066. dwIfBucket = IF_TABLE_HASH( dwInIfIndex );
  1067. ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1068. if ( FindIfEntry(
  1069. IF_BUCKET_HEAD( dwIfBucket ), dwInIfIndex,
  1070. dwInIfNextHopAddr, &pie
  1071. ) )
  1072. {
  1073. if ( FindRefEntry(
  1074. &pie-> leInIfList, prre-> dwSourceAddr, prre-> dwSourceMask,
  1075. prre-> dwGroupAddr, prre-> dwGroupMask, &pire
  1076. ) )
  1077. {
  1078. RemoveEntryList( &pire-> leRefList );
  1079. MGM_FREE( pire );
  1080. }
  1081. else
  1082. {
  1083. TRACE2(
  1084. ANY, "Could not find ref entry for %x, %x",
  1085. prre-> dwSourceAddr, prre-> dwGroupAddr
  1086. );
  1087. }
  1088. }
  1089. else
  1090. {
  1091. TRACE2(
  1092. ANY, "Could not find i/f entry for %x, %x",
  1093. dwInIfIndex, dwInIfNextHopAddr
  1094. );
  1095. }
  1096. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1097. MGM_FREE( prre );
  1098. }
  1099. }
  1100. HANDLE
  1101. SelectNextHop(
  1102. PRTM_DEST_INFO prdi
  1103. )
  1104. {
  1105. DWORD dwErr, dwSize;
  1106. HANDLE hNextHop;
  1107. PRTM_ROUTE_INFO prri;
  1108. //
  1109. // Allocate route info structure
  1110. //
  1111. dwSize = sizeof ( RTM_ROUTE_INFO ) +
  1112. ( g_rrpRtmProfile.MaxNextHopsInRoute - 1 ) *
  1113. sizeof( RTM_NEXTHOP_HANDLE );
  1114. prri = MGM_ALLOC( dwSize );
  1115. if ( prri == NULL )
  1116. {
  1117. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1118. TRACE1( ANY, "Failed to allocate route info, size : %x", dwSize );
  1119. return NULL;
  1120. }
  1121. ZeroMemory( prri, dwSize );
  1122. //
  1123. // get route info
  1124. //
  1125. dwErr = RtmGetRouteInfo(
  1126. g_hRtmHandle, prdi-> ViewInfo[ 0 ].Route,
  1127. prri, NULL
  1128. );
  1129. if ( dwErr != NO_ERROR )
  1130. {
  1131. TRACE1( ANY, "Failed to get route info : %x", dwErr );
  1132. MGM_FREE( prri );
  1133. return NULL;
  1134. }
  1135. //
  1136. // Pick the first next hop for now
  1137. //
  1138. hNextHop = prri-> NextHopsList.NextHops[0];
  1139. //
  1140. // Release the route info
  1141. //
  1142. dwErr = RtmReleaseRouteInfo( g_hRtmHandle, prri );
  1143. if ( dwErr != NO_ERROR )
  1144. {
  1145. TRACE1( ANY, "Failed to release route info : %x", dwErr );
  1146. }
  1147. MGM_FREE( prri );
  1148. return hNextHop;
  1149. }
  1150.