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.

706 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. rtmnhop.c
  5. Abstract:
  6. Contains routines for managing RTM Next Hops.
  7. Author:
  8. Chaitanya Kodeboyina (chaitk) 21-Aug-1998
  9. Revision History:
  10. --*/
  11. #include "pchrtm.h"
  12. #pragma hdrstop
  13. DWORD
  14. WINAPI
  15. RtmAddNextHop (
  16. IN RTM_ENTITY_HANDLE RtmRegHandle,
  17. IN PRTM_NEXTHOP_INFO NextHopInfo,
  18. IN OUT PRTM_NEXTHOP_HANDLE NextHopHandle OPTIONAL,
  19. OUT PRTM_NEXTHOP_CHANGE_FLAGS ChangeFlags
  20. )
  21. /*++
  22. Adds or Updates a next hop entry to the entity's next-hop table.
  23. If the 'nexthop handle' argument is present, then this next-hop
  24. is updated. Otherwise a search is made for the address in the
  25. input 'nexthop info', and if a next-hop is found, it is updated.
  26. If no matching next-hop is found, the a new next-hop is added.
  27. Arguments:
  28. RtmRegHandle - RTM registration handle for calling entity,
  29. NextHopInfo - Info that corresponds to this next-hop,
  30. NextHopHandle - Handle to the next-hop to update is passed
  31. in (or NULL), and if a next-hop is created
  32. a handle to this new next-hop is returned.
  33. ChangeFlags - Flags whether this was a add or an update.
  34. Return Value:
  35. Status of the operation
  36. --*/
  37. {
  38. PRTM_NET_ADDRESS NextHopAddress;
  39. PENTITY_INFO Entity;
  40. PDEST_INFO Dest;
  41. PNEXTHOP_LIST NewHopList;
  42. PNEXTHOP_INFO NewNextHop;
  43. PNEXTHOP_INFO NextHop;
  44. LOOKUP_CONTEXT Context;
  45. PLIST_ENTRY p;
  46. DWORD Status;
  47. //
  48. // Validate incoming information before attempting an add
  49. //
  50. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  51. if (NextHopInfo->RemoteNextHop)
  52. {
  53. VALIDATE_DEST_HANDLE(NextHopInfo->RemoteNextHop, &Dest);
  54. }
  55. //
  56. // If there is a next hop handle, we can avoid a search
  57. //
  58. NextHop = NULL;
  59. if (ARGUMENT_PRESENT(NextHopHandle) && (*NextHopHandle))
  60. {
  61. VALIDATE_NEXTHOP_HANDLE(*NextHopHandle, &NextHop);
  62. // Make sure that the caller owns this nexthop
  63. if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
  64. {
  65. return ERROR_ACCESS_DENIED;
  66. }
  67. }
  68. #if WRN
  69. NewNextHop = NULL;
  70. NewHopList = NULL;
  71. #endif
  72. *ChangeFlags = 0;
  73. ACQUIRE_NHOP_TABLE_WRITE_LOCK(Entity);
  74. do
  75. {
  76. //
  77. // Search for the next hop if we don't already have one
  78. //
  79. if (NextHop == NULL)
  80. {
  81. Status = FindNextHop(Entity, NextHopInfo, &Context, &p);
  82. if (SUCCESS(Status))
  83. {
  84. // The next hop already exists in the tree
  85. NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
  86. }
  87. else
  88. {
  89. // Init new allocations in case we fail in between
  90. NewNextHop = NULL;
  91. NewHopList = NULL;
  92. //
  93. // Create a new next hop with the input information
  94. //
  95. Status = CreateNextHop(Entity, NextHopInfo, &NewNextHop);
  96. if (!SUCCESS(Status))
  97. {
  98. break;
  99. }
  100. //
  101. // Do we need to create a new list of next hops too ?
  102. //
  103. if (p == NULL)
  104. {
  105. NewHopList = AllocNZeroMemory(sizeof(NEXTHOP_LIST));
  106. if (NewHopList == NULL)
  107. {
  108. break;
  109. }
  110. InitializeListHead(&NewHopList->NextHopsList);
  111. // Insert the next-hop-list into the tree
  112. NextHopAddress = &NextHopInfo->NextHopAddress;
  113. Status = InsertIntoTable(Entity->NextHopTable,
  114. NextHopAddress->NumBits,
  115. NextHopAddress->AddrBits,
  116. &Context,
  117. &NewHopList->LookupLinkage);
  118. if (!SUCCESS(Status))
  119. {
  120. break;
  121. }
  122. p = &NewHopList->NextHopsList;
  123. }
  124. // Insert the next hop in the list and ref it
  125. InsertTailList(p, &NewNextHop->NextHopsLE);
  126. Entity->NumNextHops++;
  127. NextHop = NewNextHop;
  128. *ChangeFlags = RTM_NEXTHOP_CHANGE_NEW;
  129. }
  130. }
  131. //
  132. // If this is an update, copy necessary information
  133. //
  134. if (*ChangeFlags != RTM_NEXTHOP_CHANGE_NEW)
  135. {
  136. CopyToNextHop(Entity, NextHopInfo, NextHop);
  137. }
  138. //
  139. // Return the next hop handle if not passed in
  140. //
  141. if (ARGUMENT_PRESENT(NextHopHandle))
  142. {
  143. if (*NextHopHandle == NULL)
  144. {
  145. *NextHopHandle = MAKE_HANDLE_FROM_POINTER(NextHop);
  146. REFERENCE_NEXTHOP(NextHop, HANDLE_REF);
  147. }
  148. }
  149. Status = NO_ERROR;
  150. }
  151. while(FALSE);
  152. RELEASE_NHOP_TABLE_WRITE_LOCK(Entity);
  153. if (!SUCCESS(Status))
  154. {
  155. // Some error occured - clean up
  156. if (NewHopList)
  157. {
  158. FreeMemory(NewHopList);
  159. }
  160. if (NewNextHop)
  161. {
  162. DEREFERENCE_NEXTHOP(NewNextHop, CREATION_REF);
  163. }
  164. }
  165. return Status;
  166. }
  167. DWORD
  168. WINAPI
  169. RtmDeleteNextHop (
  170. IN RTM_ENTITY_HANDLE RtmRegHandle,
  171. IN RTM_NEXTHOP_HANDLE NextHopHandle OPTIONAL,
  172. IN PRTM_NEXTHOP_INFO NextHopInfo
  173. )
  174. /*++
  175. Routine Description:
  176. Deletes a next hop from the next-hop table. The next-hop
  177. memory remains in use until all reference counts go to 0.
  178. Arguments:
  179. RtmRegHandle - RTM registration handle for calling entity,
  180. NextHopHandle - Handle to the next-hop we want to delete,
  181. NextHopInfo - If no NextHopHandle is passed in, this is
  182. used to match the next-hop to be deleted.
  183. Return Value:
  184. Status of the operation
  185. --*/
  186. {
  187. PRTM_NET_ADDRESS NextHopAddress;
  188. PLOOKUP_LINKAGE Linkage;
  189. PENTITY_INFO Entity;
  190. PNEXTHOP_LIST HopList;
  191. PNEXTHOP_INFO NextHop;
  192. PLOOKUP_CONTEXT PContext;
  193. LOOKUP_CONTEXT Context;
  194. PLIST_ENTRY p;
  195. DWORD Status;
  196. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  197. //
  198. // If there is a next hop handle, we can avoid a search
  199. //
  200. NextHop = NULL;
  201. if (ARGUMENT_PRESENT(NextHopHandle))
  202. {
  203. VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);
  204. // Make sure that the caller owns this nexthop
  205. if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
  206. {
  207. return ERROR_ACCESS_DENIED;
  208. }
  209. }
  210. #if WRN
  211. Status = ERROR_GEN_FAILURE;
  212. #endif
  213. ACQUIRE_NHOP_TABLE_WRITE_LOCK(Entity);
  214. do
  215. {
  216. //
  217. // Search for the next hop if we don't already have one
  218. //
  219. if (NextHop == NULL)
  220. {
  221. Status = FindNextHop(Entity,
  222. NextHopInfo,
  223. &Context,
  224. &p);
  225. if (!SUCCESS(Status))
  226. {
  227. break;
  228. }
  229. PContext = &Context;
  230. NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
  231. }
  232. else
  233. {
  234. // Make sure that it has not already been deleted
  235. if (NextHop->NextHopInfo.State == RTM_NEXTHOP_STATE_DELETED)
  236. {
  237. break;
  238. }
  239. PContext = NULL;
  240. }
  241. // Get a 'possible' list entry that starts the hop list
  242. HopList = CONTAINING_RECORD(NextHop->NextHopsLE.Blink,
  243. NEXTHOP_LIST,
  244. NextHopsList);
  245. // Delete this next-hop from the nexthops list
  246. NextHop->NextHopInfo.State = RTM_NEXTHOP_STATE_DELETED;
  247. RemoveEntryList(&NextHop->NextHopsLE);
  248. // Do we have any more next hops on this list
  249. if (IsListEmpty(&HopList->NextHopsList))
  250. {
  251. // Remove the hop-list from the next hop table
  252. NextHopAddress = &NextHop->NextHopInfo.NextHopAddress;
  253. Status = DeleteFromTable(Entity->NextHopTable,
  254. NextHopAddress->NumBits,
  255. NextHopAddress->AddrBits,
  256. PContext,
  257. &Linkage);
  258. ASSERT(SUCCESS(Status) && (&HopList->LookupLinkage == Linkage));
  259. FreeMemory(HopList);
  260. }
  261. // Dereference the next-hop that was deleted
  262. Entity->NumNextHops--;
  263. DEREFERENCE_NEXTHOP(NextHop, CREATION_REF);
  264. if (ARGUMENT_PRESENT(NextHopHandle))
  265. {
  266. DEREFERENCE_NEXTHOP(NextHop, HANDLE_REF);
  267. }
  268. Status = NO_ERROR;
  269. }
  270. while (FALSE);
  271. RELEASE_NHOP_TABLE_WRITE_LOCK(Entity);
  272. return Status;
  273. }
  274. DWORD
  275. WINAPI
  276. RtmFindNextHop (
  277. IN RTM_ENTITY_HANDLE RtmRegHandle,
  278. IN PRTM_NEXTHOP_INFO NextHopInfo,
  279. OUT PRTM_NEXTHOP_HANDLE NextHopHandle,
  280. OUT PRTM_NEXTHOP_INFO *NextHopPointer OPTIONAL
  281. )
  282. /*++
  283. Routine Description:
  284. Finds a next hop, given its info, in entity's next-hop table.
  285. Arguments:
  286. RtmRegHandle - RTM registration handle for calling entity,
  287. NextHopInfo - Info for the next-hop we are searching for
  288. ( NextHopOwner, NextHopAddress, IfIndex ),
  289. NextHopHandle - Handle to next-hop is returned (if found),
  290. NextHopPointer - A pointer to the next-hop is returned for
  291. fast direct access by the next-hop's owner.
  292. Return Value:
  293. Status of the operation
  294. --*/
  295. {
  296. PENTITY_INFO Entity;
  297. PNEXTHOP_INFO NextHop;
  298. PLIST_ENTRY p;
  299. DWORD Status;
  300. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  301. VALIDATE_ENTITY_HANDLE(NextHopInfo->NextHopOwner, &Entity);
  302. if (ARGUMENT_PRESENT(NextHopPointer))
  303. {
  304. // Only the nexthop owner gets a direct ptr
  305. if (RtmRegHandle != NextHopInfo->NextHopOwner)
  306. {
  307. return ERROR_ACCESS_DENIED;
  308. }
  309. }
  310. //
  311. // Search for the next hop in the next hop table
  312. //
  313. ACQUIRE_NHOP_TABLE_READ_LOCK(Entity);
  314. Status = FindNextHop(Entity, NextHopInfo, NULL, &p);
  315. if (SUCCESS(Status))
  316. {
  317. NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
  318. *NextHopHandle = MAKE_HANDLE_FROM_POINTER(NextHop);
  319. REFERENCE_NEXTHOP(NextHop, HANDLE_REF);
  320. if (ARGUMENT_PRESENT(NextHopPointer))
  321. {
  322. *NextHopPointer = &NextHop->NextHopInfo;
  323. }
  324. }
  325. RELEASE_NHOP_TABLE_READ_LOCK(Entity);
  326. return Status;
  327. }
  328. DWORD
  329. FindNextHop (
  330. IN PENTITY_INFO Entity,
  331. IN PRTM_NEXTHOP_INFO NextHopInfo,
  332. OUT PLOOKUP_CONTEXT Context OPTIONAL,
  333. OUT PLIST_ENTRY *NextHopLE
  334. )
  335. /*++
  336. Routine Description:
  337. Finds a next hop, given its info, in entity's next-hop table.
  338. This is a helper function that is called by public functions
  339. that add, delete or find a next hop in the next hop table.
  340. Arguments:
  341. Entity - Entity whose nexthop table we are searching,
  342. NextHopInfo - Info for the next-hop we are searching for
  343. ( NextHopOwner, NextHopAddress, IfIndex ),
  344. Context - Search context for holding list of nexthops,
  345. NextHopLE - List entry for the matching nexthop (if found)
  346. (or) list entry before which it'll be inserted.
  347. Return Value:
  348. Status of the operation
  349. --*/
  350. {
  351. PRTM_NET_ADDRESS NextHopAddress;
  352. PNEXTHOP_LIST NextHopsList;
  353. PNEXTHOP_INFO NextHop;
  354. ULONG IfIndex;
  355. PLOOKUP_LINKAGE Linkage;
  356. PLIST_ENTRY NextHops, p;
  357. DWORD Status;
  358. *NextHopLE = NULL;
  359. //
  360. // Search for list of next hops, given the address
  361. //
  362. NextHopAddress = &NextHopInfo->NextHopAddress;
  363. Status = SearchInTable(Entity->NextHopTable,
  364. NextHopAddress->NumBits,
  365. NextHopAddress->AddrBits,
  366. Context,
  367. &Linkage);
  368. if (!SUCCESS(Status))
  369. {
  370. return Status;
  371. }
  372. NextHopsList = CONTAINING_RECORD(Linkage, NEXTHOP_LIST, LookupLinkage);
  373. //
  374. // Search for the nexthop with the interface idx
  375. //
  376. IfIndex = NextHopInfo->InterfaceIndex;
  377. NextHops = &NextHopsList->NextHopsList;
  378. #if WRN
  379. NextHop = NULL;
  380. #endif
  381. for (p = NextHops->Flink; p != NextHops; p = p->Flink)
  382. {
  383. NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
  384. if (NextHop->NextHopInfo.InterfaceIndex <= IfIndex)
  385. {
  386. break;
  387. }
  388. }
  389. *NextHopLE = p;
  390. if ((p == NextHops) || (NextHop->NextHopInfo.InterfaceIndex != IfIndex))
  391. {
  392. return ERROR_NOT_FOUND;
  393. }
  394. return NO_ERROR;
  395. }
  396. DWORD
  397. WINAPI
  398. RtmGetNextHopPointer (
  399. IN RTM_ENTITY_HANDLE RtmRegHandle,
  400. IN RTM_NEXTHOP_HANDLE NextHopHandle,
  401. OUT PRTM_NEXTHOP_INFO *NextHopPointer
  402. )
  403. /*++
  404. Routine Description:
  405. Gets a direct pointer to the next-hop for read/write by its owner.
  406. Arguments:
  407. RtmRegHandle - RTM registration handle for calling entity,
  408. NextHopHandle - Handle to the next-hop whose pointer we want,
  409. NextHopPointer - A pointer to the next-hop is returned for
  410. fast direct access by the caller, only if
  411. the caller is the owner of this next-hop.
  412. Return Value:
  413. Status of the operation
  414. --*/
  415. {
  416. PENTITY_INFO Entity;
  417. PNEXTHOP_INFO NextHop;
  418. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  419. VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);
  420. //
  421. // Return a pointer only if caller owns next-hop
  422. //
  423. if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
  424. {
  425. return ERROR_ACCESS_DENIED;
  426. }
  427. *NextHopPointer = &NextHop->NextHopInfo;
  428. return NO_ERROR;
  429. }
  430. DWORD
  431. WINAPI
  432. RtmLockNextHop(
  433. IN RTM_ENTITY_HANDLE RtmRegHandle,
  434. IN RTM_NEXTHOP_HANDLE NextHopHandle,
  435. IN BOOL Exclusive,
  436. IN BOOL LockNextHop,
  437. OUT PRTM_NEXTHOP_INFO *NextHopPointer OPTIONAL
  438. )
  439. /*++
  440. Routine Description:
  441. Locks or Unlocks a next hop. This function is called by the
  442. next-hop's owner to lock the next-hop before making changes
  443. directly to the next-hop using a pointer to this next-hop.
  444. Arguments:
  445. RtmRegHandle - RTM registration handle for calling entity,
  446. NextHopHandle - Handle to the next-hop that we want to lock,
  447. Exclusive - TRUE to lock in write mode, else read mode,
  448. LockNextHop - Lock nexthop if TRUE, Unlock it if FALSE,
  449. NextHopPointer - A pointer to the next-hop is returned for
  450. fast direct access by the next hop's owner.
  451. Return Value:
  452. Status of the operation
  453. --*/
  454. {
  455. PENTITY_INFO Entity;
  456. PNEXTHOP_INFO NextHop;
  457. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  458. VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);
  459. //
  460. // Lock or unlock only if caller owns next-hop
  461. //
  462. if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
  463. {
  464. return ERROR_ACCESS_DENIED;
  465. }
  466. // Return a direct pointer for use in update
  467. if (ARGUMENT_PRESENT(NextHopPointer))
  468. {
  469. *NextHopPointer = &NextHop->NextHopInfo;
  470. }
  471. // Lock or unlock the nexthop as the case may be
  472. if (LockNextHop)
  473. {
  474. if (Exclusive)
  475. {
  476. ACQUIRE_NHOP_TABLE_WRITE_LOCK(Entity);
  477. }
  478. else
  479. {
  480. ACQUIRE_NHOP_TABLE_READ_LOCK(Entity);
  481. }
  482. }
  483. else
  484. {
  485. if (Exclusive)
  486. {
  487. RELEASE_NHOP_TABLE_WRITE_LOCK(Entity);
  488. }
  489. else
  490. {
  491. RELEASE_NHOP_TABLE_READ_LOCK(Entity);
  492. }
  493. }
  494. return NO_ERROR;
  495. }