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.

1584 lines
37 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. rtmobj1.c
  5. Abstract:
  6. Contains routines for managing RTM objects
  7. like Instances, AddrFamilies and Entities.
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 21-Aug-1998
  10. Revision History:
  11. --*/
  12. #include "pchrtm.h"
  13. #pragma hdrstop
  14. DWORD
  15. GetInstance (
  16. IN USHORT RtmInstanceId,
  17. IN BOOL ImplicitCreate,
  18. OUT PINSTANCE_INFO *RtmInstance
  19. )
  20. /*++
  21. Routine Description:
  22. Searches for an RTM instance with the input instance
  23. id. If an instance is not found and ImplicitCreate
  24. is TRUE, then a new instance is created and added to
  25. the table of instances.
  26. Arguments:
  27. RtmInstanceId - Id for RTM Instance being searched for,
  28. ImplicitCreate - Create a new instance if not found or not,
  29. RtmInstance - Pointer to the Instance Info Structure
  30. will be returned through this parameter.
  31. Return Value:
  32. Status of the operation
  33. Locks:
  34. The InstancesLock in RtmGlobals should be held while calling
  35. this function. If ImplicitCreate is FALSE, a read lock would
  36. do, but if it is TRUE then a write lock should be held as we
  37. would need to insert a new instance into the instances list.
  38. --*/
  39. {
  40. PLIST_ENTRY Instances;
  41. PINSTANCE_INFO Instance;
  42. PLIST_ENTRY p;
  43. DWORD Status;
  44. Instances = &RtmGlobals.InstanceTable[RtmInstanceId % INSTANCE_TABLE_SIZE];
  45. #if WRN
  46. Instance = NULL;
  47. #endif
  48. do
  49. {
  50. // Search the global list for a matching instance
  51. for (p = Instances->Flink; p != Instances; p = p->Flink)
  52. {
  53. Instance = CONTAINING_RECORD(p, INSTANCE_INFO, InstTableLE);
  54. if (Instance->RtmInstanceId >= RtmInstanceId)
  55. {
  56. break;
  57. }
  58. }
  59. if ((p == Instances) || (Instance->RtmInstanceId != RtmInstanceId))
  60. {
  61. // We did not find an instance - create new one ?
  62. if (!ImplicitCreate)
  63. {
  64. Status = ERROR_NOT_FOUND;
  65. break;
  66. }
  67. // Create a new instance with input Instance id
  68. Status = CreateInstance(RtmInstanceId, &Instance);
  69. if (Status != NO_ERROR)
  70. {
  71. break;
  72. }
  73. // Insert into list in sorted Instance Id order
  74. InsertTailList(p, &Instance->InstTableLE);
  75. }
  76. Status = NO_ERROR;
  77. *RtmInstance = Instance;
  78. }
  79. while (FALSE);
  80. return Status;
  81. }
  82. DWORD
  83. CreateInstance (
  84. IN USHORT RtmInstanceId,
  85. OUT PINSTANCE_INFO *NewInstance
  86. )
  87. /*++
  88. Routine Description:
  89. Creates a new instance info structure and initializes it.
  90. Arguments:
  91. RtmInstanceId - RTM Instance Id for the new RTM instance,
  92. InstConfig - Configuration Info for the new instance,
  93. NewInstance - Pointer to the Instance Info Structure
  94. will be returned through this parameter.
  95. Return Value:
  96. Status of the operation
  97. Locks:
  98. Need to be called with the instances WRITE lock as we are
  99. incrementing the number of instances here.
  100. --*/
  101. {
  102. RTM_INSTANCE_CONFIG InstConfig;
  103. PINSTANCE_INFO Instance;
  104. DWORD Status;
  105. *NewInstance = NULL;
  106. //
  107. // Read Instance Configuration from the registry
  108. //
  109. Status = RtmReadInstanceConfig(RtmInstanceId, &InstConfig);
  110. if (Status != NO_ERROR)
  111. {
  112. return Status;
  113. }
  114. //
  115. // Allocate and initialize a new instance info
  116. //
  117. Instance = (PINSTANCE_INFO) AllocNZeroObject(sizeof(INSTANCE_INFO));
  118. if (Instance == NULL)
  119. {
  120. return ERROR_NOT_ENOUGH_MEMORY;
  121. }
  122. #if DBG_HDL
  123. Instance->ObjectHeader.TypeSign = INSTANCE_ALLOC;
  124. #endif
  125. // Will be removed when last addr family goes
  126. INITIALIZE_INSTANCE_REFERENCE(Instance, CREATION_REF);
  127. Instance->RtmInstanceId = RtmInstanceId;
  128. //
  129. // Linking instance to global list of instances is
  130. // done by caller, but pretend it is already done
  131. //
  132. RtmGlobals.NumInstances++;
  133. InitializeListHead(&Instance->InstTableLE);
  134. //
  135. // Initialize the table of address families
  136. //
  137. Instance->NumAddrFamilies = 0;
  138. InitializeListHead(&Instance->AddrFamilyTable);
  139. *NewInstance = Instance;
  140. return NO_ERROR;
  141. }
  142. DWORD
  143. DestroyInstance (
  144. IN PINSTANCE_INFO Instance
  145. )
  146. /*++
  147. Routine Description:
  148. Destroys an existing instance info structure. Assumes that
  149. no registered entities exist on this instance when called.
  150. Arguments:
  151. Instance - Pointer to the Instance Info Structure.
  152. Return Value:
  153. Status of the operation
  154. Locks:
  155. The InstancesLock in RtmGlobals should be held while calling
  156. this function as it removes an instance from that list. This
  157. is typically taken in DestroyEntity, but it can also happen
  158. that the lock is acquired in RtmRegisterEntity and an error
  159. occured.
  160. --*/
  161. {
  162. ASSERT(Instance->ObjectHeader.RefCount == 0);
  163. ASSERT(Instance->NumAddrFamilies == 0);
  164. //
  165. // Remove this instance from list of instances
  166. //
  167. RemoveEntryList(&Instance->InstTableLE);
  168. RtmGlobals.NumInstances--;
  169. //
  170. // Free resources allocated for this instance
  171. //
  172. #if DBG_HDL
  173. Instance->ObjectHeader.TypeSign = INSTANCE_FREED;
  174. #endif
  175. FreeObject(Instance);
  176. return NO_ERROR;
  177. }
  178. DWORD
  179. GetAddressFamily (
  180. IN PINSTANCE_INFO Instance,
  181. IN USHORT AddressFamily,
  182. IN BOOL ImplicitCreate,
  183. OUT PADDRFAM_INFO *AddrFamilyInfo
  184. )
  185. /*++
  186. Routine Description:
  187. Searches for an address family in an RTM instance.
  188. If it is not found and ImplicitCreate is TRUE, then
  189. a new address family info is created and added to
  190. the list of address families.
  191. Arguments:
  192. Instance - RTM Instance that holds the address family,
  193. AddressFamily - Address family for info being searched for,
  194. ImplicitCreate - Create an addr family info if not found or not,
  195. AddrFamilyInfo - Pointer to the new Address Family Info
  196. will be returned through this parameter.
  197. Return Value:
  198. Status of the operation
  199. Locks:
  200. The InstancesLock in RtmGlobals should be held while calling
  201. this function. If ImplicitCreate is FALSE, a read lock would
  202. do, but if it is TRUE then a write lock should be held as we
  203. will need it to insert a new address family info into a list.
  204. --*/
  205. {
  206. PLIST_ENTRY AddrFams;
  207. PADDRFAM_INFO AddrFamInfo;
  208. PLIST_ENTRY q;
  209. DWORD Status;
  210. AddrFams = &Instance->AddrFamilyTable;
  211. #if WRN
  212. AddrFamInfo = NULL;
  213. #endif
  214. do
  215. {
  216. // Search the list of addr families on instance
  217. for (q = AddrFams->Flink; q != AddrFams; q = q->Flink)
  218. {
  219. AddrFamInfo = CONTAINING_RECORD(q, ADDRFAM_INFO, AFTableLE);
  220. if (AddrFamInfo->AddressFamily >= AddressFamily)
  221. {
  222. break;
  223. }
  224. }
  225. if ((q == AddrFams) || (AddrFamInfo->AddressFamily != AddressFamily))
  226. {
  227. // We did not find an instance - create new one ?
  228. if (!ImplicitCreate)
  229. {
  230. Status = ERROR_NOT_FOUND;
  231. break;
  232. }
  233. // Create a new addr family info with input family
  234. Status = CreateAddressFamily(Instance,AddressFamily, &AddrFamInfo);
  235. if (Status != NO_ERROR)
  236. {
  237. break;
  238. }
  239. // Insert into list sorted in Address Family order
  240. InsertTailList(q, &AddrFamInfo->AFTableLE);
  241. }
  242. Status = NO_ERROR;
  243. *AddrFamilyInfo = AddrFamInfo;
  244. }
  245. while (FALSE);
  246. return Status;
  247. }
  248. DWORD
  249. CreateAddressFamily (
  250. IN PINSTANCE_INFO Instance,
  251. IN USHORT AddressFamily,
  252. OUT PADDRFAM_INFO *NewAddrFamilyInfo
  253. )
  254. /*++
  255. Routine Description:
  256. Creates a new address family info and initializes it
  257. Arguments:
  258. Instance - RTM Instance that owns addr family info,
  259. AddressFamily - Address family for the new info block,
  260. AddrFamilyInfo - Pointer to the new Address Family Info
  261. will be returned through this parameter.
  262. Return Value:
  263. Status of the operation
  264. Locks:
  265. Need to be called with the instances WRITE lock as we are
  266. are incrementing number of address families on instance.
  267. --*/
  268. {
  269. RTM_ADDRESS_FAMILY_CONFIG AddrFamConfig;
  270. PADDRFAM_INFO AddrFamilyInfo;
  271. RTM_VIEW_SET ViewsSupported;
  272. PSINGLE_LIST_ENTRY ListPtr;
  273. UINT i;
  274. DWORD Status;
  275. *NewAddrFamilyInfo = NULL;
  276. //
  277. // Read AddressFamily Configuration from the registry
  278. //
  279. Status = RtmReadAddressFamilyConfig(Instance->RtmInstanceId,
  280. AddressFamily,
  281. &AddrFamConfig);
  282. if (Status != NO_ERROR)
  283. {
  284. if (Instance->NumAddrFamilies == 0)
  285. {
  286. DEREFERENCE_INSTANCE(Instance, CREATION_REF);
  287. }
  288. return Status;
  289. }
  290. //
  291. // Allocate and initialize a new address family info
  292. //
  293. AddrFamilyInfo = (PADDRFAM_INFO) AllocNZeroObject(sizeof(ADDRFAM_INFO));
  294. if (AddrFamilyInfo == NULL)
  295. {
  296. if (Instance->NumAddrFamilies == 0)
  297. {
  298. DEREFERENCE_INSTANCE(Instance, CREATION_REF);
  299. }
  300. return ERROR_NOT_ENOUGH_MEMORY;
  301. }
  302. do
  303. {
  304. #if DBG_HDL
  305. AddrFamilyInfo->ObjectHeader.TypeSign = ADDRESS_FAMILY_ALLOC;
  306. #endif
  307. // Will be removed when last entity deregisters
  308. INITIALIZE_ADDR_FAMILY_REFERENCE(AddrFamilyInfo, CREATION_REF);
  309. AddrFamilyInfo->AddressFamily = AddressFamily;
  310. AddrFamilyInfo->AddressSize = AddrFamConfig.AddressSize;
  311. AddrFamilyInfo->Instance = Instance;
  312. REFERENCE_INSTANCE(Instance, ADDR_FAMILY_REF);
  313. //
  314. // Linking the address family to its owning instance
  315. // is done by caller, but pretend it is already done
  316. //
  317. Instance->NumAddrFamilies++;
  318. InitializeListHead(&AddrFamilyInfo->AFTableLE);
  319. //
  320. // Count number of views supported by this addr family
  321. // & setup the view id <-> view index in dest mappings
  322. //
  323. AddrFamilyInfo->ViewsSupported = AddrFamConfig.ViewsSupported;
  324. ViewsSupported = AddrFamConfig.ViewsSupported;
  325. AddrFamilyInfo->NumberOfViews = 0;
  326. for (i = 0; i < RTM_MAX_VIEWS; i++)
  327. {
  328. AddrFamilyInfo->ViewIdFromIndex[i] = -1;
  329. AddrFamilyInfo->ViewIndexFromId[i] = -1;
  330. }
  331. for (i = 0; (i < RTM_MAX_VIEWS) && ViewsSupported; i++)
  332. {
  333. if (ViewsSupported & 0x01)
  334. {
  335. AddrFamilyInfo->ViewIdFromIndex[AddrFamilyInfo->NumberOfViews]
  336. = i;
  337. AddrFamilyInfo->ViewIndexFromId[i] =
  338. AddrFamilyInfo->NumberOfViews;
  339. AddrFamilyInfo->NumberOfViews++;
  340. }
  341. ViewsSupported >>= 1;
  342. }
  343. AddrFamilyInfo->MaxHandlesInEnum = AddrFamConfig.MaxHandlesInEnum;
  344. AddrFamilyInfo->MaxNextHopsInRoute = AddrFamConfig.MaxNextHopsInRoute;
  345. //
  346. // Initialize the opaque pointer's directory
  347. //
  348. AddrFamilyInfo->MaxOpaquePtrs = AddrFamConfig.MaxOpaqueInfoPtrs;
  349. AddrFamilyInfo->NumOpaquePtrs = 0;
  350. AddrFamilyInfo->OpaquePtrsDir =
  351. AllocNZeroMemory(AddrFamilyInfo->MaxOpaquePtrs * sizeof(PVOID));
  352. if (AddrFamilyInfo->OpaquePtrsDir == NULL)
  353. {
  354. Status = ERROR_NOT_ENOUGH_MEMORY;
  355. break;
  356. }
  357. //
  358. // Initialize the list of entities on this address family
  359. //
  360. AddrFamilyInfo->NumEntities = 0;
  361. for (i = 0; i < ENTITY_TABLE_SIZE; i++)
  362. {
  363. InitializeListHead(&AddrFamilyInfo->EntityTable[i]);
  364. }
  365. //
  366. // Init list of entities de-registered but not destroyed
  367. //
  368. InitializeListHead(&AddrFamilyInfo->DeregdEntities);
  369. //
  370. // Initialize the route table and route table lock
  371. //
  372. try
  373. {
  374. CREATE_READ_WRITE_LOCK(&AddrFamilyInfo->RouteTableLock);
  375. AddrFamilyInfo->RoutesLockInited = TRUE;
  376. }
  377. except(EXCEPTION_EXECUTE_HANDLER)
  378. {
  379. Status = GetLastError();
  380. break;
  381. }
  382. Status = CreateTable(AddrFamilyInfo->AddressSize,
  383. &AddrFamilyInfo->RouteTable);
  384. if (Status != NO_ERROR)
  385. {
  386. break;
  387. }
  388. //
  389. // Initialize queue to hold notification timers
  390. //
  391. AddrFamilyInfo->NotifTimerQueue = CreateTimerQueue();
  392. if (AddrFamilyInfo->NotifTimerQueue == NULL)
  393. {
  394. Status = GetLastError();
  395. break;
  396. }
  397. //
  398. // Initialize queue to hold route timers on AF
  399. //
  400. AddrFamilyInfo->RouteTimerQueue = CreateTimerQueue();
  401. if (AddrFamilyInfo->RouteTimerQueue == NULL)
  402. {
  403. Status = GetLastError();
  404. break;
  405. }
  406. //
  407. // Initialize the change notification info and lock
  408. //
  409. try
  410. {
  411. CREATE_READ_WRITE_LOCK(&AddrFamilyInfo->ChangeNotifsLock);
  412. AddrFamilyInfo->NotifsLockInited = TRUE;
  413. }
  414. except(EXCEPTION_EXECUTE_HANDLER)
  415. {
  416. Status = GetLastError();
  417. break;
  418. }
  419. AddrFamilyInfo->MaxChangeNotifs = AddrFamConfig.MaxChangeNotifyRegns;
  420. AddrFamilyInfo->NumChangeNotifs = 0;
  421. //
  422. // Allocate memory for the max number of notifications
  423. //
  424. AddrFamilyInfo->ChangeNotifsDir =
  425. AllocNZeroMemory(AddrFamilyInfo->MaxChangeNotifs *
  426. sizeof(PVOID));
  427. if (AddrFamilyInfo->ChangeNotifsDir == NULL)
  428. {
  429. Status = ERROR_NOT_ENOUGH_MEMORY;
  430. break;
  431. }
  432. //
  433. // Initialize lock protecting the notification timer
  434. //
  435. try
  436. {
  437. InitializeCriticalSection(&AddrFamilyInfo->NotifsTimerLock);
  438. AddrFamilyInfo->TimerLockInited = TRUE;
  439. }
  440. except(EXCEPTION_EXECUTE_HANDLER)
  441. {
  442. Status = GetLastError();
  443. break;
  444. }
  445. //
  446. // Initialize each change list in the change list table
  447. //
  448. for (i = 0; i < NUM_CHANGED_DEST_LISTS; i++)
  449. {
  450. //
  451. // Initialize the list of changed dests and lock
  452. //
  453. // Init the change list to an empty circular list
  454. ListPtr = &AddrFamilyInfo->ChangeLists[i].ChangedDestsHead;
  455. ListPtr->Next = ListPtr;
  456. AddrFamilyInfo->ChangeLists[i].ChangedDestsTail = ListPtr;
  457. try
  458. {
  459. InitializeCriticalSection
  460. (&AddrFamilyInfo->ChangeLists[i].ChangesListLock);
  461. AddrFamilyInfo->ChangeLists[i].ChangesLockInited = TRUE;
  462. continue;
  463. }
  464. except(EXCEPTION_EXECUTE_HANDLER)
  465. {
  466. Status = GetLastError();
  467. }
  468. break;
  469. }
  470. if (Status != NO_ERROR)
  471. {
  472. break;
  473. }
  474. *NewAddrFamilyInfo = AddrFamilyInfo;
  475. return NO_ERROR;
  476. }
  477. while (FALSE);
  478. //
  479. // Something failed - undo work done and return status
  480. //
  481. DEREFERENCE_ADDR_FAMILY(AddrFamilyInfo, CREATION_REF);
  482. return Status;
  483. }
  484. DWORD
  485. DestroyAddressFamily (
  486. IN PADDRFAM_INFO AddrFamilyInfo
  487. )
  488. /*++
  489. Routine Description:
  490. Destroys an address family info in an RTM instance.
  491. Assumes that no registered entities exist with this
  492. address family in this RTM instance when invoked.
  493. This function has been written such that it can be
  494. called when an error occurs in CreateAddressFamily.
  495. Arguments:
  496. AddrFamilyInfo - Pointer to the Rib Info Structure.
  497. Return Value:
  498. Status of the operation
  499. Locks:
  500. The InstancesLock in RtmGlobals should be held while calling
  501. this function as it removes an address family from the list
  502. of address families on the instance. This lock is typically
  503. taken in DestroyEntity, but it can also happen that the lock
  504. is acquired in RtmRegisterEntity and an error occured in the
  505. CreateAddressFamily function.
  506. --*/
  507. {
  508. PINSTANCE_INFO Instance;
  509. PSINGLE_LIST_ENTRY ListPtr;
  510. UINT i;
  511. ASSERT(AddrFamilyInfo->ObjectHeader.RefCount == 0);
  512. ASSERT(AddrFamilyInfo->NumEntities == 0);
  513. ASSERT(IsListEmpty(&AddrFamilyInfo->DeregdEntities));
  514. //
  515. // Block until timers on address family are cleaned up
  516. //
  517. if (AddrFamilyInfo->RouteTimerQueue)
  518. {
  519. DeleteTimerQueueEx(AddrFamilyInfo->RouteTimerQueue, (HANDLE) -1);
  520. }
  521. if (AddrFamilyInfo->NotifTimerQueue)
  522. {
  523. DeleteTimerQueueEx(AddrFamilyInfo->NotifTimerQueue, (HANDLE) -1);
  524. }
  525. //
  526. // Free resources allocated to the change lists (locks ..)
  527. //
  528. // No more dests in change list as all entities are gone
  529. ASSERT(AddrFamilyInfo->NumChangedDests == 0);
  530. for (i = 0; i < NUM_CHANGED_DEST_LISTS; i++)
  531. {
  532. ListPtr = &AddrFamilyInfo->ChangeLists[i].ChangedDestsHead;
  533. ASSERT(ListPtr->Next == ListPtr);
  534. ASSERT(AddrFamilyInfo->ChangeLists[i].ChangedDestsTail == ListPtr);
  535. if (AddrFamilyInfo->ChangeLists[i].ChangesLockInited)
  536. {
  537. DeleteCriticalSection
  538. (&AddrFamilyInfo->ChangeLists[i].ChangesListLock);
  539. }
  540. }
  541. //
  542. // Free the change notification info and the guarding lock
  543. //
  544. ASSERT(AddrFamilyInfo->NumChangeNotifs == 0);
  545. if (AddrFamilyInfo->ChangeNotifsDir)
  546. {
  547. FreeMemory(AddrFamilyInfo->ChangeNotifsDir);
  548. }
  549. if (AddrFamilyInfo->NotifsLockInited)
  550. {
  551. DELETE_READ_WRITE_LOCK(&AddrFamilyInfo->ChangeNotifsLock);
  552. }
  553. //
  554. // Free the lock guarding the notification timer
  555. //
  556. if (AddrFamilyInfo->TimerLockInited)
  557. {
  558. DeleteCriticalSection(&AddrFamilyInfo->NotifsTimerLock);
  559. }
  560. //
  561. // Free the route table and the route table lock
  562. //
  563. ASSERT(AddrFamilyInfo->NumRoutes == 0);
  564. //
  565. // Because some hold's are left out - this count
  566. // might not be equal to zero. Need to fix this
  567. // memory leak by cleaning up before this point
  568. //
  569. // ASSERT(AddrFamilyInfo->NumDests == 0);
  570. if (AddrFamilyInfo->RouteTable)
  571. {
  572. DestroyTable(AddrFamilyInfo->RouteTable);
  573. }
  574. if (AddrFamilyInfo->RoutesLockInited)
  575. {
  576. DELETE_READ_WRITE_LOCK(&AddrFamilyInfo->RouteTableLock);
  577. }
  578. //
  579. // Free Opaque Ptrs directory (if it is allocated)
  580. //
  581. if (AddrFamilyInfo->OpaquePtrsDir)
  582. {
  583. FreeMemory(AddrFamilyInfo->OpaquePtrsDir);
  584. }
  585. //
  586. // Remove the address family from owning instance
  587. //
  588. Instance = AddrFamilyInfo->Instance;
  589. RemoveEntryList(&AddrFamilyInfo->AFTableLE);
  590. Instance->NumAddrFamilies--;
  591. DEREFERENCE_INSTANCE(Instance, ADDR_FAMILY_REF);
  592. // Reclaim the instance if it has no addr familes
  593. if (Instance->NumAddrFamilies == 0)
  594. {
  595. DEREFERENCE_INSTANCE(Instance, CREATION_REF);
  596. }
  597. #if DBG_HDL
  598. AddrFamilyInfo->ObjectHeader.TypeSign = ADDRESS_FAMILY_FREED;
  599. #endif
  600. FreeObject(AddrFamilyInfo);
  601. return NO_ERROR;
  602. }
  603. DWORD
  604. GetEntity (
  605. IN PADDRFAM_INFO AddrFamilyInfo,
  606. IN ULONGLONG EntityId,
  607. IN BOOL ImplicitCreate,
  608. IN PRTM_ENTITY_INFO RtmEntityInfo OPTIONAL,
  609. IN BOOL ReserveOpaquePtr OPTIONAL,
  610. IN PRTM_ENTITY_EXPORT_METHODS ExportMethods OPTIONAL,
  611. IN RTM_EVENT_CALLBACK EventCallback OPTIONAL,
  612. OUT PENTITY_INFO *EntityInfo
  613. )
  614. /*++
  615. Routine Description:
  616. Searches for an entity with a certain protocol id and
  617. protocol instance. If it is not found and ImplicitCreate
  618. is TRUE, then a new entity is created and added to the
  619. table of entities on address family.
  620. Arguments:
  621. AddrFamilyInfo - Address family block that we are seaching,
  622. EntityId - Entity protocol id and protocol instance,
  623. ImplicitCreate - Create a new entity if not found or not,
  624. For all others - See corresponding parametes in CreateEntity
  625. EntityInfo - The entity info is returned in this param.
  626. Return Value:
  627. Status of the operation
  628. Locks:
  629. The InstancesLock in RtmGlobals should be held while calling
  630. this function. If ImplicitCreate is FALSE, a read lock would
  631. do, but if it is TRUE then a write lock should be held as we
  632. would need it to insert a new entity into the entities list.
  633. --*/
  634. {
  635. PLIST_ENTRY Entities;
  636. PENTITY_INFO Entity;
  637. PLIST_ENTRY r;
  638. DWORD Status;
  639. Entities = &AddrFamilyInfo->EntityTable[EntityId % ENTITY_TABLE_SIZE];
  640. #if WRN
  641. Entity = NULL;
  642. #endif
  643. do
  644. {
  645. // Search for an entity with the input Entity Id
  646. for (r = Entities->Flink; r != Entities; r = r->Flink)
  647. {
  648. Entity = CONTAINING_RECORD(r, ENTITY_INFO, EntityTableLE);
  649. if (Entity->EntityId.EntityId >= EntityId)
  650. {
  651. break;
  652. }
  653. }
  654. if ((r != Entities) && (Entity->EntityId.EntityId == EntityId))
  655. {
  656. Status = ERROR_ALREADY_EXISTS;
  657. break;
  658. }
  659. // We did not find an entity - create a new one ?
  660. if (!ImplicitCreate)
  661. {
  662. Status = ERROR_NOT_FOUND;
  663. break;
  664. }
  665. // Create a new entity with all the input RTM parameters
  666. Status = CreateEntity(AddrFamilyInfo,
  667. RtmEntityInfo,
  668. ReserveOpaquePtr,
  669. ExportMethods,
  670. EventCallback,
  671. &Entity);
  672. if (Status != NO_ERROR)
  673. {
  674. break;
  675. }
  676. //
  677. // Inform all existing entities of this new entity
  678. //
  679. InformEntitiesOfEvent(AddrFamilyInfo->EntityTable,
  680. RTM_ENTITY_REGISTERED,
  681. Entity);
  682. // Insert to keep the list sorted Entity Id Order
  683. InsertTailList(r, &Entity->EntityTableLE);
  684. *EntityInfo = Entity;
  685. }
  686. while (FALSE);
  687. return Status;
  688. }
  689. DWORD
  690. CreateEntity (
  691. IN PADDRFAM_INFO AddrFamilyInfo,
  692. IN PRTM_ENTITY_INFO EntityInfo,
  693. IN BOOL ReserveOpaquePtr,
  694. IN PRTM_ENTITY_EXPORT_METHODS ExportMethods,
  695. IN RTM_EVENT_CALLBACK EventCallback,
  696. OUT PENTITY_INFO *NewEntity
  697. )
  698. /*++
  699. Routine Description:
  700. Creates a new entity info structure and initializes it.
  701. Arguments:
  702. AddrFamilyInfo - Address Family the entity is registering with,
  703. EntityInfo - Information for the entity being created,
  704. ReserveOpaquePtr - Reserve a ptr in each destination or not,
  705. ExportMethods - List of methods exported by this entity,
  706. EventCallback - Callback invoked to inform of certain events
  707. like entity registrations, de-registrations,
  708. NewEntity - Pointer to the new Entity Info structure
  709. will be returned through this parameter.
  710. Return Value:
  711. Status of the operation
  712. --*/
  713. {
  714. PENTITY_INFO Entity;
  715. UINT NumMethods, i;
  716. DWORD Status;
  717. *NewEntity = NULL;
  718. //
  719. // Allocate and initialize a new entity info structure
  720. //
  721. NumMethods = ExportMethods ? ExportMethods->NumMethods : 0;
  722. Entity = (PENTITY_INFO) AllocNZeroObject(
  723. sizeof(ENTITY_INFO) +
  724. (NumMethods ? (NumMethods - 1) : 0 ) *
  725. sizeof(RTM_ENTITY_EXPORT_METHOD));
  726. if (Entity == NULL)
  727. {
  728. if (AddrFamilyInfo->NumEntities == 0)
  729. {
  730. DEREFERENCE_ADDR_FAMILY(AddrFamilyInfo, CREATION_REF);
  731. }
  732. return ERROR_NOT_ENOUGH_MEMORY;
  733. }
  734. do
  735. {
  736. #if DBG_HDL
  737. Entity->ObjectHeader.TypeSign = ENTITY_ALLOC;
  738. #endif
  739. INITIALIZE_ENTITY_REFERENCE(Entity, CREATION_REF);
  740. Entity->EntityId = EntityInfo->EntityId;
  741. Entity->OwningAddrFamily = AddrFamilyInfo;
  742. REFERENCE_ADDR_FAMILY(AddrFamilyInfo, ENTITY_REF);
  743. //
  744. // Linking the entity to its owning address family is
  745. // done by caller,but pretend that it is already done
  746. //
  747. AddrFamilyInfo->NumEntities++;
  748. InitializeListHead(&Entity->EntityTableLE);
  749. //
  750. // Allocate an opaque pointer index if asked for
  751. //
  752. Entity->OpaquePtrOffset = -1;
  753. if (ReserveOpaquePtr)
  754. {
  755. if (AddrFamilyInfo->NumOpaquePtrs >= AddrFamilyInfo->MaxOpaquePtrs)
  756. {
  757. Status = ERROR_NO_SYSTEM_RESOURCES;
  758. break;
  759. }
  760. for (i = 0; i < AddrFamilyInfo->MaxOpaquePtrs; i++)
  761. {
  762. if (AddrFamilyInfo->OpaquePtrsDir[i] == NULL)
  763. {
  764. break;
  765. }
  766. }
  767. AddrFamilyInfo->OpaquePtrsDir[i] = (PVOID) Entity;
  768. AddrFamilyInfo->NumOpaquePtrs++;
  769. Entity->OpaquePtrOffset = i;
  770. ASSERT(Entity->OpaquePtrOffset != -1);
  771. }
  772. //
  773. // Initialize lock guarding entity-specific route lists
  774. //
  775. try
  776. {
  777. CREATE_READ_WRITE_LOCK(&Entity->RouteListsLock);
  778. Entity->ListsLockInited = TRUE;
  779. }
  780. except(EXCEPTION_EXECUTE_HANDLER)
  781. {
  782. Status = GetLastError();
  783. break;
  784. }
  785. //
  786. // Initialize the list of open handles and corresponding lock
  787. //
  788. try
  789. {
  790. InitializeCriticalSection(&Entity->OpenHandlesLock);
  791. Entity->HandlesLockInited = TRUE;
  792. }
  793. except(EXCEPTION_EXECUTE_HANDLER)
  794. {
  795. Status = GetLastError();
  796. break;
  797. }
  798. InitializeListHead(&Entity->OpenHandles);
  799. //
  800. // Initialize the next hop table and the next hop table lock
  801. //
  802. try
  803. {
  804. CREATE_READ_WRITE_LOCK(&Entity->NextHopTableLock);
  805. Entity->NextHopsLockInited = TRUE;
  806. }
  807. except(EXCEPTION_EXECUTE_HANDLER)
  808. {
  809. Status = GetLastError();
  810. break;
  811. }
  812. Status = CreateTable(AddrFamilyInfo->AddressSize,
  813. &Entity->NextHopTable);
  814. if (Status != NO_ERROR)
  815. {
  816. break;
  817. }
  818. Entity->NumNextHops = 0;
  819. //
  820. // Initialize entity methods and the entity methods lock
  821. //
  822. try
  823. {
  824. CREATE_READ_WRITE_LOCK(&Entity->EntityMethodsLock);
  825. Entity->MethodsLockInited = TRUE;
  826. }
  827. except(EXCEPTION_EXECUTE_HANDLER)
  828. {
  829. Status = GetLastError();
  830. break;
  831. }
  832. Entity->EventCallback = EventCallback;
  833. Entity->EntityMethods.NumMethods = NumMethods;
  834. if (ExportMethods)
  835. {
  836. CopyMemory(Entity->EntityMethods.Methods,
  837. ExportMethods->Methods,
  838. NumMethods * sizeof(RTM_ENTITY_EXPORT_METHOD));
  839. }
  840. *NewEntity = Entity;
  841. return NO_ERROR;
  842. }
  843. while(FALSE);
  844. //
  845. // Something failed - undo work done and return status
  846. //
  847. DEREFERENCE_ENTITY(Entity, CREATION_REF);
  848. return Status;
  849. }
  850. DWORD
  851. DestroyEntity (
  852. IN PENTITY_INFO Entity
  853. )
  854. /*++
  855. Routine Description:
  856. Destroys an existing entity info structure. Frees
  857. all associated resources before de-allocation.
  858. This function has been written such that it can be
  859. called when an error occurs during CreateEntity.
  860. Arguments:
  861. EntityInfo - Pointer to the Entity Info Structure.
  862. Return Value:
  863. Status of the operation
  864. --*/
  865. {
  866. PADDRFAM_INFO AddrFamilyInfo;
  867. ASSERT(Entity->ObjectHeader.RefCount == 0);
  868. //
  869. // Take globals registrations lock while cleaning up
  870. //
  871. ACQUIRE_INSTANCES_WRITE_LOCK();
  872. //
  873. // Free lock used to block exported entity methods
  874. //
  875. if (Entity->MethodsLockInited)
  876. {
  877. DELETE_READ_WRITE_LOCK(&Entity->EntityMethodsLock);
  878. }
  879. //
  880. // Free the next hop table and the lock guarding it
  881. //
  882. ASSERT(Entity->NumNextHops == 0);
  883. if (Entity->NextHopTable)
  884. {
  885. DestroyTable(Entity->NextHopTable);
  886. }
  887. if (Entity->NextHopsLockInited)
  888. {
  889. DELETE_READ_WRITE_LOCK(&Entity->NextHopTableLock);
  890. }
  891. if (Entity->HandlesLockInited)
  892. {
  893. // There should not be any handles opened by entity
  894. ASSERT(IsListEmpty(&Entity->OpenHandles));
  895. DeleteCriticalSection(&Entity->OpenHandlesLock);
  896. }
  897. //
  898. // Free lock used to perform route list operations
  899. //
  900. if (Entity->ListsLockInited)
  901. {
  902. DELETE_READ_WRITE_LOCK(&Entity->RouteListsLock);
  903. }
  904. //
  905. // Free the opaque ptr index in the address family
  906. //
  907. AddrFamilyInfo = Entity->OwningAddrFamily;
  908. if (Entity->OpaquePtrOffset != -1)
  909. {
  910. AddrFamilyInfo->OpaquePtrsDir[Entity->OpaquePtrOffset] = NULL;
  911. AddrFamilyInfo->NumOpaquePtrs--;
  912. }
  913. #if DBG_REF
  914. //
  915. // Signal event on entity to unblock de-register
  916. // The evnt will be freed in RtmDeregisterEntity
  917. //
  918. if (Entity->BlockingEvent)
  919. {
  920. SetEvent(Entity->BlockingEvent);
  921. }
  922. #endif
  923. //
  924. // Remove the entity from the owning address family
  925. //
  926. RemoveEntryList(&Entity->EntityTableLE);
  927. AddrFamilyInfo->NumEntities--;
  928. DEREFERENCE_ADDR_FAMILY(AddrFamilyInfo, ENTITY_REF);
  929. // Reclaim the addr family if it has no entities
  930. if (AddrFamilyInfo->NumEntities == 0)
  931. {
  932. DEREFERENCE_ADDR_FAMILY(AddrFamilyInfo, CREATION_REF);
  933. }
  934. #if DBG_HDL
  935. Entity->ObjectHeader.TypeSign = ENTITY_FREED;
  936. #endif
  937. FreeObject(Entity);
  938. RELEASE_INSTANCES_WRITE_LOCK();
  939. return NO_ERROR;
  940. }
  941. VOID
  942. InformEntitiesOfEvent (
  943. IN PLIST_ENTRY EntityTable,
  944. IN RTM_EVENT_TYPE EventType,
  945. IN PENTITY_INFO EntityThis
  946. )
  947. /*++
  948. Routine Description:
  949. Informs all entities in the entity table that a certain
  950. event has occured - like a new entity registered, or an
  951. existing entity de-registered.
  952. Arguments:
  953. EntityTable - Pointer to the hash table of entities,
  954. EventType - Type of the event being notified about,
  955. EntityThis - Entity that caused the event to occur.
  956. Return Value:
  957. None
  958. Locks:
  959. The instances lock has to be held in either write or
  960. read mode as we are traversing the list of entities
  961. on the address family.
  962. --*/
  963. {
  964. RTM_ENTITY_HANDLE EntityHandle;
  965. PADDRFAM_INFO AddrFamInfo;
  966. RTM_ENTITY_INFO EntityInfo;
  967. PENTITY_INFO Entity;
  968. UINT i;
  969. PLIST_ENTRY Entities, q;
  970. //
  971. // Prepare arguments for the Event Callbacks in loop
  972. //
  973. AddrFamInfo = EntityThis->OwningAddrFamily;
  974. EntityInfo.RtmInstanceId = AddrFamInfo->Instance->RtmInstanceId;
  975. EntityInfo.AddressFamily = AddrFamInfo->AddressFamily;
  976. EntityInfo.EntityId = EntityThis->EntityId;
  977. EntityHandle = MAKE_HANDLE_FROM_POINTER(EntityThis);
  978. //
  979. // For each entity in table, call its event callback
  980. //
  981. for (i = 0; i < ENTITY_TABLE_SIZE; i++)
  982. {
  983. Entities = &EntityTable[i];
  984. for (q = Entities->Flink; q != Entities; q = q->Flink)
  985. {
  986. Entity = CONTAINING_RECORD(q, ENTITY_INFO, EntityTableLE);
  987. //
  988. // Inform the current entity of the event
  989. // if it has an event handler registered
  990. //
  991. if (Entity->EventCallback)
  992. {
  993. //
  994. // This callback should not call any of the registration
  995. // APIs as it might result in corrupting the entity list
  996. //
  997. Entity->EventCallback(MAKE_HANDLE_FROM_POINTER(Entity),
  998. EventType,
  999. EntityHandle,
  1000. &EntityInfo);
  1001. }
  1002. }
  1003. }
  1004. }
  1005. VOID
  1006. CleanupAfterDeregister (
  1007. IN PENTITY_INFO Entity
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. Cleans up all enums, notifications and entity lists
  1012. opened by an entity. Also deletes all nexthops and
  1013. routes owned by this entity. Assumes that the entity
  1014. is not making any other operations in parallel.
  1015. Arguments:
  1016. Entity - Pointer to the entity registration info.
  1017. Return Value:
  1018. None
  1019. --*/
  1020. {
  1021. RTM_ENTITY_HANDLE RtmRegHandle;
  1022. PADDRFAM_INFO AddrFamInfo;
  1023. PHANDLE Handles;
  1024. RTM_ENUM_HANDLE EnumHandle;
  1025. UINT NumHandles, i;
  1026. DWORD ChangeFlags;
  1027. DWORD Status;
  1028. AddrFamInfo = Entity->OwningAddrFamily;
  1029. RtmRegHandle = MAKE_HANDLE_FROM_POINTER(Entity);
  1030. #if DBG_HDL
  1031. // ACQUIRE_OPEN_HANDLES_LOCK(Entity);
  1032. while (!IsListEmpty(&Entity->OpenHandles))
  1033. {
  1034. POPEN_HEADER OpenHeader;
  1035. HANDLE OpenHandle;
  1036. PLIST_ENTRY p;
  1037. p = RemoveHeadList(&Entity->OpenHandles);
  1038. OpenHeader = CONTAINING_RECORD(p, OPEN_HEADER, HandlesLE);
  1039. OpenHandle = MAKE_HANDLE_FROM_POINTER(OpenHeader);
  1040. switch (OpenHeader->HandleType)
  1041. {
  1042. case DEST_ENUM_TYPE:
  1043. case ROUTE_ENUM_TYPE:
  1044. case NEXTHOP_ENUM_TYPE:
  1045. case LIST_ENUM_TYPE:
  1046. Status = RtmDeleteEnumHandle(RtmRegHandle, OpenHandle);
  1047. break;
  1048. case NOTIFY_TYPE:
  1049. Status = RtmDeregisterFromChangeNotification(RtmRegHandle,
  1050. OpenHandle);
  1051. break;
  1052. case ROUTE_LIST_TYPE:
  1053. Status = RtmDeleteRouteList(RtmRegHandle, OpenHandle);
  1054. break;
  1055. default:
  1056. Status = ERROR_INVALID_DATA;
  1057. }
  1058. ASSERT(Status == NO_ERROR);
  1059. }
  1060. // RELEASE_OPEN_HANDLES_LOCK(Entity);
  1061. #endif // DBG_HDL
  1062. Handles = AllocMemory(AddrFamInfo->MaxHandlesInEnum * sizeof(HANDLE));
  1063. if ( Handles == NULL )
  1064. {
  1065. return;
  1066. }
  1067. //
  1068. // Delete all routes created by this entity regn
  1069. //
  1070. Status = RtmCreateRouteEnum(RtmRegHandle,
  1071. NULL,
  1072. RTM_VIEW_MASK_ANY,
  1073. RTM_ENUM_OWN_ROUTES,
  1074. NULL,
  1075. 0,
  1076. NULL,
  1077. 0,
  1078. &EnumHandle);
  1079. while (Status == NO_ERROR)
  1080. {
  1081. NumHandles = AddrFamInfo->MaxHandlesInEnum;
  1082. Status = RtmGetEnumRoutes(RtmRegHandle,
  1083. EnumHandle,
  1084. &NumHandles,
  1085. Handles);
  1086. for (i = 0; i < NumHandles; i++)
  1087. {
  1088. Status = RtmDeleteRouteToDest(RtmRegHandle,
  1089. Handles[i],
  1090. &ChangeFlags);
  1091. ASSERT(Status == NO_ERROR);
  1092. }
  1093. }
  1094. Status = RtmDeleteEnumHandle(RtmRegHandle,
  1095. EnumHandle);
  1096. ASSERT(Status == NO_ERROR);
  1097. //
  1098. // Delete all nexthops created by this entity regn
  1099. //
  1100. Status = RtmCreateNextHopEnum(RtmRegHandle,
  1101. 0,
  1102. NULL,
  1103. &EnumHandle);
  1104. while (Status == NO_ERROR)
  1105. {
  1106. NumHandles = AddrFamInfo->MaxHandlesInEnum;
  1107. Status = RtmGetEnumNextHops(RtmRegHandle,
  1108. EnumHandle,
  1109. &NumHandles,
  1110. Handles);
  1111. for (i = 0; i < NumHandles; i++)
  1112. {
  1113. Status = RtmDeleteNextHop(RtmRegHandle,
  1114. Handles[i],
  1115. NULL);
  1116. ASSERT(Status == NO_ERROR);
  1117. }
  1118. }
  1119. Status = RtmDeleteEnumHandle(RtmRegHandle,
  1120. EnumHandle);
  1121. ASSERT(Status == NO_ERROR);
  1122. return;
  1123. }