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.

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