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

360 lines
7.6 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. rtmtimer.c
  5. Abstract:
  6. Contains timer callbacks for handling RTM
  7. functions like aging out routes etc.
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 14-Sep-1998
  10. Revision History:
  11. --*/
  12. #include "pchrtm.h"
  13. #pragma hdrstop
  14. VOID
  15. NTAPI
  16. RouteExpiryTimeoutCallback (
  17. IN PVOID Context,
  18. IN BOOLEAN TimeOut
  19. )
  20. /*++
  21. Routine Description:
  22. This routine is invoked when the expiry timer
  23. associated with a route fires. At this time,
  24. the route needs to be aged out.
  25. Arguments:
  26. Context - Context for this timer callback
  27. TimeOut - TRUE if the timer fired,
  28. FALSE if wait satisfied.
  29. Return Value:
  30. None
  31. --*/
  32. {
  33. PRTM_ENTITY_HANDLE EntityHandle;
  34. PRTM_ROUTE_HANDLE RouteHandle;
  35. PADDRFAM_INFO AddrFamInfo;
  36. PENTITY_INFO Entity;
  37. PDEST_INFO Dest;
  38. PROUTE_INFO Route;
  39. DWORD ChangeFlags;
  40. BOOL Success;
  41. DWORD Status;
  42. UNREFERENCED_PARAMETER(TimeOut);
  43. Route = (PROUTE_INFO) ((PROUTE_TIMER)Context)->Route;
  44. Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);
  45. //
  46. // Has the timer has not been updated after it fired
  47. //
  48. ACQUIRE_DEST_WRITE_LOCK(Dest);
  49. if (Route->TimerContext != Context)
  50. {
  51. RELEASE_DEST_WRITE_LOCK(Dest);
  52. //
  53. // The timer has been updated after it fired,
  54. // This timer context is freed by the update
  55. //
  56. return;
  57. }
  58. //
  59. // The timer is still valid for this route,
  60. // Indicate to entity and free the context
  61. //
  62. Route->TimerContext = NULL;
  63. RELEASE_DEST_WRITE_LOCK(Dest);
  64. //
  65. // Inform the owner that the route has expired
  66. //
  67. EntityHandle = Route->RouteInfo.RouteOwner;
  68. Entity = ENTITY_FROM_HANDLE(EntityHandle);
  69. AddrFamInfo = Entity->OwningAddrFamily;
  70. RouteHandle = MAKE_HANDLE_FROM_POINTER(Route);
  71. REFERENCE_ROUTE(Route, HANDLE_REF);
  72. Status = ERROR_NOT_SUPPORTED;
  73. if (Entity->EventCallback)
  74. {
  75. //
  76. // This callback can turn back and post RTM calls,
  77. // so release locks before invoking this callback
  78. //
  79. Status = Entity->EventCallback(EntityHandle,
  80. RTM_ROUTE_EXPIRED,
  81. RouteHandle,
  82. &Route->RouteInfo);
  83. }
  84. if (Status == ERROR_NOT_SUPPORTED)
  85. {
  86. //
  87. // Delete the route as the owner does not care
  88. //
  89. Status = RtmDeleteRouteToDest(EntityHandle,
  90. RouteHandle,
  91. &ChangeFlags);
  92. //
  93. // The route could already have been deleted here
  94. //
  95. ASSERT((Status == NO_ERROR) ||
  96. (Status == ERROR_NOT_FOUND) ||
  97. (Status == ERROR_INVALID_HANDLE));
  98. }
  99. //
  100. // Free the context as we do not need it now
  101. //
  102. Success = DeleteTimerQueueTimer(AddrFamInfo->RouteTimerQueue,
  103. ((PROUTE_TIMER)Context)->Timer,
  104. NULL);
  105. // ASSERT(Success);
  106. FreeMemory(Context);
  107. DEREFERENCE_ROUTE(Route, TIMER_REF);
  108. return;
  109. }
  110. VOID
  111. NTAPI
  112. RouteHolddownTimeoutCallback (
  113. IN PVOID Context,
  114. IN BOOLEAN TimeOut
  115. )
  116. /*++
  117. Routine Description:
  118. This routine is invoked when holddown timer
  119. associated with a route fires. At this time,
  120. the route needs to be taken out of holddown.
  121. Arguments:
  122. Context - Context for this timer callback
  123. TimeOut - TRUE if the timer fired,
  124. FALSE if wait satisfied.
  125. Return Value:
  126. None
  127. --*/
  128. {
  129. PADDRFAM_INFO AddrFamInfo;
  130. PENTITY_INFO Entity;
  131. PDEST_INFO Dest;
  132. PROUTE_INFO Route;
  133. PROUTE_INFO HoldRoute;
  134. PLOOKUP_LINKAGE DestData;
  135. ULONG NotifyToCNs;
  136. DWORD ViewsForCT[RTM_NUM_CHANGE_TYPES];
  137. UINT i;
  138. BOOL Success;
  139. DWORD Status;
  140. UNREFERENCED_PARAMETER(TimeOut);
  141. Route = (PROUTE_INFO) ((PROUTE_TIMER)Context)->Route;
  142. Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);
  143. Entity = ENTITY_FROM_HANDLE(Route->RouteInfo.RouteOwner);
  144. AddrFamInfo = Entity->OwningAddrFamily;
  145. //
  146. // The route must surely be in holddown by this time
  147. //
  148. ASSERT(Route->RouteInfo.State == RTM_ROUTE_STATE_DELETED);
  149. //
  150. // Has the timer has not been updated after it fired
  151. //
  152. ACQUIRE_DEST_WRITE_LOCK(Dest);
  153. if (Route->TimerContext != Context)
  154. {
  155. RELEASE_DEST_WRITE_LOCK(Dest);
  156. ASSERT(FALSE);
  157. //
  158. // The timer has been updated after it fired,
  159. // This timer context is freed by the update
  160. //
  161. return;
  162. }
  163. //
  164. // The timer is still valid for this route
  165. //
  166. //
  167. // Remove this holddown route from the dest
  168. //
  169. for (i = 0; i < AddrFamInfo->NumberOfViews; i++)
  170. {
  171. HoldRoute = Dest->ViewInfo[i].HoldRoute;
  172. if (HoldRoute == Route)
  173. {
  174. DEREFERENCE_ROUTE(HoldRoute, HOLD_REF);
  175. Dest->ViewInfo[i].HoldRoute = NULL;
  176. }
  177. }
  178. //
  179. // We need to generate notifications for any
  180. // holddown protocols interesed in this dest
  181. //
  182. //
  183. // Calculate the CNs that need to be notified
  184. //
  185. ACQUIRE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  186. for (i = 0; i < RTM_NUM_CHANGE_TYPES; i++)
  187. {
  188. ViewsForCT[i] = AddrFamInfo->ViewsSupported;
  189. }
  190. NotifyToCNs = ComputeCNsToBeNotified(AddrFamInfo,
  191. Dest->DestMarkedBits,
  192. ViewsForCT);
  193. //
  194. // Add to the global change list if required
  195. //
  196. if (NotifyToCNs)
  197. {
  198. AddToChangedDestLists(AddrFamInfo,
  199. Dest,
  200. NotifyToCNs);
  201. }
  202. RELEASE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  203. //
  204. // Reset the timer context and free it later
  205. //
  206. Route->TimerContext = NULL;
  207. //
  208. // Reduce hold ref so that dest can be deleted
  209. //
  210. ASSERT(Dest->HoldRefCount > 0);
  211. if (Dest->NumRoutes || (Dest->HoldRefCount > 1))
  212. {
  213. Dest->HoldRefCount--;
  214. }
  215. else
  216. {
  217. //
  218. // Removal of hold might result in dest deletion
  219. //
  220. RELEASE_DEST_WRITE_LOCK(Dest);
  221. ACQUIRE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  222. ACQUIRE_DEST_WRITE_LOCK(Dest);
  223. Dest->HoldRefCount--;
  224. if ((Dest->NumRoutes == 0) && (Dest->HoldRefCount == 0))
  225. {
  226. Dest->State = DEST_STATE_DELETED;
  227. Status = DeleteFromTable(AddrFamInfo->RouteTable,
  228. Dest->DestAddress.NumBits,
  229. Dest->DestAddress.AddrBits,
  230. NULL,
  231. &DestData);
  232. ASSERT(SUCCESS(Status));
  233. AddrFamInfo->NumDests--;
  234. }
  235. RELEASE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  236. }
  237. RELEASE_DEST_WRITE_LOCK(Dest);
  238. //
  239. // Free the context as we do not need it now
  240. //
  241. Success = DeleteTimerQueueTimer(AddrFamInfo->RouteTimerQueue,
  242. ((PROUTE_TIMER)Context)->Timer,
  243. NULL);
  244. // ASSERT(Success);
  245. FreeMemory(Context);
  246. DEREFERENCE_ROUTE(Route, TIMER_REF);
  247. return;
  248. }