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.

1649 lines
38 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. rtmchng.c
  5. Abstract:
  6. Contains routines for giving out change
  7. notification registrations to entities
  8. registered with the RTM.
  9. Author:
  10. Chaitanya Kodeboyina (chaitk) 10-Sep-1998
  11. Revision History:
  12. --*/
  13. #include "pchrtm.h"
  14. #pragma hdrstop
  15. DWORD
  16. WINAPI
  17. RtmRegisterForChangeNotification (
  18. IN RTM_ENTITY_HANDLE RtmRegHandle,
  19. IN RTM_VIEW_SET TargetViews,
  20. IN RTM_NOTIFY_FLAGS NotifyFlags,
  21. IN PVOID NotifyContext,
  22. OUT PRTM_NOTIFY_HANDLE NotifyHandle
  23. )
  24. /*++
  25. Routine Description:
  26. Creates a new change notification using which the caller can
  27. receive notifications to changes in best route information.
  28. Arguments:
  29. RtmRegHandle - RTM registration handle for calling entity,
  30. TargetViews - Set of views in which changes are tracked,
  31. NotifyFlags - Flags that indicate the change types and
  32. dests (marked or all) caller is interested in,
  33. NotifyContext - Context for callback to indicate new changes,
  34. NotifyHandle - Handle to this notification info used in all
  35. subsequent calls - to get changes and so on.
  36. Return Value:
  37. Status of the operation
  38. --*/
  39. {
  40. PADDRFAM_INFO AddrFamInfo;
  41. PENTITY_INFO Entity;
  42. PNOTIFY_INFO Notif;
  43. BOOL LockInited;
  44. UINT i, j;
  45. DWORD Status;
  46. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  47. AddrFamInfo = Entity->OwningAddrFamily;
  48. //
  49. // Is he interested in any change types supported ?
  50. //
  51. if ((NotifyFlags & RTM_CHANGE_TYPES_MASK) == 0)
  52. {
  53. return ERROR_INVALID_PARAMETER;
  54. }
  55. //
  56. // Is he interested in any non-supported views ?
  57. //
  58. if (TargetViews & ~AddrFamInfo->ViewsSupported)
  59. {
  60. return ERROR_NOT_SUPPORTED;
  61. }
  62. //
  63. // Create and initialize a change notification block
  64. //
  65. Notif = (PNOTIFY_INFO) AllocNZeroObject(sizeof(NOTIFY_INFO) +
  66. AddrFamInfo->MaxHandlesInEnum *
  67. sizeof(PDEST_INFO));
  68. if (Notif == NULL)
  69. {
  70. return ERROR_NOT_ENOUGH_MEMORY;
  71. }
  72. #if WRN
  73. Status = ERROR_GEN_FAILURE;
  74. #endif
  75. do
  76. {
  77. #if DBG_HDL
  78. Notif->NotifyHeader.ObjectHeader.TypeSign = NOTIFY_ALLOC;
  79. Notif->NotifyHeader.HandleType = NOTIFY_TYPE;
  80. #endif
  81. Notif->OwningEntity = Entity;
  82. Notif->TargetViews = TargetViews;
  83. Notif->NumberOfViews = NUMBER_OF_BITS(TargetViews);
  84. Notif->ChangeTypes = NotifyFlags;
  85. LockInited = FALSE;
  86. try
  87. {
  88. InitializeCriticalSection(&Notif->NotifyLock);
  89. LockInited = TRUE;
  90. }
  91. except(EXCEPTION_EXECUTE_HANDLER)
  92. {
  93. Status = GetLastError();
  94. break;
  95. }
  96. Notif->NotifyContext = NotifyContext;
  97. InitializeQueue(&Notif->NotifyDests, AddrFamInfo->MaxHandlesInEnum);
  98. Notif->CNIndex = -1;
  99. ACQUIRE_NOTIFICATIONS_WRITE_LOCK(AddrFamInfo);
  100. do
  101. {
  102. //
  103. // Do we have any space for a new change notification ?
  104. //
  105. if (AddrFamInfo->NumChangeNotifs >= AddrFamInfo->MaxChangeNotifs)
  106. {
  107. Status = ERROR_NO_SYSTEM_RESOURCES;
  108. break;
  109. }
  110. //
  111. // Search for an unused change notification (CN) slot
  112. //
  113. for (i = 0; i < AddrFamInfo->MaxChangeNotifs; i++)
  114. {
  115. if (AddrFamInfo->ChangeNotifsDir[i] == 0)
  116. {
  117. break;
  118. }
  119. }
  120. ASSERT(i < AddrFamInfo->MaxChangeNotifs);
  121. //
  122. // Reserve the CN index in the change notification dir
  123. //
  124. Notif->CNIndex = i;
  125. AddrFamInfo->ChangeNotifsDir[i] = Notif;
  126. AddrFamInfo->NumChangeNotifs++;
  127. //
  128. // Fill in the CN information for this index on AF
  129. //
  130. SET_BIT(AddrFamInfo->ChangeNotifRegns, i);
  131. // Do we indicate changes to marked dests only
  132. if (NotifyFlags & RTM_NOTIFY_ONLY_MARKED_DESTS)
  133. {
  134. SET_BIT(AddrFamInfo->CNsForMarkedDests, i);
  135. }
  136. //
  137. // Mark each view in which CN is interested
  138. //
  139. if (TargetViews == RTM_VIEW_MASK_ANY)
  140. {
  141. TargetViews = RTM_VIEW_MASK_ALL;
  142. }
  143. for (j = 0; TargetViews; j++)
  144. {
  145. if (TargetViews & 0x01)
  146. {
  147. SET_BIT(AddrFamInfo->CNsForView[j], i);
  148. }
  149. TargetViews >>= 1;
  150. }
  151. //
  152. // Mark change types in which CN is interested
  153. //
  154. for (j = 0; j < RTM_NUM_CHANGE_TYPES; j++)
  155. {
  156. if (NotifyFlags & 0x01)
  157. {
  158. SET_BIT(AddrFamInfo->CNsForChangeType[j], i);
  159. }
  160. NotifyFlags >>= 1;
  161. }
  162. }
  163. while (FALSE);
  164. RELEASE_NOTIFICATIONS_WRITE_LOCK(AddrFamInfo);
  165. if (Notif->CNIndex == -1)
  166. {
  167. break;
  168. }
  169. #if DBG_HDL
  170. //
  171. // Insert into list of handles opened by entity
  172. //
  173. ACQUIRE_OPEN_HANDLES_LOCK(Entity);
  174. InsertTailList(&Entity->OpenHandles, &Notif->NotifyHeader.HandlesLE);
  175. RELEASE_OPEN_HANDLES_LOCK(Entity);
  176. #endif
  177. REFERENCE_ENTITY(Entity, NOTIFY_REF);
  178. //
  179. // Make a handle to the notify block and return
  180. //
  181. *NotifyHandle = MAKE_HANDLE_FROM_POINTER(Notif);
  182. return NO_ERROR;
  183. }
  184. while (FALSE);
  185. //
  186. // Something failed - undo work done and return status
  187. //
  188. if (LockInited)
  189. {
  190. DeleteCriticalSection(&Notif->NotifyLock);
  191. }
  192. #if DBG_HDL
  193. Notif->NotifyHeader.ObjectHeader.TypeSign = NOTIFY_FREED;
  194. #endif
  195. FreeObject(Notif);
  196. *NotifyHandle = NULL;
  197. return Status;
  198. }
  199. DWORD
  200. WINAPI
  201. RtmGetChangedDests (
  202. IN RTM_ENTITY_HANDLE RtmRegHandle,
  203. IN RTM_NOTIFY_HANDLE NotifyHandle,
  204. IN OUT PUINT NumDests,
  205. OUT PRTM_DEST_INFO ChangedDests
  206. )
  207. /*++
  208. Routine Description:
  209. Get the next set of destinations whose best route information
  210. has changed.
  211. Arguments:
  212. RtmRegHandle - RTM registration handle for calling entity,
  213. NotifyHandle - Handle to the change notification,
  214. NumDests - Num. of DestInfo's in output is passed in,
  215. Num. of DestInfo's copied out is returned.
  216. ChangedDests - Output buffer where destination info is retd.
  217. Return Value:
  218. Status of the operation
  219. --*/
  220. {
  221. PADDRFAM_INFO AddrFamInfo;
  222. PENTITY_INFO Entity;
  223. PNOTIFY_INFO Notif;
  224. UINT DestInfoSize;
  225. UINT DestsInput;
  226. PDEST_INFO Dest;
  227. INT CnIndex;
  228. DWORD Status;
  229. //
  230. // Init the output params in case we fail validation
  231. //
  232. DestsInput = *NumDests;
  233. *NumDests = 0;
  234. //
  235. // Do some validation checks on the input params
  236. //
  237. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  238. VALIDATE_NOTIFY_HANDLE(NotifyHandle, &Notif);
  239. AddrFamInfo = Entity->OwningAddrFamily;
  240. if (DestsInput > AddrFamInfo->MaxHandlesInEnum)
  241. {
  242. return ERROR_INVALID_PARAMETER;
  243. }
  244. DestInfoSize = RTM_SIZE_OF_DEST_INFO(Notif->NumberOfViews);
  245. CnIndex = Notif->CNIndex;
  246. Status = NO_ERROR;
  247. //
  248. // Get changed dests from the local queue on CN
  249. //
  250. ACQUIRE_CHANGE_NOTIFICATION_LOCK(Notif);
  251. while (*NumDests < DestsInput)
  252. {
  253. //
  254. // Get the next destination from the queue
  255. //
  256. DequeueItem(&Notif->NotifyDests, &Dest);
  257. if (Dest == NULL)
  258. {
  259. break;
  260. }
  261. #if DBG_TRACE
  262. if (TRACING_ENABLED(NOTIFY))
  263. {
  264. ULONG TempAddr, TempMask;
  265. RTM_IPV4_GET_ADDR_AND_MASK(TempAddr, TempMask, &Dest->DestAddress);
  266. Trace2(NOTIFY,"Returning dest %p to CN %d:", Dest, Notif->CNIndex);
  267. TracePrintAddress(NOTIFY, TempAddr, TempMask); Trace0(NOTIFY,"\n");
  268. }
  269. #endif
  270. ACQUIRE_DEST_WRITE_LOCK(Dest);
  271. // The queue bit for this CN should be set
  272. ASSERT(IS_BIT_SET(Dest->DestOnQueueBits, CnIndex));
  273. //
  274. // Do not copy dest if a change was ignored
  275. // after the dest was put on the queue - in which
  276. // case both Changed & OnQueue bits are set
  277. //
  278. if (IS_BIT_SET(Dest->DestChangedBits, CnIndex))
  279. {
  280. RESET_BIT(Dest->DestChangedBits, CnIndex);
  281. }
  282. else
  283. {
  284. //
  285. // Copy the dest information to output
  286. //
  287. GetDestInfo(Entity,
  288. Dest,
  289. RTM_BEST_PROTOCOL,
  290. Notif->TargetViews,
  291. ChangedDests);
  292. (*NumDests)++;
  293. ChangedDests =
  294. (PRTM_DEST_INFO) (DestInfoSize + (PUCHAR) ChangedDests);
  295. }
  296. // Reset bit as it has been pulled off the queue
  297. RESET_BIT(Dest->DestOnQueueBits, CnIndex);
  298. RELEASE_DEST_WRITE_LOCK(Dest);
  299. DEREFERENCE_DEST(Dest, NOTIFY_REF);
  300. }
  301. //
  302. // Do we have any more destinations in the queue ?
  303. //
  304. if ((*NumDests) == 0)
  305. {
  306. Status = ERROR_NO_MORE_ITEMS;
  307. }
  308. RELEASE_CHANGE_NOTIFICATION_LOCK(Notif);
  309. return Status;
  310. }
  311. DWORD
  312. WINAPI
  313. RtmReleaseChangedDests (
  314. IN RTM_ENTITY_HANDLE RtmRegHandle,
  315. IN RTM_NOTIFY_HANDLE NotifyHandle,
  316. IN UINT NumDests,
  317. IN PRTM_DEST_INFO ChangedDests
  318. )
  319. /*++
  320. Routine Description:
  321. Releases all handles present in the input dest info structures.
  322. Arguments:
  323. RtmRegHandle - RTM registration handle for calling entity,
  324. NotifyHandle - Handle to the change notification,
  325. NumDests - Number of dest info structures in buffer,
  326. ChangedDests - Array of dest info structures being released.
  327. Return Value:
  328. Status of the operation
  329. --*/
  330. {
  331. PENTITY_INFO Entity;
  332. UINT NumViews;
  333. UINT DestInfoSize;
  334. UINT i;
  335. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  336. //
  337. // De-registration could have happened by now
  338. // so do not validate the notification handle
  339. //
  340. UNREFERENCED_PARAMETER(NotifyHandle);
  341. //
  342. // Get size of dest info in info array
  343. //
  344. NumViews = ((PRTM_DEST_INFO) ChangedDests)->NumberOfViews;
  345. DestInfoSize = RTM_SIZE_OF_DEST_INFO(NumViews);
  346. //
  347. // Dereference each dest info in array
  348. //
  349. for (i = 0; i < NumDests; i++)
  350. {
  351. RtmReleaseDestInfo(RtmRegHandle, ChangedDests);
  352. ChangedDests = (PRTM_DEST_INFO) (DestInfoSize + (PUCHAR) ChangedDests);
  353. }
  354. return NO_ERROR;
  355. }
  356. DWORD
  357. WINAPI
  358. RtmIgnoreChangedDests (
  359. IN RTM_ENTITY_HANDLE RtmRegHandle,
  360. IN RTM_NOTIFY_HANDLE NotifyHandle,
  361. IN UINT NumDests,
  362. IN PRTM_DEST_HANDLE ChangedDests
  363. )
  364. /*++
  365. Routine Description:
  366. Ignores the next change on each of the input destinations if
  367. it has already occurred.
  368. We do not take a lock on the notification here as we are not
  369. serializing this call with other RtmGetChangedDests calls.
  370. Arguments:
  371. RtmRegHandle - RTM registration handle for calling entity,
  372. NotifyHandle - Handle to the change notification,
  373. NumDests - Number of dest handles in buffer below,
  374. ChangedDests - Dests whose next change we are ignoring.
  375. Return Value:
  376. Status of the operation
  377. --*/
  378. {
  379. PENTITY_INFO Entity;
  380. PNOTIFY_INFO Notif;
  381. PDEST_INFO Dest;
  382. INT CnIndex;
  383. BOOL ChangedBit;
  384. BOOL OnQueueBit;
  385. UINT i;
  386. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  387. VALIDATE_NOTIFY_HANDLE(NotifyHandle, &Notif);
  388. CnIndex = Notif->CNIndex;
  389. for (i = 0; i < NumDests; i++)
  390. {
  391. Dest = DEST_FROM_HANDLE(ChangedDests[i]);
  392. ACQUIRE_DEST_WRITE_LOCK(Dest);
  393. ChangedBit = IS_BIT_SET(Dest->DestChangedBits, CnIndex);
  394. OnQueueBit = IS_BIT_SET(Dest->DestOnQueueBits, CnIndex);
  395. if (ChangedBit && !OnQueueBit)
  396. {
  397. //
  398. // Dest on a changed list - reset the changed bit
  399. //
  400. RESET_BIT(Dest->DestChangedBits, CnIndex);
  401. //
  402. // If there are no more "changed bits" set on dest,
  403. // it is removed from the change list when the list
  404. // is processed next (in ProcessChangedDests call)
  405. //
  406. }
  407. else
  408. if (!ChangedBit && OnQueueBit)
  409. {
  410. //
  411. // Dest on queue - Invalidate by setting changed bit
  412. //
  413. SET_BIT(Dest->DestChangedBits, CnIndex);
  414. }
  415. RELEASE_DEST_WRITE_LOCK(Dest);
  416. }
  417. return NO_ERROR;
  418. }
  419. DWORD
  420. WINAPI
  421. RtmGetChangeStatus (
  422. IN RTM_ENTITY_HANDLE RtmRegHandle,
  423. IN RTM_NOTIFY_HANDLE NotifyHandle,
  424. IN RTM_DEST_HANDLE DestHandle,
  425. OUT PBOOL ChangeStatus
  426. )
  427. /*++
  428. Routine Description:
  429. Checks if there are pending changes to be notified on a dest.
  430. Arguments:
  431. RtmRegHandle - RTM registration handle for calling entity,
  432. NotifyHandle - Handle to the change notification,
  433. DestHandle - Dest whose change status we are querying,
  434. ChangedStatus - Change Status of this dest is returned.
  435. Return Value:
  436. Status of the operation
  437. --*/
  438. {
  439. PENTITY_INFO Entity;
  440. PNOTIFY_INFO Notif;
  441. PDEST_INFO Dest;
  442. INT CnIndex;
  443. BOOL ChangedBit;
  444. BOOL OnQueueBit;
  445. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  446. VALIDATE_NOTIFY_HANDLE(NotifyHandle, &Notif);
  447. VALIDATE_DEST_HANDLE(DestHandle, &Dest);
  448. CnIndex = Notif->CNIndex;
  449. ACQUIRE_DEST_READ_LOCK(Dest);
  450. ChangedBit = IS_BIT_SET(Dest->DestChangedBits, CnIndex);
  451. OnQueueBit = IS_BIT_SET(Dest->DestOnQueueBits, CnIndex);
  452. RELEASE_DEST_READ_LOCK(Dest);
  453. if (ChangedBit)
  454. {
  455. if (OnQueueBit)
  456. {
  457. // The last change has been ignored
  458. *ChangeStatus = FALSE;
  459. }
  460. else
  461. {
  462. // A pending change to be notified
  463. *ChangeStatus = TRUE;
  464. }
  465. }
  466. else
  467. {
  468. if (OnQueueBit)
  469. {
  470. // A pending change to be notified
  471. *ChangeStatus = TRUE;
  472. }
  473. else
  474. {
  475. // No changes available on this dest
  476. *ChangeStatus = FALSE;
  477. }
  478. }
  479. return NO_ERROR;
  480. }
  481. DWORD
  482. WINAPI
  483. RtmMarkDestForChangeNotification (
  484. IN RTM_ENTITY_HANDLE RtmRegHandle,
  485. IN RTM_NOTIFY_HANDLE NotifyHandle,
  486. IN RTM_DEST_HANDLE DestHandle,
  487. IN BOOL MarkDest
  488. )
  489. /*++
  490. Routine Description:
  491. Marks a destination to request notifications to changes to its
  492. best route information on this change notification.
  493. Arguments:
  494. RtmRegHandle - RTM registration handle for calling entity,
  495. NotifyHandle - Handle to the change notification,
  496. DestHandle - Dest that we are marking for notifications,
  497. MarkDest - Mark dest if TRUE, Unmark dest if FALSE
  498. Return Value:
  499. Status of the operation
  500. --*/
  501. {
  502. PENTITY_INFO Entity;
  503. PNOTIFY_INFO Notif;
  504. PDEST_INFO Dest;
  505. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  506. VALIDATE_NOTIFY_HANDLE(NotifyHandle, &Notif);
  507. // VALIDATE_DEST_HANDLE(DestHandle, &Dest);
  508. Dest = DEST_FROM_HANDLE(DestHandle);
  509. if (!Dest)
  510. {
  511. return ERROR_INVALID_HANDLE;
  512. }
  513. //
  514. // We make this check so that we can avoid taking
  515. // the dest lock (which is dynamic) unnecessarily
  516. //
  517. if (IS_BIT_SET(Dest->DestMarkedBits, Notif->CNIndex))
  518. {
  519. //
  520. // Reset mark bit on dest for this CN if reqd
  521. //
  522. if (!MarkDest)
  523. {
  524. ACQUIRE_DEST_WRITE_LOCK(Dest);
  525. RESET_BIT(Dest->DestMarkedBits, Notif->CNIndex);
  526. RELEASE_DEST_WRITE_LOCK(Dest);
  527. }
  528. }
  529. else
  530. {
  531. //
  532. // Set mark bit on dest for this CN if reqd
  533. //
  534. if (MarkDest)
  535. {
  536. ACQUIRE_DEST_WRITE_LOCK(Dest);
  537. SET_BIT(Dest->DestMarkedBits, Notif->CNIndex);
  538. RELEASE_DEST_WRITE_LOCK(Dest);
  539. }
  540. }
  541. return NO_ERROR;
  542. }
  543. DWORD
  544. WINAPI
  545. RtmIsMarkedForChangeNotification (
  546. IN RTM_ENTITY_HANDLE RtmRegHandle,
  547. IN RTM_NOTIFY_HANDLE NotifyHandle,
  548. IN RTM_DEST_HANDLE DestHandle,
  549. OUT PBOOL DestMarked
  550. )
  551. /*++
  552. Routine Description:
  553. Checks if a dest has been marked (by a CN handle) for receving
  554. notifications to changes in its best route information.
  555. Arguments:
  556. RtmRegHandle - RTM registration handle for calling entity,
  557. NotifyHandle - Handle to the change notification,
  558. DestHandle - Dest that we want to check is marked or not,
  559. DestMarked - TRUE if marked, and FALSE if not.
  560. Return Value:
  561. Status of the operation
  562. --*/
  563. {
  564. PENTITY_INFO Entity;
  565. PNOTIFY_INFO Notif;
  566. PDEST_INFO Dest;
  567. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  568. VALIDATE_NOTIFY_HANDLE(NotifyHandle, &Notif);
  569. // VALIDATE_DEST_HANDLE(DestHandle, &Dest);
  570. Dest = DEST_FROM_HANDLE(DestHandle);
  571. if (!Dest)
  572. {
  573. return ERROR_INVALID_HANDLE;
  574. }
  575. //
  576. // Return the state of mark bit on the dest for CN
  577. //
  578. *DestMarked = IS_BIT_SET(Dest->DestMarkedBits, Notif->CNIndex);
  579. return NO_ERROR;
  580. }
  581. DWORD
  582. WINAPI
  583. RtmDeregisterFromChangeNotification (
  584. IN RTM_ENTITY_HANDLE RtmRegHandle,
  585. IN RTM_NOTIFY_HANDLE NotifyHandle
  586. )
  587. /*++
  588. Routine Description:
  589. Deregisters a change notification and frees all resources
  590. allocated to it. It also cleans up all information kept
  591. in the destination for this particular notification index.
  592. Arguments:
  593. RtmRegHandle - RTM registration handle for calling entity,
  594. NotifyHandle - Handle to notification being de-registered.
  595. Return Value:
  596. Status of the operation
  597. --*/
  598. {
  599. PADDRFAM_INFO AddrFamInfo;
  600. PENTITY_INFO Entity;
  601. PNOTIFY_INFO Notif;
  602. PDEST_INFO Dest;
  603. UINT NumDests;
  604. INT CNIndex;
  605. UINT i;
  606. DWORD Status;
  607. RTM_NET_ADDRESS NetAddress;
  608. RTM_VIEW_SET ViewSet;
  609. PLOOKUP_LINKAGE DestData[DEFAULT_MAX_HANDLES_IN_ENUM];
  610. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  611. AddrFamInfo = Entity->OwningAddrFamily;
  612. VALIDATE_NOTIFY_HANDLE(NotifyHandle, &Notif);
  613. //
  614. // Remove this notification from CN regn's mask
  615. // so that no more bits for this CN will be set
  616. //
  617. ACQUIRE_NOTIFICATIONS_WRITE_LOCK(AddrFamInfo);
  618. CNIndex = Notif->CNIndex;
  619. ASSERT(AddrFamInfo->ChangeNotifsDir[CNIndex] == Notif);
  620. Notif->CNIndex = -1;
  621. RESET_BIT(AddrFamInfo->ChangeNotifRegns, CNIndex);
  622. //
  623. // Reset other bits that refer to the CN's state
  624. //
  625. // Unmark state whether this CN need marked dests
  626. RESET_BIT(AddrFamInfo->CNsForMarkedDests, CNIndex);
  627. // Unmark interest of this CN in each view
  628. ViewSet = RTM_VIEW_MASK_ALL;
  629. for (i = 0; ViewSet; i++)
  630. {
  631. if (ViewSet & 0x01)
  632. {
  633. RESET_BIT(AddrFamInfo->CNsForView[i], CNIndex);
  634. }
  635. ViewSet >>= 1;
  636. }
  637. // Unmark CN's interest in each change type
  638. for (i = 0; i < RTM_NUM_CHANGE_TYPES; i++)
  639. {
  640. RESET_BIT(AddrFamInfo->CNsForChangeType[i], CNIndex);
  641. }
  642. RELEASE_NOTIFICATIONS_WRITE_LOCK(AddrFamInfo);
  643. //
  644. // Cleanup the notification's "DestChanged" bits
  645. //
  646. ProcessChangedDestLists(AddrFamInfo, FALSE);
  647. //
  648. // Reset the CN's marked bits on all the dests
  649. //
  650. ZeroMemory(&NetAddress, sizeof(RTM_NET_ADDRESS));
  651. do
  652. {
  653. NumDests = DEFAULT_MAX_HANDLES_IN_ENUM;
  654. ACQUIRE_ROUTE_TABLE_READ_LOCK(AddrFamInfo);
  655. Status = EnumOverTable(AddrFamInfo->RouteTable,
  656. &NetAddress.NumBits,
  657. NetAddress.AddrBits,
  658. NULL,
  659. 0,
  660. NULL,
  661. &NumDests,
  662. DestData);
  663. for (i = 0; i < NumDests; i++)
  664. {
  665. Dest = CONTAINING_RECORD(DestData[i], DEST_INFO, LookupLinkage);
  666. if (IS_BIT_SET(Dest->DestMarkedBits, CNIndex))
  667. {
  668. LOCKED_RESET_BIT(Dest->DestMarkedBits, CNIndex);
  669. }
  670. }
  671. RELEASE_ROUTE_TABLE_READ_LOCK(AddrFamInfo);
  672. }
  673. while (SUCCESS(Status));
  674. //
  675. // Now remove the CN completely from dir of CNs
  676. //
  677. ACQUIRE_NOTIFICATIONS_WRITE_LOCK(AddrFamInfo);
  678. AddrFamInfo->ChangeNotifsDir[CNIndex] = NULL;
  679. AddrFamInfo->NumChangeNotifs--;
  680. RELEASE_NOTIFICATIONS_WRITE_LOCK(AddrFamInfo);
  681. //
  682. // Deference any destinations on the CN's queue
  683. //
  684. while (TRUE)
  685. {
  686. //
  687. // Get the next destination from the queue
  688. //
  689. DequeueItem(&Notif->NotifyDests, &Dest);
  690. if (Dest == NULL)
  691. {
  692. break;
  693. }
  694. // Reset the "on CN's queue" bit on dest
  695. if (IS_BIT_SET(Dest->DestOnQueueBits, CNIndex))
  696. {
  697. LOCKED_RESET_BIT(Dest->DestOnQueueBits, CNIndex);
  698. }
  699. DEREFERENCE_DEST(Dest, NOTIFY_REF);
  700. }
  701. //
  702. // Free all resources allocated to this CN
  703. //
  704. DeleteCriticalSection(&Notif->NotifyLock);
  705. #if DBG_HDL
  706. //
  707. // Remove from the list of handles opened by entity
  708. //
  709. ACQUIRE_OPEN_HANDLES_LOCK(Entity);
  710. RemoveEntryList(&Notif->NotifyHeader.HandlesLE);
  711. RELEASE_OPEN_HANDLES_LOCK(Entity);
  712. #endif
  713. DEREFERENCE_ENTITY(Entity, NOTIFY_REF);
  714. // Free memory allocated for notification and return
  715. #if DBG_HDL
  716. Notif->NotifyHeader.ObjectHeader.TypeSign = NOTIFY_FREED;
  717. #endif
  718. FreeObject(Notif);
  719. return NO_ERROR;
  720. }
  721. DWORD
  722. ComputeCNsToBeNotified (
  723. IN PADDRFAM_INFO AddrFamInfo,
  724. IN DWORD DestMarkedBits,
  725. IN DWORD *ViewsForChangeType
  726. )
  727. /*++
  728. Routine Description:
  729. Computes the set of change notification registrations that
  730. need to be notified when the best route to a particular
  731. destination changes.
  732. Arguments:
  733. AddrFamInfo - Address family that has the CN regn info,
  734. DestMarkedBits - CN's that marked for changes this dest
  735. or the dest's parent if it's a new dest
  736. ViewsForChangeType
  737. - Views in which change of a type occurred.
  738. Return Value:
  739. CNs that need to be notified of this change.
  740. Locks:
  741. Called with ChangeNotifsLock in AddrFamInfo in READ mode
  742. as this protects CN regn info from changing while we are
  743. reading it.
  744. --*/
  745. {
  746. RTM_VIEW_SET ViewSet;
  747. DWORD FilterCNs;
  748. DWORD CNsForCT;
  749. UINT i, j;
  750. DWORD NotifyCNs;
  751. //
  752. // Either a CN has marked the dest, or wants all changes
  753. //
  754. NotifyCNs = DestMarkedBits | ~AddrFamInfo->CNsForMarkedDests;
  755. if (NotifyCNs == 0)
  756. {
  757. return 0;
  758. }
  759. // The CNs not in this bit-mask should not be notified
  760. FilterCNs = NotifyCNs;
  761. NotifyCNs = 0;
  762. for (i = 0; i < RTM_NUM_CHANGE_TYPES; i++)
  763. {
  764. //
  765. // For each change type, get all CN's that can be notified
  766. //
  767. // See what views this change type (CT) applies to
  768. CNsForCT = 0;
  769. ViewSet = ViewsForChangeType[i];
  770. for (j = 0; ViewSet; j++)
  771. {
  772. // For each view, get all interested CN's
  773. if (ViewSet & 0x01)
  774. {
  775. CNsForCT |= AddrFamInfo->CNsForView[j];
  776. }
  777. ViewSet >>= 1;
  778. }
  779. // Now see which CNs are actually interested in CT
  780. CNsForCT &= AddrFamInfo->CNsForChangeType[i];
  781. // Add these CNs to the CNs need to be notified
  782. NotifyCNs |= CNsForCT;
  783. //
  784. // If we have to notify all CNs, we are done here
  785. //
  786. if (NotifyCNs == AddrFamInfo->ChangeNotifRegns)
  787. {
  788. break;
  789. }
  790. }
  791. //
  792. // Apply the filer of CNs you stored away earlier
  793. //
  794. NotifyCNs &= FilterCNs;
  795. return NotifyCNs;
  796. }
  797. DWORD
  798. AddToChangedDestLists (
  799. IN PADDRFAM_INFO AddrFamInfo,
  800. IN PDEST_INFO Dest,
  801. IN DWORD NotifyCNs
  802. )
  803. /*++
  804. Routine Description:
  805. Add a destination to a list of changed dests on address
  806. family, and sets the appropriate state in dest.
  807. Arguments:
  808. AddrFamInfo - The address family holding the change-list,
  809. Dest - Pointer to the dest that has changed,
  810. NotifyCNs - CNs that need to be notified of this change.
  811. Return Value:
  812. Status of the operation
  813. Locks:
  814. Called with destination lock held in WRITE mode as we are
  815. updating the DestChanged and DestOnQueue bits on it. This
  816. lock also protects the change list linkage.In other words
  817. you need to have the dest lock for inserting or removing
  818. from a change list.
  819. Also called with ChangeNotifsLock in AddrFamInfo in READ
  820. mode as this protects CN registration info from changing
  821. while we are adding to the list. If we do not take this
  822. lock, we might end up adding to the change list after an
  823. entity has de-registered from notifications. See code in
  824. RtmDeregisterFromChangeNotification.
  825. --*/
  826. {
  827. SINGLE_LIST_ENTRY *ListPtr;
  828. UINT ListNum;
  829. BOOL Success;
  830. //
  831. // Set change bits to 1 if not already on queue
  832. //
  833. Dest->DestChangedBits |= (NotifyCNs & ~Dest->DestOnQueueBits);
  834. //
  835. // Reset change bits to 0 if already on queue
  836. //
  837. Dest->DestChangedBits &= ~(NotifyCNs & Dest->DestOnQueueBits);
  838. //
  839. // Push dest into the change list if it is not
  840. // already on the list and we have new changes
  841. //
  842. if ((Dest->ChangeListLE.Next == NULL) &&
  843. (Dest->DestChangedBits & ~Dest->DestOnQueueBits))
  844. {
  845. // Get the change list to insert the dest in
  846. ListNum = CHANGE_LIST_TO_INSERT(Dest);
  847. //
  848. // Note that we take a lock on changes list
  849. // only if the dest (which is locked) isn't
  850. // already on the list, else could deadlock
  851. // with the code in ProcessChangedDestLists
  852. //
  853. #if DBG_TRACE
  854. if (TRACING_ENABLED(NOTIFY))
  855. {
  856. ULONG TempAddr, TempMask;
  857. RTM_IPV4_GET_ADDR_AND_MASK(TempAddr, TempMask, &Dest->DestAddress);
  858. Trace2(NOTIFY,"Adding dest %p to change list %d: ", Dest, ListNum);
  859. TracePrintAddress(NOTIFY, TempAddr, TempMask); Trace0(NOTIFY,"\n");
  860. }
  861. #endif
  862. ACQUIRE_CHANGED_DESTS_LIST_LOCK(AddrFamInfo, ListNum);
  863. //
  864. // Insert the item at the end of the list
  865. // and update the pointer to the list end
  866. //
  867. ListPtr = AddrFamInfo->ChangeLists[ListNum].ChangedDestsTail;
  868. PushEntryList(ListPtr, &Dest->ChangeListLE);
  869. AddrFamInfo->ChangeLists[ListNum].ChangedDestsTail =
  870. &Dest->ChangeListLE;
  871. RELEASE_CHANGED_DESTS_LIST_LOCK(AddrFamInfo, ListNum);
  872. REFERENCE_DEST(Dest, NOTIFY_REF);
  873. //
  874. // Activate a timer if it is not already done.
  875. // This is done with the dest lock held so the
  876. // dest doesn't get removed before this code.
  877. //
  878. if (InterlockedIncrement(&AddrFamInfo->NumChangedDests) == 1)
  879. {
  880. //
  881. // Create a periodic notifications timer
  882. //
  883. ACQUIRE_NOTIF_TIMER_LOCK(AddrFamInfo);
  884. ASSERT(AddrFamInfo->ChangeNotifTimer == NULL);
  885. do
  886. {
  887. Success = CreateTimerQueueTimer(&AddrFamInfo->ChangeNotifTimer,
  888. AddrFamInfo->NotifTimerQueue,
  889. ProcessChangedDestLists,
  890. AddrFamInfo,
  891. TIMER_CALLBACK_FREQUENCY,
  892. TIMER_CALLBACK_FREQUENCY,
  893. 0);
  894. if (Success)
  895. {
  896. break;
  897. }
  898. // Should not happen - but try again
  899. Sleep(0);
  900. }
  901. while (TRUE);
  902. RELEASE_NOTIF_TIMER_LOCK(AddrFamInfo);
  903. }
  904. }
  905. return NO_ERROR;
  906. }
  907. VOID
  908. NTAPI
  909. ProcessChangedDestLists (
  910. IN PVOID Context,
  911. IN BOOLEAN TimeOut
  912. )
  913. /*++
  914. Routine Description:
  915. Processes the lists of changes on the address family, and
  916. populates the per CN queues of changed destinations. If a
  917. dest is distributed to queues of all interested CNs, it is
  918. removed from the change list on address family to which it
  919. belonged.
  920. Arguments:
  921. AddrFamInfo - The address family holding the change-list.
  922. TimeOut - TRUE if called from a timer, FALSE if not
  923. Return Value:
  924. None
  925. --*/
  926. {
  927. PADDRFAM_INFO AddrFamInfo;
  928. RTM_ENTITY_HANDLE EntityHandle;
  929. PSINGLE_LIST_ENTRY ListPtr, TempList;
  930. PSINGLE_LIST_ENTRY Prev, Curr;
  931. RTM_EVENT_CALLBACK NotifyCallback;
  932. PNOTIFY_INFO Notif;
  933. PDEST_INFO Dest;
  934. UINT ListNum;
  935. UINT NumDests, i;
  936. INT NumDestsRemoved;
  937. DWORD ActualChangedBits;
  938. DWORD NotifyChanges;
  939. BOOL QueueEmpty, QueueFull;
  940. ULONG ThreadId;
  941. PLONG ListInUse;
  942. BOOL Success;
  943. UNREFERENCED_PARAMETER(TimeOut);
  944. DBG_UNREFERENCED_LOCAL_VARIABLE(ThreadId);
  945. #if DBG_TRACE
  946. ThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
  947. if (TRACING_ENABLED(NOTIFY))
  948. {
  949. Trace1(NOTIFY, "Entering ProcessChangedDestLists: %lu", ThreadId);
  950. }
  951. #endif
  952. AddrFamInfo = (PADDRFAM_INFO) Context;
  953. NotifyChanges = 0;
  954. NumDestsRemoved = 0;
  955. ACQUIRE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  956. for (ListNum = 0; ListNum < NUM_CHANGED_DEST_LISTS; ListNum++)
  957. {
  958. //
  959. // Check if this list is already being processed
  960. //
  961. ListInUse = &AddrFamInfo->ChangeLists[ListNum].ChangesListInUse;
  962. if (InterlockedIncrement(ListInUse) != 1)
  963. {
  964. InterlockedDecrement(ListInUse);
  965. continue;
  966. }
  967. //
  968. // Move all items in the list to a temp list
  969. //
  970. ListPtr = &AddrFamInfo->ChangeLists[ListNum].ChangedDestsHead;
  971. ACQUIRE_CHANGED_DESTS_LIST_LOCK(AddrFamInfo, ListNum);
  972. TempList = ListPtr->Next;
  973. ListPtr->Next = ListPtr;
  974. AddrFamInfo->ChangeLists[ListNum].ChangedDestsTail = ListPtr;
  975. RELEASE_CHANGED_DESTS_LIST_LOCK(AddrFamInfo, ListNum);
  976. //
  977. // Process each destination in the temp list
  978. //
  979. Prev = CONTAINING_RECORD(&TempList, SINGLE_LIST_ENTRY, Next);
  980. Curr = Prev->Next;
  981. NumDests = 0;
  982. while (Curr != ListPtr)
  983. {
  984. // Get the next destination on the list
  985. Dest = CONTAINING_RECORD(Curr, DEST_INFO, ChangeListLE);
  986. #if DBG_TRACE
  987. if (TRACING_ENABLED(NOTIFY))
  988. {
  989. ULONG Addr, Mask;
  990. RTM_IPV4_GET_ADDR_AND_MASK(Addr, Mask, &Dest->DestAddress);
  991. Trace2(NOTIFY, "Next dest %p in list %d: ", Dest, ListNum);
  992. TracePrintAddress(NOTIFY, Addr, Mask); Trace0(NOTIFY,"\n");
  993. }
  994. #endif
  995. ACQUIRE_DEST_WRITE_LOCK(Dest);
  996. //
  997. // Note that this dest can have no "changed bits" set,
  998. // yet be on the list because the changes were ignored
  999. // or because one of the entities deregistered its CN
  1000. //
  1001. // Remove bits obsoleted by any CN deregistrations
  1002. Dest->DestChangedBits &= AddrFamInfo->ChangeNotifRegns;
  1003. //
  1004. // Process all CNs whose DestChanged bit is set on dest
  1005. //
  1006. ActualChangedBits = Dest->DestChangedBits & ~Dest->DestOnQueueBits;
  1007. for (i = 0; i < AddrFamInfo->MaxChangeNotifs; i++)
  1008. {
  1009. if (!ActualChangedBits)
  1010. {
  1011. break;
  1012. }
  1013. if (IS_BIT_SET(ActualChangedBits, i))
  1014. {
  1015. Notif = AddrFamInfo->ChangeNotifsDir[i];
  1016. //
  1017. // Note that we take a lock on notify block
  1018. // only if the dest (which is locked) isn't
  1019. // already on the queue - otherwise we will
  1020. // deadlock with code in RtmGetChangedDests
  1021. //
  1022. ACQUIRE_CHANGE_NOTIFICATION_LOCK(Notif);
  1023. QueueEmpty = IsQueueEmpty(&Notif->NotifyDests);
  1024. //
  1025. // Enqueue this destination if the
  1026. // the CN's queue is not yet full
  1027. //
  1028. EnqueueItem(&Notif->NotifyDests, Dest, QueueFull);
  1029. if (!QueueFull)
  1030. {
  1031. //
  1032. // If we are adding changes to an
  1033. // empty queue, signal this event
  1034. //
  1035. if (QueueEmpty)
  1036. {
  1037. SET_BIT(NotifyChanges, i);
  1038. }
  1039. //
  1040. // Adjust dest change and queue bits
  1041. //
  1042. SET_BIT(Dest->DestOnQueueBits, i);
  1043. RESET_BIT(Dest->DestChangedBits, i);
  1044. RESET_BIT(ActualChangedBits, i);
  1045. REFERENCE_DEST(Dest, NOTIFY_REF);
  1046. }
  1047. RELEASE_CHANGE_NOTIFICATION_LOCK(Notif);
  1048. }
  1049. }
  1050. //
  1051. // Do we have any more changes to process on dest ?
  1052. //
  1053. if (ActualChangedBits == 0)
  1054. {
  1055. // Splice this dest from the changed list
  1056. Prev->Next = Curr->Next;
  1057. NumDestsRemoved++;
  1058. // "Next" == NULL means it is not on list
  1059. Curr->Next = NULL;
  1060. }
  1061. RELEASE_DEST_WRITE_LOCK(Dest);
  1062. //
  1063. // Do we have any more changes to process on dest ?
  1064. //
  1065. if (ActualChangedBits == 0)
  1066. {
  1067. DEREFERENCE_DEST(Dest, NOTIFY_REF);
  1068. }
  1069. else
  1070. {
  1071. // Advance the pointer to next dest in list
  1072. Prev = Curr;
  1073. }
  1074. Curr = Prev->Next;
  1075. if ((++NumDests == MAX_DESTS_TO_PROCESS_ONCE) ||
  1076. (Curr == ListPtr))
  1077. {
  1078. //
  1079. // Do we have any changes to inform to entities
  1080. //
  1081. for (i = 0; NotifyChanges != 0; i++)
  1082. {
  1083. if (NotifyChanges & 0x01)
  1084. {
  1085. Notif = AddrFamInfo->ChangeNotifsDir[i];
  1086. NotifyCallback = Notif->OwningEntity->EventCallback;
  1087. EntityHandle =
  1088. MAKE_HANDLE_FROM_POINTER(Notif->OwningEntity);
  1089. #if DBG_TRACE
  1090. if (TRACING_ENABLED(NOTIFY))
  1091. {
  1092. Trace1(NOTIFY, "Notifying CN %d BEGIN", i);
  1093. }
  1094. #endif
  1095. NotifyCallback(EntityHandle,
  1096. RTM_CHANGE_NOTIFICATION,
  1097. MAKE_HANDLE_FROM_POINTER(Notif),
  1098. Notif->NotifyContext);
  1099. #if DBG_TRACE
  1100. if (TRACING_ENABLED(NOTIFY))
  1101. {
  1102. Trace1(NOTIFY, "Notifying CN %d END\n", i);
  1103. }
  1104. #endif
  1105. }
  1106. NotifyChanges >>= 1;
  1107. }
  1108. // Reset counter for number of dests processed
  1109. NumDests = 0;
  1110. }
  1111. }
  1112. if (TempList != ListPtr)
  1113. {
  1114. //
  1115. // Merge back what is left of the temp list
  1116. //
  1117. ASSERT(Prev->Next == ListPtr);
  1118. ACQUIRE_CHANGED_DESTS_LIST_LOCK(AddrFamInfo, ListNum);
  1119. if (ListPtr->Next == ListPtr)
  1120. {
  1121. AddrFamInfo->ChangeLists[ListNum].ChangedDestsTail = Prev;
  1122. }
  1123. Prev->Next = ListPtr->Next;
  1124. ListPtr->Next = TempList;
  1125. RELEASE_CHANGED_DESTS_LIST_LOCK(AddrFamInfo, ListNum);
  1126. }
  1127. InterlockedDecrement(ListInUse);
  1128. }
  1129. //
  1130. // Update number of destinations left to process on change list
  1131. //
  1132. if (NumDestsRemoved)
  1133. {
  1134. //
  1135. // Do we have any more destinations to process ?
  1136. //
  1137. ACQUIRE_NOTIF_TIMER_LOCK(AddrFamInfo);
  1138. if (InterlockedExchangeAdd(&AddrFamInfo->NumChangedDests,
  1139. (-1) * NumDestsRemoved) == NumDestsRemoved)
  1140. {
  1141. //
  1142. // Delete timer as we have no items on change list
  1143. //
  1144. ASSERT(AddrFamInfo->ChangeNotifTimer);
  1145. Success = DeleteTimerQueueTimer(AddrFamInfo->NotifTimerQueue,
  1146. AddrFamInfo->ChangeNotifTimer,
  1147. NULL);
  1148. // ASSERT(Success);
  1149. AddrFamInfo->ChangeNotifTimer = NULL;
  1150. }
  1151. RELEASE_NOTIF_TIMER_LOCK(AddrFamInfo);
  1152. }
  1153. RELEASE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  1154. #if DBG_TRACE
  1155. if (TRACING_ENABLED(NOTIFY))
  1156. {
  1157. Trace1(NOTIFY, "Leaving ProcessChangedDestLists: %lu\n", ThreadId);
  1158. }
  1159. #endif
  1160. return;
  1161. }