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.

2223 lines
67 KiB

  1. #include "allinc.h"
  2. DWORD
  3. RtmEventCallback (
  4. IN RTM_ENTITY_HANDLE hRtmHandle,
  5. IN RTM_EVENT_TYPE retEvent,
  6. IN PVOID pContext1,
  7. IN PVOID pContext2
  8. )
  9. /*++
  10. Routine Description:
  11. This callback is given by RTM when we have changed dests
  12. to process. We just queue a work item to process changed
  13. destinations.
  14. Arguments:
  15. hRtmHandle - Handle that we got during registration
  16. retEvent - Event type - we only handle events of
  17. type "more changes available" for now
  18. pContext1 - Notification handle on which changes
  19. are available
  20. pContext2 - Context supplied during notification
  21. registration time
  22. Return Value:
  23. Status of the operation.
  24. --*/
  25. {
  26. DWORD dwResult;
  27. // Only "change notifications available" is supported
  28. if (retEvent != RTM_CHANGE_NOTIFICATION)
  29. {
  30. return ERROR_NOT_SUPPORTED;
  31. }
  32. return ((HANDLE) pContext1) == g_hNotification ?
  33. ProcessChanges(g_hNotification) :
  34. ProcessDefaultRouteChanges( g_hDefaultRouteNotification );
  35. }
  36. DWORD
  37. WINAPI
  38. ProcessChanges (
  39. IN HANDLE hNotifyHandle
  40. )
  41. /*++
  42. Routine Description:
  43. Upon learning that we have changed destinations to
  44. process, this function gets called. We retrieve all
  45. destinations to process and take appropriate action.
  46. Arguments:
  47. hRtmHandle - RTM registration handle
  48. hNotifyHandle - Handle correponding to the change notification
  49. that is being signalled
  50. Return Value:
  51. Status of the operation.
  52. --*/
  53. {
  54. PRTM_DEST_INFO pDestInfo;
  55. PRTM_ROUTE_INFO pRouteInfo;
  56. DWORD dwDests;
  57. DWORD dwResult;
  58. BOOL bMark = FALSE;
  59. TraceEnter("ProcessChanges");
  60. pRouteInfo = HeapAlloc(
  61. IPRouterHeap,
  62. 0,
  63. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  64. );
  65. if (pRouteInfo == NULL)
  66. {
  67. Trace1(
  68. ERR, "ProcessChanges : error allocating %d bytes for "
  69. "route info",
  70. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  71. );
  72. TraceLeave("ProcessChanges");
  73. return ERROR_NOT_ENOUGH_MEMORY;
  74. }
  75. pDestInfo = HeapAlloc(
  76. IPRouterHeap,
  77. 0,
  78. RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
  79. );
  80. if (pDestInfo == NULL)
  81. {
  82. Trace1(
  83. ERR, "ProcessChanges : error allocating %d bytes for "
  84. "dest. info",
  85. RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
  86. );
  87. HeapFree(IPRouterHeap, 0, pRouteInfo);
  88. TraceLeave("ProcessChanges");
  89. return ERROR_NOT_ENOUGH_MEMORY;
  90. }
  91. dwDests = 1;
  92. // Get each changed dest from the table
  93. do
  94. {
  95. RtmGetChangedDests(g_hLocalRoute,
  96. hNotifyHandle,
  97. &dwDests,
  98. pDestInfo);
  99. if (dwDests < 1)
  100. {
  101. break;
  102. }
  103. //
  104. // For default routes, mark the route so that future changes
  105. // are managed by ProcessDefaultRouteChanges.
  106. //
  107. // We need to do this here so that default routes added by
  108. // routing protocols RIP/OSPF are marked for change notification
  109. // These default routes are added by entities other than
  110. // RouterManager. Default routes added by RM i.e STATIC,
  111. // AUTO-STATIC and NETMGMT default routes are already marked for
  112. // change notification when they are added by RM.
  113. //
  114. // By marking routing protocol default routes here we make sure
  115. // that all default routes are subsequently handled by marked changed
  116. // mechanism (ProcessDefaultRouteChanges).
  117. //
  118. if (pDestInfo->DestAddress.NumBits is 0)
  119. {
  120. TraceRoute2(
  121. ROUTE, "Checking dest %d.%d.%d.%d/%d is marked",
  122. PRINT_IPADDR(*(ULONG *)pDestInfo->DestAddress.AddrBits),
  123. PRINT_IPADDR(pDestInfo->DestAddress.NumBits)
  124. );
  125. dwResult = RtmIsMarkedForChangeNotification(
  126. g_hNetMgmtRoute,
  127. g_hDefaultRouteNotification,
  128. pDestInfo->DestHandle,
  129. &bMark
  130. );
  131. if (dwResult is NO_ERROR)
  132. {
  133. if (bMark)
  134. {
  135. //
  136. // default route is already marked, nothing further
  137. // to do here. This default route change will be
  138. // handled by ProcessDefaultRouteChanges
  139. //
  140. TraceRoute0(
  141. ROUTE,
  142. "ProcessChanges : Route 0/0 is already marked"
  143. );
  144. RtmReleaseChangedDests(g_hLocalRoute,
  145. hNotifyHandle,
  146. dwDests,
  147. pDestInfo);
  148. continue;
  149. }
  150. //
  151. // Default route is not marked, mark it
  152. //
  153. dwResult = RtmMarkDestForChangeNotification(
  154. g_hNetMgmtRoute,
  155. g_hDefaultRouteNotification,
  156. pDestInfo->DestHandle,
  157. TRUE
  158. );
  159. if (dwResult isnot NO_ERROR)
  160. {
  161. //
  162. // Failed to mark 0/0 route. The consequence is that
  163. // only best route changes are processed. We will
  164. // have to live with the fact that we cannot
  165. // install multiple NETMGMT default routes since
  166. // this is performed by the mark dest. change
  167. // processing (in ProcessDefaultRouteChanges)
  168. //
  169. Trace1(
  170. ERR,
  171. "ProcessChanges: error %d marking default route",
  172. dwResult
  173. );
  174. }
  175. }
  176. else
  177. {
  178. //
  179. // Failed to check is 0/0 destination has been
  180. // marked for change notification
  181. // - Refer previous comment
  182. //
  183. Trace1(
  184. ERR,
  185. "ProcessChanges: error %d checking if default route "
  186. "marked",
  187. dwResult
  188. );
  189. }
  190. }
  191. // Check if we have a route in Unicast view
  192. if (pDestInfo->BelongsToViews & RTM_VIEW_MASK_UCAST)
  193. {
  194. // This is either a new or update route
  195. // Update the same route in KM Frwder
  196. ASSERT(pDestInfo->ViewInfo[0].ViewId is RTM_VIEW_ID_UCAST);
  197. dwResult = RtmGetRouteInfo(g_hLocalRoute,
  198. pDestInfo->ViewInfo[0].Route,
  199. pRouteInfo,
  200. NULL);
  201. // An error mean route just got deleted
  202. // Ignore this change as it is obsolete
  203. if (dwResult is NO_ERROR)
  204. {
  205. ChangeRouteWithForwarder(&pDestInfo->DestAddress,
  206. pRouteInfo,
  207. TRUE,
  208. TRUE);
  209. RtmReleaseRouteInfo(g_hLocalRoute,
  210. pRouteInfo);
  211. }
  212. }
  213. else
  214. {
  215. // The last UCAST route has been deleted
  216. // Delete the same route from KM Frwder
  217. //
  218. // Check to make sure that the route was added to
  219. // the forwarder. If not there is no need to
  220. // ChangeRouteWithForwarder.
  221. //
  222. // This rather kludgy fix was done for 446075
  223. // The problem here is really a fallout of
  224. // of RTMv2 behavior and how IPRTRMGR uses
  225. // RTM.
  226. //
  227. // Routes added to RTM and not to the TCP/IP
  228. // stack are marked as such in the Flags1 field
  229. // of the RTM_ROUTE_INFO struture. (they have
  230. // the IP_STACK_ROUTE bit turned off).
  231. //
  232. // The problem arises when a particular destination
  233. // is no longer reachable i.e. all routes to it have
  234. // been deleted. When a change notification for this
  235. // is processed by IPRTRMGR, it no longer has access
  236. // to the RTM_ROUTE_INFO STUCTURE for the last route
  237. // to the destination and consequently no access to
  238. // the flags field mentioned above. Hence routes
  239. // were being deleted from the the TCP/IP stack that
  240. // had not been added by IPRTRMGR.
  241. //
  242. // In the normal case this is not a problem. However
  243. // for host routes added by PPTP directly to TCP/IP stack
  244. // a problem arises as follows:
  245. //
  246. // 1. Host route to VPN server Route added by PPTP to TCP
  247. // 2. IPRTRMGR notified of route by TCP.
  248. // 3. IPRTRMGR added route to RTM with stack bit cleared
  249. // as we do not want to readd this route to stack.
  250. // 4. RTM notifies IPRTRMGR to new best route.
  251. // 5. IPRTRMGR skips adding this route to the stack as
  252. // its stack bit is cleared.
  253. //
  254. // 6. Host route to VPN server Route deleted by PPTP to TCP
  255. // 7. IPRTRMGR notified of route deletion by TCP
  256. // 8. IPRTRMGR deleted route from RTM
  257. // 9. RTM notified IPRTRMGR of route/dest deletion
  258. // 10. IPRTRMGR having no idea if this was added to TCP
  259. // deletes this route from TCP.
  260. //
  261. // Somewhere between steps 7 and 10, PPTP adds the route
  262. // to TCP again. Step 10 deleted the new route in TCP in
  263. // response to the old route being deleted thereby
  264. // disabling the new PPTP connection.
  265. //
  266. // To get around this problem we set state in the
  267. // destination RTM_DEST_INFO to flag this condition. This
  268. // is not a complete fix, allows IPRTRMGR to not delete
  269. // routes from TCP that were added by it in the first
  270. // place.
  271. //
  272. // Refer AddRtmRoute to figure out for which routes this
  273. // state is set.
  274. //
  275. TraceRoute2(
  276. ROUTE, "Route delete notification for "
  277. "%d.%d.%d.%d/%d",
  278. PRINT_IPADDR(*(ULONG *)pDestInfo->DestAddress.AddrBits),
  279. pDestInfo->DestAddress.NumBits
  280. );
  281. //
  282. // if this is a host route
  283. //
  284. if(pDestInfo->DestAddress.NumBits is HOST_MASK_LENGTH)
  285. {
  286. PBYTE pbOpaque;
  287. do
  288. {
  289. //
  290. // 1. Get the opaque pointer for NETMGMT
  291. //
  292. dwResult = RtmGetOpaqueInformationPointer(
  293. g_hNetMgmtRoute,
  294. pDestInfo->DestHandle,
  295. &pbOpaque
  296. );
  297. if(dwResult isnot NO_ERROR)
  298. {
  299. Trace1(
  300. ERR,
  301. "AddRtmRoute : error %d retrieving opaque "
  302. "info",
  303. dwResult
  304. );
  305. break;
  306. }
  307. //
  308. // 2. Check if this route was set to stack
  309. //
  310. if(*((PDWORD) pbOpaque) isnot RTM_NOT_STACK_ROUTE)
  311. {
  312. TraceRoute1(
  313. ROUTE, "Host route with Stack bit 0x%x",
  314. *((PDWORD) pbOpaque)
  315. );
  316. //
  317. // 3.1 If so delete it.
  318. //
  319. ChangeRouteWithForwarder(
  320. &pDestInfo->DestAddress,
  321. NULL,
  322. FALSE,
  323. TRUE
  324. );
  325. }
  326. else
  327. {
  328. //
  329. // 3.2 Otherwise move on.
  330. //
  331. TraceRoute1(
  332. ROUTE, "Stack bit not set on host "
  333. "route, Skipping deleting 0x%x",
  334. *((PDWORD) pbOpaque)
  335. );
  336. }
  337. }while( FALSE );
  338. }
  339. else
  340. {
  341. TraceRoute0(ROUTE, "Deleting a subnet route" );
  342. ChangeRouteWithForwarder(&pDestInfo->DestAddress,
  343. NULL,
  344. FALSE,
  345. TRUE);
  346. }
  347. }
  348. RtmReleaseChangedDests(g_hLocalRoute,
  349. hNotifyHandle,
  350. dwDests,
  351. pDestInfo);
  352. }
  353. while (TRUE);
  354. HeapFree(IPRouterHeap, 0, pRouteInfo);
  355. HeapFree(IPRouterHeap, 0, pDestInfo);
  356. TraceLeave("ProcessChanges");
  357. return NO_ERROR;
  358. }
  359. DWORD
  360. WINAPI
  361. ProcessDefaultRouteChanges(
  362. IN HANDLE hNotifyHandle
  363. )
  364. /*++
  365. Routine Description:
  366. This function is invoked in response to changes to
  367. the default route. If the best default route is owned
  368. by protocol PROTO_IP_NETMGMT enumerate all PROTO_IP_NETMGMT
  369. routes for default route 0/0 and set them as one
  370. multihop route to the forwarder
  371. Arguments:
  372. hRtmHandle - RTM registration handle
  373. hNotifyHandle - Handle correponding to the change notification
  374. that is being signalled
  375. Return Value:
  376. NO_ERROR - Success
  377. System error code - Otherwise
  378. --*/
  379. {
  380. PRTM_DEST_INFO pDestInfo;
  381. PRTM_ROUTE_INFO pRouteInfo;
  382. DWORD dwDests;
  383. DWORD dwResult;
  384. TraceEnter("ProcessDefaultRouteChanges");
  385. pRouteInfo = HeapAlloc(
  386. IPRouterHeap,
  387. 0,
  388. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  389. );
  390. if (pRouteInfo == NULL)
  391. {
  392. Trace1(
  393. ERR, "ProcessDefaultRouteChanges : error allocating %d bytes for "
  394. "route info",
  395. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  396. );
  397. TraceLeave("ProcessDefaultRouteChanges");
  398. return ERROR_NOT_ENOUGH_MEMORY;
  399. }
  400. pDestInfo = HeapAlloc(
  401. IPRouterHeap,
  402. 0,
  403. RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
  404. );
  405. if (pDestInfo == NULL)
  406. {
  407. Trace1(
  408. ERR, "ProcessDefaultRouteChanges : error allocating %d bytes for "
  409. "dest. info",
  410. RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
  411. );
  412. HeapFree(IPRouterHeap, 0, pRouteInfo);
  413. TraceLeave("ProcessDefaultRouteChanges");
  414. return ERROR_NOT_ENOUGH_MEMORY;
  415. }
  416. do
  417. {
  418. //
  419. // retreive changed dests
  420. //
  421. dwDests = 1;
  422. dwResult = RtmGetChangedDests(
  423. g_hNetMgmtRoute,
  424. hNotifyHandle,
  425. &dwDests,
  426. pDestInfo
  427. );
  428. if ((dwResult isnot NO_ERROR) and
  429. (dwResult isnot ERROR_NO_MORE_ITEMS))
  430. {
  431. Trace1(
  432. ERR,
  433. "ProcessDefaultRouteChanges: error %d retrieving changed dests",
  434. dwResult
  435. );
  436. break;
  437. }
  438. if (dwDests < 1)
  439. {
  440. //
  441. // no more dests to enumerate
  442. //
  443. break;
  444. }
  445. do
  446. {
  447. //
  448. // Make sure this the default route 0/0. This functions
  449. // only processes default route changes.
  450. //
  451. if ((pDestInfo->DestAddress.NumBits isnot 0) or
  452. (*((ULONG *)pDestInfo->DestAddress.AddrBits) isnot 0))
  453. {
  454. Trace2(
  455. ERR,
  456. "ProcessDefaultRouteChanges: Not default route %d.%d.%d.%d/%d",
  457. PRINT_IPADDR(*((ULONG *)pDestInfo->DestAddress.AddrBits)),
  458. pDestInfo->DestAddress.NumBits
  459. );
  460. break;
  461. }
  462. //
  463. // If all routes to 0/0 have been deleted,
  464. // delete it from the forwarder too.
  465. //
  466. if (!(pDestInfo->BelongsToViews & RTM_VIEW_MASK_UCAST))
  467. {
  468. dwResult = ChangeRouteWithForwarder(
  469. &(pDestInfo->DestAddress),
  470. NULL,
  471. FALSE,
  472. TRUE
  473. );
  474. break;
  475. }
  476. //
  477. // A route to 0/0 was added/updated
  478. //
  479. if (pDestInfo->ViewInfo[0].Owner isnot g_hNetMgmtRoute)
  480. {
  481. //
  482. // Default route is not owned by PROTO_IP_NETMGT
  483. // Add only the best route to forwarder
  484. //
  485. TraceRoute1(
  486. ROUTE,
  487. "ProcessDefaultRouteChanges: Adding non-NetMgmt"
  488. " route to forwarder, owner RTM handle 0x%x",
  489. pDestInfo->ViewInfo[0].Owner
  490. );
  491. dwResult = RtmGetRouteInfo(
  492. g_hNetMgmtRoute,
  493. pDestInfo->ViewInfo[0].Route,
  494. pRouteInfo,
  495. NULL
  496. );
  497. if (dwResult is NO_ERROR)
  498. {
  499. ChangeRouteWithForwarder(
  500. &pDestInfo->DestAddress,
  501. pRouteInfo,
  502. TRUE,
  503. TRUE
  504. );
  505. dwResult = RtmReleaseRouteInfo(
  506. g_hNetMgmtRoute,
  507. pRouteInfo
  508. );
  509. if (dwResult isnot NO_ERROR)
  510. {
  511. Trace1(
  512. ERR,
  513. "ProcessDefaultRouteChanges: Failed "
  514. "to release route info",
  515. dwResult
  516. );
  517. }
  518. }
  519. break;
  520. }
  521. //
  522. // Default route owned by PROTO_IP_NETMGMT
  523. //
  524. //
  525. // First delete existing 0/0 from the TCP/IP forwarder
  526. //
  527. dwResult = ChangeRouteWithForwarder(
  528. &(pDestInfo->DestAddress),
  529. NULL,
  530. FALSE,
  531. TRUE
  532. );
  533. if (dwResult isnot NO_ERROR)
  534. {
  535. Trace1(
  536. ERR,
  537. "ProcessDefaultRouteChanges: error %d deleting "
  538. "old NetMgmt default routes from forwarder",
  539. dwResult
  540. );
  541. // break;
  542. }
  543. //
  544. // Second add all NETMGMT 0/0 to the TCP/IP forwarder
  545. //
  546. AddNetmgmtDefaultRoutesToForwarder(pDestInfo);
  547. } while( FALSE );
  548. //
  549. // release handles to changed destinations
  550. //
  551. dwResult = RtmReleaseChangedDests(
  552. g_hNetMgmtRoute,
  553. hNotifyHandle,
  554. dwDests,
  555. pDestInfo
  556. );
  557. if (dwResult isnot NO_ERROR)
  558. {
  559. Trace1(
  560. ERR,
  561. "ProcessDefaultRouteChanges: error %d releasing dests ",
  562. dwResult
  563. );
  564. }
  565. } while ( TRUE );
  566. HeapFree(IPRouterHeap, 0, pRouteInfo);
  567. HeapFree(IPRouterHeap, 0, pDestInfo);
  568. TraceLeave("ProcessDefaultRouteChanges");
  569. return dwResult;
  570. }
  571. DWORD
  572. WINAPI
  573. AddNetmgmtDefaultRoutesToForwarder(
  574. PRTM_DEST_INFO pDestInfo
  575. )
  576. /*++
  577. Routine Description:
  578. This routine enumerates the routes to 0/0 added by protocol
  579. PROTO_IP_NETMGT and adds them to the forwarder. This routine
  580. is invoked in response to any change to the default route
  581. If the best default route is owned by PROTO_IP_NETMGMT, all
  582. PROTO_IP_NETMGMT default routes are added to the TCP/IP
  583. forwarder.
  584. This is required since the TCP/IP stack does dead gateway
  585. detection and that required multiple default routes if
  586. present to be installed in the stack.
  587. An implicit assumption here is that PROTO_IP_NETMGMT routes
  588. alone merit this treatment. In case of static or other
  589. protocol generated 0/0 routes, only the best route is
  590. added to the stack. It is assumed that in the later case(s)
  591. the administrator (for static routes) or the protocol has
  592. a better idea of routing and so the dead gateway detection
  593. is suppressed in the stack by the addition of the best route
  594. to 0/0 alone.
  595. Arguments:
  596. pDestInfo - RTM destination info structure of 0/0 route
  597. Return Value :
  598. NO_ERROR - Sucess
  599. Win32 error code - Otherwise
  600. --*/
  601. {
  602. DWORD dwResult, dwNumHandles = 0, i;
  603. BOOL bRelEnum = FALSE, bRelRoutes = FALSE;
  604. PRTM_ROUTE_INFO pRouteInfo;
  605. PRTM_ROUTE_HANDLE pHandles;
  606. RTM_ENUM_HANDLE hRouteEnum;
  607. dwNumHandles = pDestInfo->ViewInfo[0].NumRoutes;
  608. pHandles = HeapAlloc(
  609. IPRouterHeap,
  610. 0,
  611. dwNumHandles * sizeof(RTM_ROUTE_HANDLE)
  612. );
  613. if (pHandles == NULL)
  614. {
  615. Trace1(
  616. ERR,
  617. "AddNetmgmtDefaultRoutesToForwarder: error allocating %d bytes"
  618. "for route handles",
  619. dwNumHandles * sizeof(RTM_ROUTE_HANDLE)
  620. );
  621. return ERROR_NOT_ENOUGH_MEMORY;
  622. }
  623. pRouteInfo = HeapAlloc(
  624. IPRouterHeap,
  625. 0,
  626. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  627. );
  628. if (pRouteInfo == NULL)
  629. {
  630. Trace1(
  631. ERR,
  632. "AddNetmgmtDefaultRoutesToForwarder: error allocating %d bytes"
  633. "for route info",
  634. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  635. );
  636. HeapFree(IPRouterHeap, 0, pHandles);
  637. return ERROR_NOT_ENOUGH_MEMORY;
  638. }
  639. do
  640. {
  641. //
  642. // Enumerate and add all NETMGMT routes to the forwarder
  643. //
  644. dwResult = RtmCreateRouteEnum(
  645. g_hNetMgmtRoute,
  646. pDestInfo->DestHandle,
  647. RTM_VIEW_MASK_UCAST,
  648. RTM_ENUM_OWN_ROUTES,
  649. NULL,
  650. 0,
  651. NULL,
  652. 0,
  653. &hRouteEnum
  654. );
  655. if (dwResult isnot NO_ERROR)
  656. {
  657. Trace1(
  658. ERR,
  659. "AddNetmgmtDefaultRoutesToForwarder: error %d creating route "
  660. "enumeration",
  661. dwResult
  662. );
  663. break;
  664. }
  665. bRelEnum = TRUE;
  666. dwResult = RtmGetEnumRoutes(
  667. g_hNetMgmtRoute,
  668. hRouteEnum,
  669. &dwNumHandles,
  670. pHandles
  671. );
  672. if (dwResult isnot NO_ERROR)
  673. {
  674. Trace1(
  675. ERR,
  676. "ProcessDefaultRouteChanges:error %d enumerating "
  677. "routes",
  678. dwResult
  679. );
  680. break;
  681. }
  682. bRelRoutes = TRUE;
  683. //
  684. // Change route with the forwarder
  685. //
  686. for (i = 0; i < dwNumHandles; i++)
  687. {
  688. dwResult = RtmGetRouteInfo(
  689. g_hNetMgmtRoute,
  690. pHandles[i],
  691. pRouteInfo,
  692. NULL
  693. );
  694. if (dwResult is NO_ERROR)
  695. {
  696. ChangeRouteWithForwarder(
  697. &(pDestInfo->DestAddress),
  698. pRouteInfo,
  699. TRUE,
  700. FALSE
  701. );
  702. dwResult = RtmReleaseRouteInfo(
  703. g_hNetMgmtRoute,
  704. pRouteInfo
  705. );
  706. if (dwResult isnot NO_ERROR)
  707. {
  708. Trace1(
  709. ERR,
  710. "ProcessDefaultRouteChanges: error %d releasing "
  711. "route info ",
  712. dwResult
  713. );
  714. }
  715. }
  716. else
  717. {
  718. Trace2(
  719. ERR,
  720. "ProcessDefaultRouteChanges: error %d getting route "
  721. "info for route %d",
  722. dwResult, i
  723. );
  724. }
  725. }
  726. } while( FALSE );
  727. //
  728. // Release handles
  729. //
  730. if (bRelRoutes)
  731. {
  732. Trace0(ROUTE, "Releasing routes to 0/0");
  733. dwResult = RtmReleaseRoutes(
  734. g_hNetMgmtRoute,
  735. dwNumHandles,
  736. pHandles
  737. );
  738. if (dwResult isnot NO_ERROR)
  739. {
  740. Trace1(
  741. ERR,
  742. "ProcessDefaultRouteChanges: error %d deleting enum "
  743. "handle",
  744. dwResult
  745. );
  746. }
  747. }
  748. if (bRelEnum)
  749. {
  750. Trace0(ROUTE, "Releasing route enum for 0/0");
  751. dwResult = RtmDeleteEnumHandle(
  752. g_hNetMgmtRoute,
  753. hRouteEnum
  754. );
  755. if (dwResult isnot NO_ERROR)
  756. {
  757. Trace1(
  758. ERR,
  759. "ProcessDefaultRouteChanges: error %d deleting enum "
  760. "handle",
  761. dwResult
  762. );
  763. }
  764. }
  765. HeapFree(IPRouterHeap, 0, pHandles);
  766. HeapFree(IPRouterHeap, 0, pRouteInfo);
  767. return dwResult;
  768. }
  769. DWORD
  770. AddRtmRoute (
  771. IN HANDLE hRtmHandle,
  772. IN PINTERFACE_ROUTE_INFO pRtInfo,
  773. IN DWORD dwRouteFlags,
  774. IN DWORD dwNextHopMask,
  775. IN DWORD dwTimeToLive,
  776. OUT HANDLE *phRtmRoute
  777. )
  778. /*++
  779. Routine Description:
  780. Adds a route to RTM with the specified route information.
  781. Arguments:
  782. hRtmHandle - RTM registration handle used in RTM calls
  783. pRtInfo -
  784. dwNextHopMask -
  785. dwTimeToLive - Time for which the route is kept in RTM
  786. before being deleted (value is seconds).
  787. Return Value:
  788. Status of the operation.
  789. --*/
  790. {
  791. PRTM_NET_ADDRESS pDestAddr;
  792. PRTM_ROUTE_INFO pRouteInfo;
  793. RTM_NEXTHOP_INFO rniInfo;
  794. DWORD dwFlags;
  795. DWORD dwResult;
  796. HANDLE hNextHopHandle;
  797. PADAPTER_INFO pBinding;
  798. // Initialize output before caling ops
  799. if (ARGUMENT_PRESENT(phRtmRoute))
  800. {
  801. *phRtmRoute = NULL;
  802. }
  803. pDestAddr = HeapAlloc(
  804. IPRouterHeap,
  805. 0,
  806. sizeof(RTM_NET_ADDRESS)
  807. );
  808. if (pDestAddr == NULL)
  809. {
  810. Trace1(
  811. ERR,
  812. "AddRtmRoute : error allocating %d bytes"
  813. "for dest. address",
  814. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  815. );
  816. return ERROR_NOT_ENOUGH_MEMORY;
  817. }
  818. pRouteInfo = HeapAlloc(
  819. IPRouterHeap,
  820. 0,
  821. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  822. );
  823. if (pRouteInfo == NULL)
  824. {
  825. Trace1(
  826. ERR,
  827. "AddRtmRoute : error allocating %d bytes"
  828. "for route info",
  829. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  830. );
  831. HeapFree(IPRouterHeap, 0, pDestAddr);
  832. return ERROR_NOT_ENOUGH_MEMORY;
  833. }
  834. //
  835. // Add a next hop if not already present
  836. //
  837. RTM_IPV4_MAKE_NET_ADDRESS(&rniInfo.NextHopAddress,
  838. pRtInfo->dwRtInfoNextHop,
  839. 32);
  840. rniInfo.InterfaceIndex = pRtInfo->dwRtInfoIfIndex;
  841. rniInfo.EntitySpecificInfo = (PVOID) (ULONG_PTR)dwNextHopMask;
  842. rniInfo.Flags = 0;
  843. rniInfo.RemoteNextHop = NULL;
  844. hNextHopHandle = NULL;
  845. dwResult = RtmAddNextHop(hRtmHandle,
  846. &rniInfo,
  847. &hNextHopHandle,
  848. &dwFlags);
  849. if (dwResult is NO_ERROR)
  850. {
  851. TraceRoute2(
  852. ROUTE, "Route to %d.%d.%d.%d/%d.%d.%d.%d",
  853. PRINT_IPADDR(pRtInfo->dwRtInfoDest),
  854. PRINT_IPADDR(pRtInfo->dwRtInfoMask)
  855. );
  856. TraceRoute4(
  857. ROUTE, "Next Hop %d.%d.%d.%d/%d.%d.%d.%d, If 0x%x, handle is 0x%x",
  858. PRINT_IPADDR(pRtInfo->dwRtInfoNextHop),
  859. PRINT_IPADDR(dwNextHopMask),
  860. pRtInfo->dwRtInfoIfIndex,
  861. hNextHopHandle
  862. );
  863. dwResult = ConvertRouteInfoToRtm(hRtmHandle,
  864. pRtInfo,
  865. hNextHopHandle,
  866. dwRouteFlags,
  867. pDestAddr,
  868. pRouteInfo);
  869. if (dwResult is NO_ERROR)
  870. {
  871. //
  872. // If we are adding a non-dod route we should
  873. // adjust the state of the route to match
  874. // that of the interface it is being added on
  875. //
  876. if ((hRtmHandle == g_hNonDodRoute) ||
  877. (hRtmHandle == g_hNetMgmtRoute))
  878. {
  879. //
  880. // Find the binding given the interface id
  881. //
  882. ENTER_READER(BINDING_LIST);
  883. pBinding = GetInterfaceBinding(pRtInfo->dwRtInfoIfIndex);
  884. if ((!pBinding) || (!pBinding->bBound))
  885. {
  886. // Interface has been deleted meanwhile
  887. // or is not bound at this point - quit
  888. EXIT_LOCK(BINDING_LIST);
  889. return ERROR_INVALID_PARAMETER;
  890. }
  891. }
  892. //
  893. // Convert TimeToLive from secs to millisecs
  894. //
  895. if (dwTimeToLive != INFINITE)
  896. {
  897. if (dwTimeToLive < (INFINITE / 1000))
  898. {
  899. dwTimeToLive *= 1000;
  900. }
  901. else
  902. {
  903. dwTimeToLive = INFINITE;
  904. }
  905. }
  906. dwFlags = 0;
  907. //
  908. // Add the new route using the RTMv2 API call
  909. //
  910. dwResult = RtmAddRouteToDest(hRtmHandle,
  911. phRtmRoute,
  912. pDestAddr,
  913. pRouteInfo,
  914. dwTimeToLive,
  915. NULL,
  916. 0,
  917. NULL,
  918. &dwFlags);
  919. if ((hRtmHandle == g_hNonDodRoute) ||
  920. (hRtmHandle == g_hNetMgmtRoute))
  921. {
  922. EXIT_LOCK(BINDING_LIST);
  923. }
  924. //
  925. // check if route is 0/0 and route protocol is
  926. // PROTO_IP_NETMGMT. If so mark for change notification
  927. //
  928. if ((pRtInfo->dwRtInfoDest is 0) and
  929. (pRtInfo->dwRtInfoMask is 0))
  930. {
  931. RTM_DEST_INFO rdi;
  932. BOOL bMark;
  933. BOOL bRelDest = FALSE;
  934. do
  935. {
  936. TraceRoute2(
  937. ROUTE, "Checking dest %d.%d.%d.%d/%d for mark",
  938. PRINT_IPADDR(*(ULONG *)pDestAddr->AddrBits),
  939. PRINT_IPADDR(pDestAddr->NumBits)
  940. );
  941. dwResult = RtmGetExactMatchDestination(
  942. g_hNetMgmtRoute,
  943. pDestAddr,
  944. RTM_THIS_PROTOCOL,
  945. RTM_VIEW_MASK_UCAST,
  946. &rdi
  947. );
  948. if (dwResult isnot NO_ERROR)
  949. {
  950. Trace1(
  951. ERR,
  952. "AddRtmRoute: error %d failed to get "
  953. "destination 0/0 for change notification",
  954. dwResult
  955. );
  956. break;
  957. }
  958. bRelDest = TRUE;
  959. dwResult = RtmIsMarkedForChangeNotification(
  960. g_hNetMgmtRoute,
  961. g_hDefaultRouteNotification,
  962. rdi.DestHandle,
  963. &bMark
  964. );
  965. if (dwResult isnot NO_ERROR)
  966. {
  967. Trace1(
  968. ERR,
  969. "AddRtmRoute: error %d failed to check "
  970. "destination 0/0 for change notification",
  971. dwResult
  972. );
  973. break;
  974. }
  975. if (!bMark)
  976. {
  977. dwResult = RtmMarkDestForChangeNotification(
  978. g_hNetMgmtRoute,
  979. g_hDefaultRouteNotification,
  980. rdi.DestHandle,
  981. TRUE
  982. );
  983. if (dwResult isnot NO_ERROR)
  984. {
  985. Trace1(
  986. ERR,
  987. "AddRtmRoute: error %d failed to nark "
  988. "destination 0/0 for change notification",
  989. dwResult
  990. );
  991. break;
  992. }
  993. //
  994. // Add route once more, to force marked dest
  995. // change notifications to be issued for this
  996. // change
  997. //
  998. dwFlags = 0;
  999. dwResult = RtmAddRouteToDest(
  1000. hRtmHandle,
  1001. phRtmRoute,
  1002. pDestAddr,
  1003. pRouteInfo,
  1004. dwTimeToLive,
  1005. NULL,
  1006. 0,
  1007. NULL,
  1008. &dwFlags
  1009. );
  1010. if (dwResult isnot NO_ERROR)
  1011. {
  1012. Trace1(
  1013. ERR,
  1014. "AddRtmRoute: error %d added route after "
  1015. "marking destination",
  1016. dwResult
  1017. );
  1018. break;
  1019. }
  1020. TraceRoute2(
  1021. ROUTE, "Marked dest %d.%d.%d.%d/%d and added",
  1022. PRINT_IPADDR(*(ULONG *)pDestAddr->AddrBits),
  1023. pDestAddr->NumBits
  1024. );
  1025. }
  1026. } while (FALSE);
  1027. if (bRelDest)
  1028. {
  1029. RtmReleaseDestInfo(
  1030. g_hNetMgmtRoute,
  1031. &rdi
  1032. );
  1033. }
  1034. }
  1035. //
  1036. // for host routes, added by NETMGMT
  1037. // if they are not added to the stack
  1038. //
  1039. if((pRtInfo->dwRtInfoMask is HOST_ROUTE_MASK) and
  1040. (pRtInfo->dwRtInfoProto is PROTO_IP_NETMGMT) and
  1041. (!(dwRouteFlags & IP_STACK_ROUTE)))
  1042. {
  1043. RTM_DEST_INFO rdi;
  1044. BOOL bRelDest = FALSE;
  1045. PBYTE pbOpaque = NULL;
  1046. TraceRoute2(
  1047. ROUTE,
  1048. "Non-stack Netmgmt host route "
  1049. "%d.%d.%d.%d/%d",
  1050. PRINT_IPADDR(*(ULONG *)pDestAddr->AddrBits),
  1051. pDestAddr->NumBits
  1052. );
  1053. do
  1054. {
  1055. //
  1056. // Retrieve destination
  1057. //
  1058. dwResult = RtmGetExactMatchDestination(
  1059. g_hNetMgmtRoute,
  1060. pDestAddr,
  1061. RTM_THIS_PROTOCOL,
  1062. RTM_VIEW_MASK_UCAST,
  1063. &rdi
  1064. );
  1065. if (dwResult isnot NO_ERROR)
  1066. {
  1067. Trace1(
  1068. ERR,
  1069. "AddRtmRoute : error %d retriveing host route "
  1070. "destination",
  1071. dwResult
  1072. );
  1073. break;
  1074. }
  1075. bRelDest = TRUE;
  1076. //
  1077. // get opaque info ptr.
  1078. //
  1079. dwResult = RtmLockDestination(
  1080. g_hNetMgmtRoute,
  1081. rdi.DestHandle,
  1082. TRUE,
  1083. TRUE
  1084. );
  1085. if (dwResult isnot NO_ERROR)
  1086. {
  1087. Trace1(
  1088. ERR,
  1089. "AddRtmRoute : error %d locking host route "
  1090. "destination",
  1091. dwResult
  1092. );
  1093. break;
  1094. }
  1095. dwResult = RtmGetOpaqueInformationPointer(
  1096. g_hNetMgmtRoute,
  1097. rdi.DestHandle,
  1098. &pbOpaque
  1099. );
  1100. if(dwResult isnot NO_ERROR)
  1101. {
  1102. Trace1(
  1103. ERR,
  1104. "AddRtmRoute : error %d retrieving opaque "
  1105. "info",
  1106. dwResult
  1107. );
  1108. break;
  1109. }
  1110. *((PDWORD) pbOpaque) = RTM_NOT_STACK_ROUTE;
  1111. dwResult = RtmLockDestination(
  1112. g_hNetMgmtRoute,
  1113. rdi.DestHandle,
  1114. TRUE,
  1115. FALSE
  1116. );
  1117. if (dwResult isnot NO_ERROR)
  1118. {
  1119. Trace1(
  1120. ERR,
  1121. "AddRtmRoute : error %d unlocking dest",
  1122. dwResult
  1123. );
  1124. break;
  1125. }
  1126. }while( FALSE );
  1127. if (bRelDest)
  1128. {
  1129. RtmReleaseDestInfo(
  1130. g_hNetMgmtRoute,
  1131. &rdi
  1132. );
  1133. }
  1134. TraceRoute3(
  1135. ROUTE,
  1136. "Non-stack Netmgmt host route "
  1137. "%d.%d.%d.%d/%d opaq info set, res == %d",
  1138. PRINT_IPADDR(*(ULONG *)pDestAddr->AddrBits),
  1139. pDestAddr->NumBits,
  1140. dwResult
  1141. );
  1142. }
  1143. }
  1144. // Release the next hop handle obtained above
  1145. RtmReleaseNextHops(hRtmHandle,
  1146. 1,
  1147. &hNextHopHandle);
  1148. }
  1149. HeapFree(IPRouterHeap, 0, pDestAddr);
  1150. HeapFree(IPRouterHeap, 0, pRouteInfo);
  1151. return dwResult;
  1152. }
  1153. DWORD
  1154. DeleteRtmRoute (
  1155. IN HANDLE hRtmHandle,
  1156. IN PINTERFACE_ROUTE_INFO pRtInfo
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Deletes an RTM route with the specified route information.
  1161. Arguments:
  1162. hRtmHandle - RTM registration handle used in RTM calls
  1163. pRtInfo -
  1164. Return Value:
  1165. Status of the operation.
  1166. --*/
  1167. {
  1168. PRTM_NET_ADDRESS pDestAddr;
  1169. PRTM_ROUTE_INFO pRouteInfo;
  1170. RTM_NEXTHOP_INFO rniInfo;
  1171. DWORD dwFlags;
  1172. DWORD dwResult;
  1173. HANDLE hRouteHandle;
  1174. HANDLE hNextHopHandle;
  1175. pRouteInfo = HeapAlloc(
  1176. IPRouterHeap,
  1177. 0,
  1178. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  1179. );
  1180. if (pRouteInfo == NULL)
  1181. {
  1182. Trace1(
  1183. ERR,
  1184. "DeleteRtmRoute : error allocating %d bytes"
  1185. "for route info",
  1186. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  1187. );
  1188. return ERROR_NOT_ENOUGH_MEMORY;
  1189. }
  1190. pDestAddr = HeapAlloc(
  1191. IPRouterHeap,
  1192. 0,
  1193. sizeof(RTM_NET_ADDRESS)
  1194. );
  1195. if (pDestAddr == NULL)
  1196. {
  1197. Trace1(
  1198. ERR,
  1199. "AddRtmRoute : error allocating %d bytes"
  1200. "for dest. address",
  1201. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  1202. );
  1203. HeapFree(IPRouterHeap, 0, pRouteInfo);
  1204. return ERROR_NOT_ENOUGH_MEMORY;
  1205. }
  1206. //
  1207. // Obtain a handle to the next hop in the route
  1208. //
  1209. RTM_IPV4_MAKE_NET_ADDRESS(&rniInfo.NextHopAddress,
  1210. pRtInfo->dwRtInfoNextHop,
  1211. 32);
  1212. rniInfo.InterfaceIndex = pRtInfo->dwRtInfoIfIndex;
  1213. rniInfo.NextHopOwner = hRtmHandle;
  1214. dwResult = RtmFindNextHop(hRtmHandle,
  1215. &rniInfo,
  1216. &hNextHopHandle,
  1217. NULL);
  1218. if (dwResult isnot NO_ERROR)
  1219. {
  1220. HeapFree(IPRouterHeap, 0, pDestAddr);
  1221. HeapFree(IPRouterHeap, 0, pRouteInfo);
  1222. return dwResult;
  1223. }
  1224. //
  1225. // We can get this route by matching the route's
  1226. // net addr, its owner and neighbour learnt from
  1227. //
  1228. ConvertRouteInfoToRtm(hRtmHandle,
  1229. pRtInfo,
  1230. hNextHopHandle,
  1231. 0,
  1232. pDestAddr,
  1233. pRouteInfo);
  1234. dwResult = RtmGetExactMatchRoute(hRtmHandle,
  1235. pDestAddr,
  1236. RTM_MATCH_OWNER | RTM_MATCH_NEIGHBOUR,
  1237. pRouteInfo,
  1238. 0,
  1239. 0,
  1240. &hRouteHandle);
  1241. if (dwResult is NO_ERROR)
  1242. {
  1243. //
  1244. // Delete the route found above using the handle
  1245. //
  1246. dwResult = RtmDeleteRouteToDest(hRtmHandle,
  1247. hRouteHandle,
  1248. &dwFlags);
  1249. if (dwResult isnot NO_ERROR)
  1250. {
  1251. // If delete successful, deref is automatic
  1252. RtmReleaseRoutes(hRtmHandle,
  1253. 1,
  1254. &hRouteHandle);
  1255. }
  1256. // Release the route information obtained above
  1257. RtmReleaseRouteInfo(hRtmHandle,
  1258. pRouteInfo);
  1259. }
  1260. // Release the next hop handle obtained above
  1261. RtmReleaseNextHops(hRtmHandle,
  1262. 1,
  1263. &hNextHopHandle);
  1264. HeapFree(IPRouterHeap, 0, pDestAddr);
  1265. HeapFree(IPRouterHeap, 0, pRouteInfo);
  1266. return dwResult;
  1267. }
  1268. DWORD
  1269. ConvertRouteInfoToRtm(
  1270. IN HANDLE hRtmHandle,
  1271. IN PINTERFACE_ROUTE_INFO pRtInfo,
  1272. IN HANDLE hNextHopHandle,
  1273. IN DWORD dwRouteFlags,
  1274. OUT PRTM_NET_ADDRESS pDestAddr,
  1275. OUT PRTM_ROUTE_INFO pRouteInfo
  1276. )
  1277. {
  1278. DWORD dwAddrLen;
  1279. // Fill the destination addr structure
  1280. RTM_IPV4_LEN_FROM_MASK(dwAddrLen, pRtInfo->dwRtInfoMask);
  1281. RTM_IPV4_MAKE_NET_ADDRESS(pDestAddr,
  1282. pRtInfo->dwRtInfoDest,
  1283. dwAddrLen);
  1284. // Fill in the route information now
  1285. ZeroMemory(pRouteInfo, sizeof(RTM_ROUTE_INFO));
  1286. pRouteInfo->RouteOwner = hRtmHandle;
  1287. pRouteInfo->Neighbour = hNextHopHandle;
  1288. pRouteInfo->PrefInfo.Metric = pRtInfo->dwRtInfoMetric1;
  1289. pRouteInfo->PrefInfo.Preference = pRtInfo->dwRtInfoPreference;
  1290. pRouteInfo->BelongsToViews = pRtInfo->dwRtInfoViewSet;
  1291. //
  1292. // BUG BUG BUG BUG :
  1293. // This is broken for future references
  1294. //
  1295. if(g_pLoopbackInterfaceCb &&
  1296. pRtInfo->dwRtInfoIfIndex is g_pLoopbackInterfaceCb->dwIfIndex)
  1297. {
  1298. pRouteInfo->BelongsToViews &= ~RTM_VIEW_MASK_MCAST;
  1299. }
  1300. pRouteInfo->NextHopsList.NumNextHops = 1;
  1301. pRouteInfo->NextHopsList.NextHops[0] = hNextHopHandle;
  1302. // an unsigned integer is converted to a shorter
  1303. // unsigned integer by truncating the high-order bits!
  1304. pRouteInfo->Flags1 = (UCHAR) dwRouteFlags;
  1305. pRouteInfo->Flags = (USHORT) (dwRouteFlags >> 16);
  1306. // Get the preference for this route
  1307. return ValidateRouteForProtocol(pRtInfo->dwRtInfoProto,
  1308. pRouteInfo,
  1309. pDestAddr);
  1310. // The following information is lost
  1311. //
  1312. // dwForwardMetric2,3
  1313. // dwForwardPolicy
  1314. // dwForwardType
  1315. // dwForwardAge
  1316. // dwForwardNextHopAS
  1317. }
  1318. VOID
  1319. ConvertRtmToRouteInfo (
  1320. IN DWORD ownerProtocol,
  1321. IN PRTM_NET_ADDRESS pDestAddr,
  1322. IN PRTM_ROUTE_INFO pRouteInfo,
  1323. IN PRTM_NEXTHOP_INFO pNextHop,
  1324. OUT PINTERFACE_ROUTE_INFO pRtInfo
  1325. )
  1326. {
  1327. pRtInfo->dwRtInfoDest = *(ULONG *)pDestAddr->AddrBits;
  1328. pRtInfo->dwRtInfoMask = RTM_IPV4_MASK_FROM_LEN(pDestAddr->NumBits);
  1329. pRtInfo->dwRtInfoIfIndex = pNextHop->InterfaceIndex;
  1330. pRtInfo->dwRtInfoNextHop = *(ULONG *)pNextHop->NextHopAddress.AddrBits;
  1331. pRtInfo->dwRtInfoProto = ownerProtocol;
  1332. pRtInfo->dwRtInfoMetric1 =
  1333. pRtInfo->dwRtInfoMetric2 =
  1334. pRtInfo->dwRtInfoMetric3 = pRouteInfo->PrefInfo.Metric;
  1335. pRtInfo->dwRtInfoPreference = pRouteInfo->PrefInfo.Preference;
  1336. pRtInfo->dwRtInfoViewSet = pRouteInfo->BelongsToViews;
  1337. pRtInfo->dwRtInfoPolicy = 0;
  1338. pRtInfo->dwRtInfoType = 0;
  1339. pRtInfo->dwRtInfoAge = 0;
  1340. pRtInfo->dwRtInfoNextHopAS = 0;
  1341. return;
  1342. }
  1343. PINTERFACE_ROUTE_INFO
  1344. ConvertMibRouteToRouteInfo(
  1345. IN PMIB_IPFORWARDROW pMibRow
  1346. )
  1347. {
  1348. PINTERFACE_ROUTE_INFO pRouteInfo = (PINTERFACE_ROUTE_INFO)pMibRow;
  1349. pMibRow->dwForwardMetric2 = 0;
  1350. pMibRow->dwForwardMetric3 = 0;
  1351. pMibRow->dwForwardMetric4 = 0;
  1352. pMibRow->dwForwardMetric5 = 0;
  1353. // Make sure Metric1 isn't 0
  1354. if (pRouteInfo->dwRtInfoMetric1 is 0)
  1355. {
  1356. pRouteInfo->dwRtInfoMetric1 = 1;
  1357. }
  1358. // By default put it in both views
  1359. pRouteInfo->dwRtInfoViewSet = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST;
  1360. return pRouteInfo;
  1361. }
  1362. PMIB_IPFORWARDROW
  1363. ConvertRouteInfoToMibRoute(
  1364. IN PINTERFACE_ROUTE_INFO pRouteInfo
  1365. )
  1366. {
  1367. PMIB_IPFORWARDROW pMibRoute = (PMIB_IPFORWARDROW) pRouteInfo;
  1368. pMibRoute->dwForwardMetric2 =
  1369. pMibRoute->dwForwardMetric3 =
  1370. pMibRoute->dwForwardMetric4 =
  1371. pMibRoute->dwForwardMetric5 = IRE_METRIC_UNUSED;
  1372. pMibRoute->dwForwardAge = INFINITE;
  1373. pMibRoute->dwForwardPolicy = 0;
  1374. pMibRoute->dwForwardNextHopAS = 0;
  1375. pMibRoute->dwForwardType = IRE_TYPE_INDIRECT;
  1376. return pMibRoute;
  1377. }
  1378. VOID
  1379. ConvertRouteNotifyOutputToRouteInfo(
  1380. IN PIPRouteNotifyOutput pirno,
  1381. OUT PINTERFACE_ROUTE_INFO pRtInfo
  1382. )
  1383. {
  1384. ZeroMemory(pRtInfo, sizeof(INTERFACE_ROUTE_INFO));
  1385. pRtInfo->dwRtInfoDest = pirno->irno_dest;
  1386. pRtInfo->dwRtInfoMask = pirno->irno_mask;
  1387. pRtInfo->dwRtInfoIfIndex = pirno->irno_ifindex;
  1388. pRtInfo->dwRtInfoNextHop = pirno->irno_nexthop;
  1389. pRtInfo->dwRtInfoProto = pirno->irno_proto;
  1390. pRtInfo->dwRtInfoMetric1 =
  1391. pRtInfo->dwRtInfoMetric2 =
  1392. pRtInfo->dwRtInfoMetric3 = pirno->irno_metric;
  1393. pRtInfo->dwRtInfoPreference = ComputeRouteMetric(pirno->irno_proto);
  1394. pRtInfo->dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
  1395. RTM_VIEW_MASK_MCAST;
  1396. pRtInfo->dwRtInfoType = (pirno->irno_proto == PROTO_IP_LOCAL) ?
  1397. MIB_IPROUTE_TYPE_DIRECT : MIB_IPROUTE_TYPE_OTHER;
  1398. pRtInfo->dwRtInfoAge = INFINITE;
  1399. pRtInfo->dwRtInfoNextHopAS = 0;
  1400. pRtInfo->dwRtInfoPolicy = 0;
  1401. return;
  1402. }
  1403. DWORD
  1404. BlockConvertRoutesToStatic (
  1405. IN HANDLE hRtmHandle,
  1406. IN DWORD dwIfIndex,
  1407. IN DWORD dwProtocolId
  1408. )
  1409. {
  1410. HANDLE hRtmEnum;
  1411. RTM_ENTITY_INFO reiInfo;
  1412. RTM_NET_ADDRESS rnaDest;
  1413. PRTM_ROUTE_INFO pRouteInfo1;
  1414. PRTM_ROUTE_INFO pRouteInfo2;
  1415. RTM_NEXTHOP_INFO nhiInfo;
  1416. RTM_NEXTHOP_HANDLE hNextHop;
  1417. PHANDLE hRoutes;
  1418. DWORD dwHandles;
  1419. DWORD dwFlags;
  1420. DWORD dwNumBytes;
  1421. DWORD i, j, k;
  1422. BOOL fDeleted;
  1423. DWORD dwResult;
  1424. hRoutes = HeapAlloc(
  1425. IPRouterHeap,
  1426. 0,
  1427. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  1428. );
  1429. if (hRoutes == NULL)
  1430. {
  1431. Trace1(
  1432. ERR,
  1433. "BlockConvertRoutesToStatic : error allocating %d bytes"
  1434. "for route handes",
  1435. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  1436. );
  1437. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1438. return ERROR_NOT_ENOUGH_MEMORY;
  1439. }
  1440. dwNumBytes = RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute);
  1441. pRouteInfo1 = HeapAlloc(
  1442. IPRouterHeap,
  1443. 0,
  1444. dwNumBytes
  1445. );
  1446. if (pRouteInfo1 == NULL)
  1447. {
  1448. Trace1(
  1449. ERR,
  1450. "BlockConvertRoutesToStatic : error allocating %d bytes"
  1451. "for route info",
  1452. dwNumBytes
  1453. );
  1454. HeapFree(IPRouterHeap, 0, hRoutes);
  1455. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1456. return ERROR_NOT_ENOUGH_MEMORY;
  1457. }
  1458. pRouteInfo2 = HeapAlloc(
  1459. IPRouterHeap,
  1460. 0,
  1461. dwNumBytes
  1462. );
  1463. if (pRouteInfo2 == NULL)
  1464. {
  1465. Trace1(
  1466. ERR,
  1467. "BlockConvertRoutesToStatic : error allocating %d bytes"
  1468. "for route info",
  1469. dwNumBytes
  1470. );
  1471. HeapFree(IPRouterHeap, 0, hRoutes);
  1472. HeapFree(IPRouterHeap, 0, pRouteInfo1);
  1473. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1474. return ERROR_NOT_ENOUGH_MEMORY;
  1475. }
  1476. //
  1477. // Enum all routes on the interface that we need
  1478. //
  1479. dwResult = RtmCreateRouteEnum(hRtmHandle,
  1480. NULL,
  1481. RTM_VIEW_MASK_ANY,
  1482. RTM_ENUM_ALL_ROUTES,
  1483. NULL,
  1484. RTM_MATCH_INTERFACE,
  1485. NULL,
  1486. dwIfIndex,
  1487. &hRtmEnum);
  1488. if(dwResult isnot NO_ERROR)
  1489. {
  1490. Trace2(ERR,
  1491. "BlockConvertRoutesToStatic: Error %d creating handle for %d\n",
  1492. dwResult,
  1493. hRtmHandle);
  1494. HeapFree(IPRouterHeap, 0, hRoutes);
  1495. HeapFree(IPRouterHeap, 0, pRouteInfo1);
  1496. HeapFree(IPRouterHeap, 0, pRouteInfo2);
  1497. return dwResult;
  1498. }
  1499. do
  1500. {
  1501. dwHandles = g_rtmProfile.MaxHandlesInEnum;
  1502. dwResult = RtmGetEnumRoutes(hRtmHandle,
  1503. hRtmEnum,
  1504. &dwHandles,
  1505. hRoutes);
  1506. for (i = 0; i < dwHandles; i++)
  1507. {
  1508. fDeleted = FALSE;
  1509. // Get the route info from the handle
  1510. if (RtmGetRouteInfo(hRtmHandle,
  1511. hRoutes[i],
  1512. pRouteInfo1,
  1513. &rnaDest) is NO_ERROR)
  1514. {
  1515. // Does this match the routing protocol we want ?
  1516. if ((RtmGetEntityInfo(hRtmHandle,
  1517. pRouteInfo1->RouteOwner,
  1518. &reiInfo) is NO_ERROR) &&
  1519. (reiInfo.EntityId.EntityProtocolId is dwProtocolId))
  1520. {
  1521. //
  1522. // Add new static route with same information
  1523. //
  1524. CopyMemory(pRouteInfo2,
  1525. pRouteInfo1,
  1526. sizeof(RTM_ROUTE_INFO));
  1527. // Adjust the preference to confirm to protocol
  1528. pRouteInfo2->PrefInfo.Preference =
  1529. ComputeRouteMetric(PROTO_IP_NT_AUTOSTATIC);
  1530. // Adjust the neighbour to corr to new protocol
  1531. if (pRouteInfo1->Neighbour)
  1532. {
  1533. // In case we cant get convert the neighbour
  1534. pRouteInfo2->Neighbour = NULL;
  1535. if (RtmGetNextHopInfo(hRtmHandle,
  1536. pRouteInfo1->Neighbour,
  1537. &nhiInfo) is NO_ERROR)
  1538. {
  1539. // Add the same neigbour using new protocol
  1540. hNextHop = NULL;
  1541. if (RtmAddNextHop(hRtmHandle,
  1542. &nhiInfo,
  1543. &hNextHop,
  1544. &dwFlags) is NO_ERROR)
  1545. {
  1546. pRouteInfo2->Neighbour = hNextHop;
  1547. }
  1548. RtmReleaseNextHopInfo(hRtmHandle, &nhiInfo);
  1549. }
  1550. }
  1551. // Adjust the next hops to corr to new protocol
  1552. for (j = k = 0;
  1553. j < pRouteInfo1->NextHopsList.NumNextHops;
  1554. j++)
  1555. {
  1556. if (RtmGetNextHopInfo(hRtmHandle,
  1557. pRouteInfo1->NextHopsList.NextHops[j],
  1558. &nhiInfo) is NO_ERROR)
  1559. {
  1560. // Add the same nexthop using new protocol
  1561. hNextHop = NULL;
  1562. if (RtmAddNextHop(hRtmHandle,
  1563. &nhiInfo,
  1564. &hNextHop,
  1565. &dwFlags) is NO_ERROR)
  1566. {
  1567. pRouteInfo2->NextHopsList.NextHops[k++] = hNextHop;
  1568. }
  1569. RtmReleaseNextHopInfo(hRtmHandle, &nhiInfo);
  1570. }
  1571. }
  1572. pRouteInfo2->NextHopsList.NumNextHops = (USHORT) k;
  1573. // Add the new route with the next hop information
  1574. if (k > 0)
  1575. {
  1576. dwFlags = 0;
  1577. if (RtmAddRouteToDest(hRtmHandle,
  1578. NULL,
  1579. &rnaDest,
  1580. pRouteInfo2,
  1581. INFINITE,
  1582. NULL,
  1583. 0,
  1584. NULL,
  1585. &dwFlags) is NO_ERROR)
  1586. {
  1587. // Route add is successful - delete old route
  1588. if (RtmDeleteRouteToDest(pRouteInfo1->RouteOwner,
  1589. hRoutes[i],
  1590. &dwFlags) is NO_ERROR)
  1591. {
  1592. fDeleted = TRUE;
  1593. }
  1594. }
  1595. RtmReleaseNextHops(hRtmHandle,
  1596. k,
  1597. pRouteInfo2->NextHopsList.NextHops);
  1598. }
  1599. }
  1600. RtmReleaseRouteInfo(hRtmHandle, pRouteInfo1);
  1601. }
  1602. if (!fDeleted)
  1603. {
  1604. RtmReleaseRoutes(hRtmHandle, 1, &hRoutes[i]);
  1605. }
  1606. }
  1607. }
  1608. while (dwResult is NO_ERROR);
  1609. RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
  1610. HeapFree(IPRouterHeap, 0, hRoutes);
  1611. HeapFree(IPRouterHeap, 0, pRouteInfo1);
  1612. HeapFree(IPRouterHeap, 0, pRouteInfo2);
  1613. return NO_ERROR;
  1614. }
  1615. DWORD
  1616. DeleteRtmRoutes (
  1617. IN HANDLE hRtmHandle,
  1618. IN DWORD dwIfIndex,
  1619. IN BOOL fDeleteAll
  1620. )
  1621. {
  1622. HANDLE hRtmEnum;
  1623. PHANDLE hRoutes;
  1624. DWORD dwHandles;
  1625. DWORD dwFlags;
  1626. DWORD i;
  1627. DWORD dwResult;
  1628. hRoutes = HeapAlloc(
  1629. IPRouterHeap,
  1630. 0,
  1631. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  1632. );
  1633. if (hRoutes == NULL)
  1634. {
  1635. Trace1(ERR,
  1636. "DeleteRtmRoutes: Error allocating %d bytes",
  1637. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE));
  1638. return ERROR_NOT_ENOUGH_MEMORY;
  1639. }
  1640. dwFlags = fDeleteAll ? 0: RTM_MATCH_INTERFACE;
  1641. dwResult = RtmCreateRouteEnum(hRtmHandle,
  1642. NULL,
  1643. RTM_VIEW_MASK_ANY,
  1644. RTM_ENUM_OWN_ROUTES,
  1645. NULL,
  1646. dwFlags,
  1647. NULL,
  1648. dwIfIndex,
  1649. &hRtmEnum);
  1650. if(dwResult isnot NO_ERROR)
  1651. {
  1652. Trace2(ERR,
  1653. "DeleteRtmRoutes: Error %d creating handle for %d\n",
  1654. dwResult,
  1655. hRtmHandle);
  1656. HeapFree(IPRouterHeap, 0, hRoutes);
  1657. return dwResult;
  1658. }
  1659. do
  1660. {
  1661. dwHandles = g_rtmProfile.MaxHandlesInEnum;
  1662. dwResult = RtmGetEnumRoutes(hRtmHandle,
  1663. hRtmEnum,
  1664. &dwHandles,
  1665. hRoutes);
  1666. for (i = 0; i < dwHandles; i++)
  1667. {
  1668. if (RtmDeleteRouteToDest(hRtmHandle,
  1669. hRoutes[i],
  1670. &dwFlags) isnot NO_ERROR)
  1671. {
  1672. // If delete is successful, this is automatic
  1673. RtmReleaseRoutes(hRtmHandle, 1, &hRoutes[i]);
  1674. }
  1675. }
  1676. }
  1677. while (dwResult is NO_ERROR);
  1678. RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
  1679. HeapFree(IPRouterHeap, 0, hRoutes);
  1680. return NO_ERROR;
  1681. }
  1682. DWORD
  1683. DeleteRtmNexthops (
  1684. IN HANDLE hRtmHandle,
  1685. IN DWORD dwIfIndex,
  1686. IN BOOL fDeleteAll
  1687. )
  1688. {
  1689. PRTM_NEXTHOP_INFO pNexthop;
  1690. PHANDLE hNexthops;
  1691. HANDLE hRtmEnum;
  1692. DWORD dwHandles;
  1693. DWORD i;
  1694. DWORD dwResult;
  1695. hNexthops = HeapAlloc(
  1696. IPRouterHeap,
  1697. 0,
  1698. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  1699. );
  1700. if (hNexthops == NULL)
  1701. {
  1702. Trace1(ERR,
  1703. "DeleteRtmNextHops: Error allocating %d bytes",
  1704. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE));
  1705. return ERROR_NOT_ENOUGH_MEMORY;
  1706. }
  1707. dwResult = RtmCreateNextHopEnum(hRtmHandle,
  1708. 0,
  1709. NULL,
  1710. &hRtmEnum);
  1711. if(dwResult isnot NO_ERROR)
  1712. {
  1713. Trace2(ERR,
  1714. "DeleteAllNexthops: Error %d creating handle for %d\n",
  1715. dwResult,
  1716. hRtmHandle);
  1717. HeapFree(IPRouterHeap, 0, hNexthops);
  1718. return dwResult;
  1719. }
  1720. do
  1721. {
  1722. dwHandles = g_rtmProfile.MaxHandlesInEnum;
  1723. dwResult = RtmGetEnumNextHops(hRtmHandle,
  1724. hRtmEnum,
  1725. &dwHandles,
  1726. hNexthops);
  1727. for (i = 0; i < dwHandles; i++)
  1728. {
  1729. if (!fDeleteAll)
  1730. {
  1731. //
  1732. // Make sure that the interface matches
  1733. //
  1734. if ((RtmGetNextHopPointer(hRtmHandle,
  1735. hNexthops[i],
  1736. &pNexthop) isnot NO_ERROR) ||
  1737. (pNexthop->InterfaceIndex != dwIfIndex))
  1738. {
  1739. RtmReleaseNextHops(hRtmHandle, 1, &hNexthops[i]);
  1740. continue;
  1741. }
  1742. }
  1743. // We need to delete this next hop here
  1744. if (RtmDeleteNextHop(hRtmHandle,
  1745. hNexthops[i],
  1746. NULL) isnot NO_ERROR)
  1747. {
  1748. // If delete is successful, this is automatic
  1749. RtmReleaseNextHops(hRtmHandle, 1, &hNexthops[i]);
  1750. }
  1751. }
  1752. }
  1753. while (dwResult is NO_ERROR);
  1754. RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
  1755. HeapFree(IPRouterHeap, 0, hNexthops);
  1756. return NO_ERROR;
  1757. }