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.

1864 lines
40 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. tcpip\ip\mcastmfe.c
  5. Abstract:
  6. A lot of the MFE code does some funky intertwined IRQL stuff. We often
  7. acquire the group lock as reader or writer at some level X
  8. We then acquire the source lock at DPC
  9. We now release the group lock (as reader or writer) from DPC
  10. Later we can release the source lock from X
  11. The crucial point to remember is that the IRQL is associated with a thread,
  12. and not with a lock
  13. Author:
  14. Amritansh Raghav
  15. Revision History:
  16. AmritanR Created
  17. Notes:
  18. --*/
  19. #include "precomp.h"
  20. #if IPMCAST
  21. #define __FILE_SIG__ MFE_SIG
  22. #include "ipmcast.h"
  23. #include "ipmcstxt.h"
  24. #include "mcastioc.h"
  25. #include "mcastmfe.h"
  26. #include "tcpipbuf.h"
  27. NTSTATUS
  28. IPMForward(
  29. PNDIS_PACKET pnpPacket,
  30. PSOURCE pSource,
  31. BOOLEAN bSendFromQueue
  32. );
  33. void
  34. FreeFWPacket(
  35. PNDIS_PACKET Packet
  36. );
  37. Interface*
  38. GetInterfaceGivenIndex(
  39. IN DWORD dwIndex
  40. )
  41. /*++
  42. Routine Description:
  43. Returns the IP stacks Interface structure for the given index.
  44. If the invalid index is given, then it returns the DummyInterface
  45. The interface's if_refcount is incremented (except for Loopback and Dummy)
  46. Locks:
  47. Acquires the route table lock
  48. Arguments:
  49. dwIndex Interface Index
  50. Return Value:
  51. Pointer to interface
  52. NULL
  53. --*/
  54. {
  55. Interface *pIpIf;
  56. CTELockHandle Handle;
  57. CTEGetLock(&RouteTableLock.Lock, &Handle);
  58. for(pIpIf = IFList; pIpIf isnot NULL; pIpIf = pIpIf->if_next)
  59. {
  60. if(pIpIf->if_index is dwIndex)
  61. {
  62. if(pIpIf->if_flags & IF_FLAGS_DELETING)
  63. {
  64. CTEFreeLock(&RouteTableLock.Lock, Handle);
  65. return NULL;
  66. }
  67. if((pIpIf isnot &LoopInterface) and
  68. (pIpIf isnot &DummyInterface))
  69. {
  70. RefMIF(pIpIf);
  71. }
  72. CTEFreeLock(&RouteTableLock.Lock, Handle);
  73. return pIpIf;
  74. }
  75. }
  76. CTEFreeLock(&RouteTableLock.Lock, Handle);
  77. if(dwIndex is INVALID_IF_INDEX)
  78. {
  79. return &DummyInterface;
  80. }
  81. return NULL;
  82. }
  83. //
  84. // MUST BE PAGED IN
  85. //
  86. #pragma alloc_text(PAGEIPMc, CreateOrUpdateMfe)
  87. NTSTATUS
  88. CreateOrUpdateMfe(
  89. IN PIPMCAST_MFE pMfe
  90. )
  91. /*++
  92. Routine Description:
  93. Inserts an MFE into the MFIB.
  94. We first validate the given MFE. Then we find the group and source, if they
  95. exist. After that, we free all the OIFs for the source, putting the new
  96. OIFS in
  97. Locks:
  98. None needed on entry. Takes the MFIB lock as WRITER
  99. Arguments:
  100. Return Value:
  101. STATUS_SUCCESS
  102. STATUS_INVALID_PARAMETER
  103. --*/
  104. {
  105. PGROUP pGroup;
  106. PSOURCE pSource;
  107. SOURCE OldSource;
  108. POUT_IF pOif, pTempOif;
  109. KIRQL kiCurrIrql;
  110. ULONG ulIndex, i;
  111. NTSTATUS nsStatus;
  112. PLIST_ENTRY pleNode;
  113. Interface *pIpIf;
  114. FWQ *pfqNode, fwqPending;
  115. BOOLEAN bError, bOldSource, bCreated;
  116. PNDIS_PACKET pnpPacket;
  117. FWContext *pFWC;
  118. TraceEnter(MFE, "CreateOrUpdateMfe");
  119. if(pMfe->ulNumOutIf)
  120. {
  121. //
  122. // Lets make sure that the incoming interface is valid
  123. //
  124. pIpIf = GetInterfaceGivenIndex(pMfe->dwInIfIndex);
  125. if(pIpIf is NULL)
  126. {
  127. Trace(MFE, ERROR,
  128. ("CreateOrUpdateMfe: Can not find incoming interface 0x%x\n",
  129. pMfe->dwInIfIndex));
  130. TraceLeave(MFE, "CreateOrUpdateMfe");
  131. return STATUS_INVALID_PARAMETER;
  132. }
  133. if((pIpIf is &LoopInterface) or
  134. (pIpIf is &DummyInterface))
  135. {
  136. //
  137. // Cant set MFEs out over the loopback or dummy interface
  138. //
  139. Trace(MFE, ERROR,
  140. ("CreateOrUpdateMfe: Incoming interface index 0x%x points to Loopback or Dummy\n",
  141. pMfe->dwInIfIndex));
  142. TraceLeave(MFE, "CreateOrUpdateMfe");
  143. return STATUS_INVALID_PARAMETER;
  144. }
  145. //
  146. // If there is only one interface then the OIF and IIF must be
  147. // different
  148. //
  149. if(pMfe->ulNumOutIf is 1)
  150. {
  151. if(pMfe->rgioOutInfo[0].dwOutIfIndex is pMfe->dwInIfIndex)
  152. {
  153. Trace(MFE, ERROR,
  154. ("CreateOrUpdateMfe: Only oif is same as iif\n"));
  155. DerefMIF(pIpIf);
  156. TraceLeave(MFE, "CreateOrUpdateMfe");
  157. return STATUS_INVALID_PARAMETER;
  158. }
  159. }
  160. }
  161. else
  162. {
  163. //
  164. // User is trying to setup a negative entry - just set in interface
  165. // to NULL
  166. //
  167. pIpIf = NULL;
  168. }
  169. //
  170. // Lock out the group bucket
  171. //
  172. ulIndex = GROUP_HASH(pMfe->dwGroup);
  173. EnterWriter(&g_rgGroupTable[ulIndex].rwlLock,
  174. &kiCurrIrql);
  175. //
  176. // If the SG entry is in INIT state, then some other thread may be
  177. // using the entry WITHOUT HOLDING THE LOCK.
  178. // This is important. The MFE is used even when it is in other states, but
  179. // the only time it is used without it being locked is when a send is
  180. // in progess and this can only happen when the entry is MFE_INIT
  181. // So since we need to change the OIF list when a send may possibly be
  182. // in progress, we delete the source if the state is init.
  183. //
  184. pSource = NULL;
  185. bOldSource = FALSE;
  186. pGroup = LookupGroup(pMfe->dwGroup);
  187. if(pGroup isnot NULL)
  188. {
  189. pSource = FindSourceGivenGroup(pGroup,
  190. pMfe->dwSource,
  191. pMfe->dwSrcMask);
  192. if(pSource isnot NULL)
  193. {
  194. if(pSource->byState is MFE_INIT)
  195. {
  196. //
  197. // Since we are going to throw away the SOURCE and create a
  198. // new one, keep a copy of the stats of the old source
  199. //
  200. RtlCopyMemory(&OldSource,
  201. pSource,
  202. sizeof(OldSource));
  203. bOldSource = TRUE;
  204. //
  205. // FindSourceGivenGroup would have already ref'ed and locked
  206. // the SOURCE so we can call RemoveSource here.
  207. //
  208. RemoveSource(pMfe->dwGroup,
  209. pMfe->dwSource,
  210. pMfe->dwSrcMask,
  211. pGroup,
  212. pSource);
  213. pSource = NULL;
  214. }
  215. }
  216. }
  217. if(pSource is NULL)
  218. {
  219. #if DBG
  220. nsStatus = FindOrCreateSource(pMfe->dwGroup,
  221. ulIndex,
  222. pMfe->dwSource,
  223. pMfe->dwSrcMask,
  224. &pSource,
  225. &bCreated);
  226. #else
  227. nsStatus = FindOrCreateSource(pMfe->dwGroup,
  228. ulIndex,
  229. pMfe->dwSource,
  230. pMfe->dwSrcMask,
  231. &pSource);
  232. #endif
  233. if(nsStatus isnot STATUS_SUCCESS)
  234. {
  235. ExitWriter(&g_rgGroupTable[ulIndex].rwlLock,
  236. kiCurrIrql);
  237. if(pIpIf isnot NULL)
  238. {
  239. DerefMIF(pIpIf);
  240. }
  241. TraceLeave(MFE, "CreateOrUpdateMfe");
  242. return nsStatus;
  243. }
  244. }
  245. //
  246. // Cant access the group without the bucket lock
  247. //
  248. pGroup = NULL;
  249. ExitWriterFromDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
  250. //
  251. // We may have got a preexisting source. Even then
  252. // we overwrite the in interface info
  253. //
  254. if(pSource->pInIpIf isnot NULL)
  255. {
  256. //
  257. // The interface is already referenced by the source, so release
  258. // the new reference acquired above.
  259. //
  260. if(pIpIf isnot NULL)
  261. {
  262. DerefIF(pIpIf);
  263. }
  264. RtAssert(pSource->pInIpIf is pIpIf);
  265. }
  266. pSource->dwInIfIndex = pMfe->dwInIfIndex;
  267. pSource->pInIpIf = pIpIf;
  268. pSource->byState = MFE_INIT;
  269. //
  270. // A new source is created with a timeout of DEFAULT_LIFETIME
  271. // We MUST override here..
  272. //
  273. pSource->llTimeOut = SECS_TO_TICKS(pMfe->ulTimeOut);
  274. //
  275. // At this point we have a valid source. We need to update the
  276. // OIFs to the given MFE. The problem here is that the only easy
  277. // way to do this (without sorting etc) is two O(n^2) loops
  278. // So we go through and free all the OIFs - this is not
  279. // expensive because freeing will only send them to the Lookaside
  280. // list. Then we create the new OIFS all over again
  281. //
  282. pOif = pSource->pFirstOutIf;
  283. while(pOif)
  284. {
  285. //
  286. // Dereference IP's i/f
  287. //
  288. RtAssert(pOif->pIpIf);
  289. DerefMIF(pOif->pIpIf);
  290. pTempOif = pOif->pNextOutIf;
  291. ExFreeToNPagedLookasideList(&g_llOifBlocks,
  292. pOif);
  293. pOif = pTempOif;
  294. }
  295. //
  296. // So now we have a source with no OIFS
  297. //
  298. bError = FALSE;
  299. for(i = 0; i < pMfe->ulNumOutIf; i++)
  300. {
  301. //
  302. // recreate the OIFS
  303. //
  304. //
  305. // First get a pointer to IPs interface for the
  306. // given interface index
  307. //
  308. #if DBG
  309. if(pMfe->rgioOutInfo[i].dwOutIfIndex is INVALID_IF_INDEX)
  310. {
  311. //
  312. // For demand dial OIFs, the context must be valid
  313. //
  314. RtAssert(pMfe->rgioOutInfo[i].dwOutIfIndex isnot INVALID_DIAL_CONTEXT);
  315. }
  316. #endif
  317. //
  318. // Else we must be able to get an index, and it should not be
  319. // the loopback interface
  320. //
  321. pIpIf = GetInterfaceGivenIndex(pMfe->rgioOutInfo[i].dwOutIfIndex);
  322. if((pIpIf is NULL) or
  323. (pIpIf is (Interface *)&LoopInterface))
  324. {
  325. Trace(MFE, ERROR,
  326. ("CreateOrUpdateMfe: Can not find outgoing interface 0x%x\n",
  327. pMfe->rgioOutInfo[i].dwOutIfIndex));
  328. bError = TRUE;
  329. break;
  330. }
  331. pOif = ExAllocateFromNPagedLookasideList(&g_llOifBlocks);
  332. if(pOif is NULL)
  333. {
  334. DerefMIF(pIpIf);
  335. bError = TRUE;
  336. break;
  337. }
  338. pOif->pNextOutIf = pSource->pFirstOutIf;
  339. pOif->pIpIf = pIpIf;
  340. pOif->dwIfIndex = pMfe->rgioOutInfo[i].dwOutIfIndex;
  341. pOif->dwNextHopAddr = pMfe->rgioOutInfo[i].dwNextHopAddr;
  342. pOif->dwDialContext = pMfe->rgioOutInfo[i].dwDialContext;
  343. //
  344. // Initialize the statistics
  345. //
  346. pOif->ulTtlTooLow = 0;
  347. pOif->ulFragNeeded = 0;
  348. pOif->ulOutPackets = 0;
  349. pOif->ulOutDiscards = 0;
  350. pSource->pFirstOutIf = pOif;
  351. }
  352. pSource->ulNumOutIf = pMfe->ulNumOutIf;
  353. //
  354. // If there was any error, we remove the source so that there is
  355. // no inconsistency between what MGM has and what we have.
  356. // Note that from here on, we will call RemoveSource to do the cleanup
  357. // so we dont need to deref IP's interfaces
  358. // Note that the reason to do all this jumping through hoops is because
  359. // we let go of the group bucket lock. We do that because the create
  360. // oif loop can be time consuming on really big boxes. Sometimes I wonder
  361. // if it is better to take the perf hit instead of doing the code
  362. // gymnastics below
  363. //
  364. if(bError)
  365. {
  366. PSOURCE pTempSource;
  367. //
  368. // Undo everything. We need to call RemoveSource(). However, that
  369. // requires us to hold the bucket lock. Which means we need to let
  370. // go of the source's lock. Once we let go of the source lock
  371. // someone else can call RemoveSource() on it. Ofcourse since we
  372. // have references to it (either from FindSource or from FindOrCreate)
  373. // the pSource is going to be around, it just may not be the one
  374. // hanging off the group. So this gives us three cases
  375. //
  376. RtReleaseSpinLock(&(pSource->mlLock), kiCurrIrql);
  377. EnterWriter(&g_rgGroupTable[ulIndex].rwlLock,
  378. &kiCurrIrql);
  379. pGroup = LookupGroup(pMfe->dwGroup);
  380. if(pGroup isnot NULL)
  381. {
  382. pTempSource = FindSourceGivenGroup(pGroup,
  383. pMfe->dwSource,
  384. pMfe->dwSrcMask);
  385. if(pTempSource is pSource)
  386. {
  387. //
  388. // CASE 1:
  389. // The pSource we have is the one in the hash table.
  390. // So we need to RemoveSource to get it out of the table
  391. // Since the pSource is referenced we can simply call
  392. // RemoveSource. However we also have an alias to
  393. // it via pTempSource which would have put an additional
  394. // reference on it
  395. //
  396. DereferenceSource(pTempSource);
  397. RemoveSource(pMfe->dwGroup,
  398. pMfe->dwSource,
  399. pMfe->dwSrcMask,
  400. pGroup,
  401. pSource);
  402. }
  403. else
  404. {
  405. //
  406. // CASE 2:
  407. // So the source changed. This means someone already
  408. // called RemoveSource on this. So just deref it.
  409. //
  410. DereferenceSource(pSource);
  411. //
  412. // Remove the ref on the different source too
  413. //
  414. DereferenceSource(pTempSource);
  415. }
  416. }
  417. else
  418. {
  419. //
  420. // CASE 3:
  421. // This can only happen when someone calls RemoveSource on the
  422. // pSource, the sourcecount for the group goes to 0, the group
  423. // is deleted and we are left with a zombie source
  424. // Just deref the source to remove the memory
  425. //
  426. DereferenceSource(pSource);
  427. }
  428. ExitWriter(&g_rgGroupTable[ulIndex].rwlLock,
  429. kiCurrIrql);
  430. TraceLeave(MFE, "CreateOrUpdateMfe");
  431. return STATUS_INVALID_PARAMETER;
  432. }
  433. //
  434. // Maybe there were no MFEs, in which case this is a negative entry
  435. //
  436. if(pMfe->ulNumOutIf is 0)
  437. {
  438. pSource->byState = MFE_NEGATIVE;
  439. }
  440. if(bOldSource)
  441. {
  442. //
  443. // Save a copy of the old statistics
  444. //
  445. pSource->ulInPkts = OldSource.ulInPkts;
  446. pSource->ulInOctets = OldSource.ulInOctets;
  447. pSource->ulPktsDifferentIf = OldSource.ulPktsDifferentIf;
  448. pSource->ulQueueOverflow = OldSource.ulQueueOverflow;
  449. pSource->ulUninitMfe = OldSource.ulUninitMfe;
  450. pSource->ulNegativeMfe = OldSource.ulNegativeMfe;
  451. pSource->ulInDiscards = OldSource.ulInDiscards;
  452. pSource->ulInHdrErrors = OldSource.ulInHdrErrors;
  453. pSource->ulTotalOutPackets = OldSource.ulTotalOutPackets;
  454. }
  455. //
  456. // Time stamp it so that the source doesnt go away under us
  457. //
  458. UpdateActivityTime(pSource);
  459. //
  460. // Ok we are done
  461. //
  462. //
  463. // Are there any packets queued up?
  464. // Send them now. We should put them on some deferred
  465. // procedure, maybe?
  466. //
  467. InitializeFwq(&fwqPending);
  468. if(!IsFwqEmpty(&(pSource->fwqPending)))
  469. {
  470. RtAssert(pSource->ulNumPending);
  471. //
  472. // Copy out the queue
  473. //
  474. CopyFwq(&fwqPending,
  475. &(pSource->fwqPending));
  476. }
  477. InitializeFwq(&(pSource->fwqPending));
  478. pSource->ulNumPending = 0;
  479. while(!IsFwqEmpty(&fwqPending))
  480. {
  481. pfqNode = RemoveHeadFwq(&fwqPending);
  482. pFWC = CONTAINING_RECORD(pfqNode,
  483. FWContext,
  484. fc_q);
  485. pnpPacket = CONTAINING_RECORD(pFWC,
  486. NDIS_PACKET,
  487. ProtocolReserved);
  488. //
  489. // If we have just set the SG entry to NEGATIVE, the IPMForward
  490. // code will throw it out
  491. //
  492. //
  493. // Ref the source once for each send, because IPMForward will deref
  494. // it
  495. //
  496. ReferenceSource(pSource);
  497. //
  498. // IPMForward will not do an RPF check, and when we queued the
  499. // packets we didnt have the IIF so we didnt do an RPF check.
  500. // Thus queued packets dont have an RPF check done on them and can
  501. // be duplicated
  502. //
  503. IPMForward(pnpPacket,
  504. pSource,
  505. TRUE);
  506. //
  507. // IPMForward would have released the spinlock, so acquire it again
  508. //
  509. RtAcquireSpinLockAtDpcLevel(&(pSource->mlLock));
  510. }
  511. RtReleaseSpinLock(&(pSource->mlLock), kiCurrIrql);
  512. //
  513. // Deref the source - creating one would have put TWO ref's on it so
  514. // we can deref it once
  515. //
  516. DereferenceSource(pSource);
  517. TraceLeave(MFE, "CreateOrUpdateMfe");
  518. return STATUS_SUCCESS;
  519. }
  520. //
  521. // MUST BE PAGED IN
  522. //
  523. #pragma alloc_text(PAGEIPMc, LookupGroup)
  524. PGROUP
  525. LookupGroup(
  526. IN DWORD dwGroupAddr
  527. )
  528. /*++
  529. Routine Description:
  530. Returns a pointer to the group structure for the current group
  531. Locks:
  532. Lock for the group's hash bucket must be taken atleast as reader
  533. Arguments:
  534. dwGroupAddr Class D IP Address of group
  535. Return Value:
  536. Valid pointer to the GROUP structure
  537. NULL
  538. --*/
  539. {
  540. ULONG ulIndex;
  541. PGROUP pGroup;
  542. PLIST_ENTRY pleNode;
  543. ulIndex = GROUP_HASH(dwGroupAddr);
  544. //
  545. // Just walk down the appropriate bucket looking for
  546. // the group in question
  547. //
  548. for(pleNode = g_rgGroupTable[ulIndex].leHashHead.Flink;
  549. pleNode isnot &(g_rgGroupTable[ulIndex].leHashHead);
  550. pleNode = pleNode->Flink)
  551. {
  552. pGroup = CONTAINING_RECORD(pleNode, GROUP, leHashLink);
  553. if(pGroup->dwGroup is dwGroupAddr)
  554. {
  555. //
  556. // Found? Good, return it
  557. //
  558. return pGroup;
  559. }
  560. }
  561. //
  562. // Not found - return NULL
  563. //
  564. return NULL;
  565. }
  566. //
  567. // MUST BE PAGED IN
  568. //
  569. #pragma alloc_text(PAGEIPMc, FindSourceGivenGroup)
  570. PSOURCE
  571. FindSourceGivenGroup(
  572. IN PGROUP pGroup,
  573. IN DWORD dwSource,
  574. IN DWORD dwSrcMask
  575. )
  576. /*++
  577. Routine Description:
  578. Traverses the list of sources transmitting on a group and returns a matchin
  579. SOURCE structure.
  580. If a source is found, it is Referenced and Locked
  581. Otherwise, NULL is returned
  582. Since the code only runs at DPC, the lock is acquired at DPCLevel
  583. Locks:
  584. The lock for the group's hash bucket must be held atleast as READER -
  585. implying that the code can ONLY be run at DPCLevel
  586. Arguments:
  587. Return Value:
  588. Valid pointer to a SOURCE
  589. NULL
  590. --*/
  591. {
  592. PLIST_ENTRY pleNode;
  593. PSOURCE pSource;
  594. for(pleNode = pGroup->leSrcHead.Flink;
  595. pleNode isnot &pGroup->leSrcHead;
  596. pleNode = pleNode->Flink)
  597. {
  598. pSource = CONTAINING_RECORD(pleNode, SOURCE, leGroupLink);
  599. if(pSource->dwSource is dwSource)
  600. {
  601. //
  602. // ignore the SrcMask match for now
  603. //
  604. ReferenceSource(pSource);
  605. RtAcquireSpinLockAtDpcLevel(&(pSource->mlLock));
  606. return pSource;
  607. }
  608. }
  609. return NULL;
  610. }
  611. //
  612. // MUST BE PAGED IN
  613. //
  614. #pragma alloc_text(PAGEIPMc, FindSGEntry)
  615. PSOURCE
  616. FindSGEntry(
  617. IN DWORD dwSrc,
  618. IN DWORD dwGroup
  619. )
  620. /*++
  621. Routine Description:
  622. Main lookup routine. We try for a quick cache lookup, if we
  623. succeed, return that. Otherwise lookup the group and from
  624. that the source
  625. Since this calls FindSourceGivenGroup(), the returned source is
  626. Referenced and Locked
  627. Locks:
  628. Takes the lock for the group's hash bucket as reader
  629. This routine must be called from DPCLevel itself
  630. Arguments:
  631. Return Value:
  632. Valid pointer to a SOURCE
  633. NULL
  634. --*/
  635. {
  636. PGROUP pGroup;
  637. ULONG ulIndex;
  638. PSOURCE pSource;
  639. //
  640. // Lock out the group bucket
  641. //
  642. ulIndex = GROUP_HASH(dwGroup);
  643. EnterReaderAtDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
  644. pGroup = NULL;
  645. if(g_rgGroupTable[ulIndex].pGroup isnot NULL)
  646. {
  647. if(g_rgGroupTable[ulIndex].pGroup->dwGroup is dwGroup)
  648. {
  649. pGroup = g_rgGroupTable[ulIndex].pGroup;
  650. #if DBG
  651. g_rgGroupTable[ulIndex].ulCacheHits++;
  652. #endif
  653. }
  654. }
  655. if(pGroup is NULL)
  656. {
  657. #if DBG
  658. g_rgGroupTable[ulIndex].ulCacheMisses++;
  659. #endif
  660. pGroup = LookupGroup(dwGroup);
  661. }
  662. if(pGroup is NULL)
  663. {
  664. ExitReaderFromDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
  665. return NULL;
  666. }
  667. //
  668. // Prime the cache
  669. //
  670. g_rgGroupTable[ulIndex].pGroup = pGroup;
  671. pSource = FindSourceGivenGroup(pGroup,
  672. dwSrc,
  673. 0);
  674. ExitReaderFromDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
  675. return pSource;
  676. }
  677. //
  678. // MUST BE PAGED IN
  679. //
  680. #pragma alloc_text(PAGEIPMc, FindOrCreateSource)
  681. #if DBG
  682. NTSTATUS
  683. FindOrCreateSource(
  684. IN DWORD dwGroup,
  685. IN DWORD dwGroupIndex,
  686. IN DWORD dwSource,
  687. IN DWORD dwSrcMask,
  688. OUT SOURCE **ppRetSource,
  689. OUT BOOLEAN *pbCreated
  690. )
  691. #else
  692. NTSTATUS
  693. FindOrCreateSource(
  694. IN DWORD dwGroup,
  695. IN DWORD dwGroupIndex,
  696. IN DWORD dwSource,
  697. IN DWORD dwSrcMask,
  698. OUT SOURCE **ppRetSource
  699. )
  700. #endif
  701. /*++
  702. Routine Description:
  703. Given a group,source and source mask, it finds the PSOURCE or
  704. creates one.
  705. The PSOURCE returned is refcounted and locked. Since the routine ONLY
  706. runs at DPC, the SOURCE lock is acquired at DPCLevel
  707. Locks:
  708. Called with the group hash bucket lock held as writer
  709. Arguments:
  710. dwGroup The class D address of the group
  711. dwGroupIndex The index into the hash table for this
  712. group
  713. dwSource The address of the source
  714. dwSrcMask The source mask - UNUSED currently
  715. **ppRetSource pointer to where pointer to source is returned
  716. Return Value:
  717. STATUS_SUCCESS
  718. STATUS_NO_MEMORY
  719. --*/
  720. {
  721. PGROUP pGroup;
  722. PSOURCE pSource;
  723. TraceEnter(MFE, "FindOrCreateSource");
  724. *ppRetSource = NULL;
  725. #if DBG
  726. *pbCreated = FALSE;
  727. #endif
  728. //
  729. // Find the group, if it exists
  730. //
  731. pGroup = LookupGroup(dwGroup);
  732. if(pGroup is NULL)
  733. {
  734. Trace(MFE, INFO,
  735. ("FindOrCreateSource: Group %d.%d.%d.%d not found\n",
  736. PRINT_IPADDR(dwGroup)));
  737. //
  738. // Group was not present, create one
  739. //
  740. pGroup = ExAllocateFromNPagedLookasideList(&g_llGroupBlocks);
  741. if(pGroup is NULL)
  742. {
  743. Trace(MFE, ERROR,
  744. ("FindOrCreateSource: Unable to alloc memory for group\n"));
  745. TraceLeave(MFE, "FindOrCreateSource");
  746. return STATUS_NO_MEMORY;
  747. }
  748. //
  749. // Initialize it
  750. //
  751. pGroup->dwGroup = dwGroup;
  752. pGroup->ulNumSources = 0;
  753. InitializeListHead(&(pGroup->leSrcHead));
  754. //
  755. // Insert the group into the hash table
  756. //
  757. InsertHeadList(&(g_rgGroupTable[dwGroupIndex].leHashHead),
  758. &(pGroup->leHashLink));
  759. #if DBG
  760. g_rgGroupTable[dwGroupIndex].ulGroupCount++;
  761. #endif
  762. }
  763. //
  764. // We have either created a group, or we already had a group
  765. // This is common code that finds the existing source entry if any
  766. //
  767. pSource = FindSourceGivenGroup(pGroup,
  768. dwSource,
  769. dwSrcMask);
  770. if(pSource is NULL)
  771. {
  772. Trace(MFE, INFO,
  773. ("FindOrCreateSource: Src %d.%d.%d.%d (%d.%d.%d.%d) not found\n",
  774. PRINT_IPADDR(dwSource),
  775. PRINT_IPADDR(dwSrcMask)));
  776. //
  777. // Source was not found, create it
  778. //
  779. pSource = ExAllocateFromNPagedLookasideList(&g_llSourceBlocks);
  780. if(pSource is NULL)
  781. {
  782. Trace(MFE, ERROR,
  783. ("FindOrCreateSource: Unable to alloc memory for source\n"));
  784. //
  785. // We dont free up the group even if we had just created it
  786. //
  787. TraceLeave(MFE, "FindOrCreateSource");
  788. return STATUS_NO_MEMORY;
  789. }
  790. #if DBG
  791. *pbCreated = TRUE;
  792. #endif
  793. //
  794. // Initialize it
  795. //
  796. RtlZeroMemory(pSource,
  797. sizeof(*pSource));
  798. pSource->dwSource = dwSource;
  799. pSource->dwSrcMask = dwSrcMask;
  800. //
  801. // Set up the create time and by default we set the time out
  802. // DEFAULT_LIFETIME
  803. //
  804. KeQueryTickCount((PLARGE_INTEGER)&(((pSource)->llCreateTime)));
  805. pSource->llTimeOut = SECS_TO_TICKS(DEFAULT_LIFETIME);
  806. pSource->byState = MFE_UNINIT;
  807. //
  808. // Make sure the queues and the locks are initialized
  809. //
  810. InitializeFwq(&(pSource->fwqPending));
  811. RtInitializeSpinLock(&(pSource->mlLock));
  812. //
  813. // Set Refcount to 2 --> one reference for the fact that a pointer
  814. // to the source lies on the group list, and another reference
  815. // because the caller will dereference it after she is done calling
  816. // this function
  817. //
  818. InitRefCount(pSource);
  819. //
  820. // Since the group lock is held, we are at DPC
  821. //
  822. RtAcquireSpinLockAtDpcLevel(&(pSource->mlLock));
  823. //
  824. // If the group was created, then ulNumSources should be 0
  825. // and if it was already present then the ulNumSources is
  826. // the number of current sources. Either way, increment
  827. // the field
  828. //
  829. pGroup->ulNumSources++;
  830. InsertTailList(&(pGroup->leSrcHead),
  831. &(pSource->leGroupLink));
  832. }
  833. *ppRetSource = pSource;
  834. TraceLeave(MFE, "FindOrCreateSource");
  835. return STATUS_SUCCESS;
  836. }
  837. //
  838. // MUST BE PAGED IN
  839. //
  840. #pragma alloc_text(PAGEIPMc, CreateSourceAndQueuePacket)
  841. NTSTATUS
  842. CreateSourceAndQueuePacket(
  843. IN DWORD dwGroup,
  844. IN DWORD dwSource,
  845. IN DWORD dwRcvIfIndex,
  846. IN LinkEntry *pLink,
  847. IN PNDIS_PACKET pnpPacket
  848. )
  849. /*++
  850. Routine Description:
  851. Called when the lookup routine fails. We need
  852. to create a queuing MFE and finish and IRP to user
  853. mode.
  854. Locks:
  855. Called with the lock for the group bucket held as writer
  856. Arguments:
  857. Return Value:
  858. STATUS_SUCCESS
  859. or result from FindOrCreateSource()
  860. --*/
  861. {
  862. ULONG ulIndex, ulCopyLen, ulLeft;
  863. PSOURCE pSource;
  864. KIRQL kiCurrIrql;
  865. PVOID pvCopy, pvData;
  866. UINT uiFirstBufLen=0;
  867. NTSTATUS nsStatus;
  868. FWContext *pFWC;
  869. IPHeader *pHeader;
  870. BOOLEAN bCreated;
  871. PNDIS_BUFFER pnbDataBuffer;
  872. PNOTIFICATION_MSG pMsg;
  873. TraceEnter(FWD, "CreateSourceAndQueuePacket");
  874. Trace(FWD, INFO,
  875. ("Creating source for %d.%d.%d.%d %d.%d.%d.%d\n",
  876. PRINT_IPADDR(dwSource),
  877. PRINT_IPADDR(dwGroup)));
  878. ulIndex = GROUP_HASH(dwGroup);
  879. EnterWriter(&g_rgGroupTable[ulIndex].rwlLock,
  880. &kiCurrIrql);
  881. #if DBG
  882. nsStatus = FindOrCreateSource(dwGroup,
  883. ulIndex,
  884. dwSource,
  885. 0xFFFFFFFF,
  886. &pSource,
  887. &bCreated);
  888. #else
  889. nsStatus = FindOrCreateSource(dwGroup,
  890. ulIndex,
  891. dwSource,
  892. 0xFFFFFFFF,
  893. &pSource);
  894. #endif
  895. if(nsStatus isnot STATUS_SUCCESS)
  896. {
  897. Trace(FWD, ERROR,
  898. ("CreateSourceAndQueuePacket: Error %x creating source\n",
  899. nsStatus));
  900. ExitWriter(&g_rgGroupTable[ulIndex].rwlLock,
  901. kiCurrIrql);
  902. TraceLeave(FWD, "CreateSourceAndQueuePacket");
  903. return nsStatus;
  904. }
  905. //
  906. // The intertwined IRQL stuff
  907. //
  908. ExitWriterFromDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
  909. //
  910. // Just set the state to QUEUE
  911. //
  912. #if DBG
  913. if(!bCreated)
  914. {
  915. RtAssert(pSource->byState is MFE_QUEUE);
  916. }
  917. #endif
  918. pSource->byState = MFE_QUEUE;
  919. pMsg = ExAllocateFromNPagedLookasideList(&g_llMsgBlocks);
  920. if(!pMsg)
  921. {
  922. RtReleaseSpinLock(&(pSource->mlLock), kiCurrIrql);
  923. DereferenceSource(pSource);
  924. Trace(FWD, ERROR,
  925. ("CreateSourceAndQueuePacket: Could not create msg\n"));
  926. TraceLeave(FWD, "CreateSourceAndQueuePacket");
  927. return STATUS_NO_MEMORY;
  928. }
  929. pMsg->inMessage.dwEvent = IPMCAST_RCV_PKT_MSG;
  930. pMsg->inMessage.ipmPkt.dwInIfIndex = dwRcvIfIndex;
  931. pMsg->inMessage.ipmPkt.dwInNextHopAddress =
  932. pLink ? pLink->link_NextHop : 0;
  933. //
  934. // First lets copy out the header
  935. //
  936. pFWC = (FWContext *)pnpPacket->ProtocolReserved;
  937. pHeader = pFWC->fc_hbuff;
  938. ulLeft = PKT_COPY_SIZE;
  939. pvCopy = pMsg->inMessage.ipmPkt.rgbyData;
  940. RtlCopyMemory(pvCopy,
  941. pHeader,
  942. sizeof(IPHeader));
  943. ulLeft -= sizeof(IPHeader);
  944. pvCopy = (PVOID)((PBYTE)pvCopy + sizeof(IPHeader));
  945. if(pFWC->fc_options)
  946. {
  947. //
  948. // Ok, lets copy out the options
  949. //
  950. RtlCopyMemory(pvCopy,
  951. pFWC->fc_options,
  952. pFWC->fc_optlength);
  953. ulLeft -= pFWC->fc_optlength;
  954. pvCopy = (PVOID)((PBYTE)pvCopy + pFWC->fc_optlength);
  955. }
  956. //
  957. // We will copy out the first buffer, or whatever space is left,
  958. // whichever is smaller
  959. //
  960. pnbDataBuffer = pFWC->fc_buffhead;
  961. if (pnbDataBuffer) {
  962. TcpipQueryBuffer(pnbDataBuffer,
  963. &pvData,
  964. &uiFirstBufLen,
  965. NormalPagePriority);
  966. if(pvData is NULL)
  967. {
  968. RtReleaseSpinLock(&(pSource->mlLock), kiCurrIrql);
  969. DereferenceSource(pSource);
  970. Trace(FWD, ERROR,
  971. ("CreateSourceAndQueuePacket: Could query data buffer.\n"));
  972. TraceLeave(FWD, "CreateSourceAndQueuePacket");
  973. return STATUS_NO_MEMORY;
  974. }
  975. }
  976. ulCopyLen = MIN(ulLeft, uiFirstBufLen);
  977. //
  978. // The length of the data copied
  979. //
  980. pMsg->inMessage.ipmPkt.cbyDataLen = (ULONG)
  981. (((ULONG_PTR)pvCopy + ulCopyLen) - (ULONG_PTR)(pMsg->inMessage.ipmPkt.rgbyData));
  982. RtlCopyMemory(pvCopy,
  983. pvData,
  984. ulCopyLen);
  985. //
  986. // Queue the packet to the tail.
  987. // Why O Why did Henry not use LIST_ENTRY?
  988. //
  989. #if DBG
  990. if(bCreated)
  991. {
  992. RtAssert(pSource->ulNumPending is 0);
  993. }
  994. #endif
  995. pSource->ulNumPending++;
  996. InsertTailFwq(&(pSource->fwqPending),
  997. &(pFWC->fc_q));
  998. UpdateActivityTime(pSource);
  999. RtReleaseSpinLock(&(pSource->mlLock), kiCurrIrql);
  1000. DereferenceSource(pSource);
  1001. CompleteNotificationIrp(pMsg);
  1002. TraceLeave(FWD, "CreateSourceAndQueuePacket");
  1003. return STATUS_SUCCESS;
  1004. }
  1005. NTSTATUS
  1006. SendWrongIfUpcall(
  1007. IN Interface *pIf,
  1008. IN LinkEntry *pLink,
  1009. IN IPHeader UNALIGNED *pHeader,
  1010. IN ULONG ulHdrLen,
  1011. IN PVOID pvOptions,
  1012. IN ULONG ulOptLen,
  1013. IN PVOID pvData,
  1014. IN ULONG ulDataLen
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. Called when we need to send a wrong i/f upcall to the router manager
  1019. Locks:
  1020. None needed. Actually, thats not quite true. The interface needs
  1021. to be locked, but then this is IP we are talking about.
  1022. Arguments:
  1023. pIf
  1024. pLink
  1025. pHeader
  1026. ulHdrLen
  1027. pvOptions
  1028. ulOptLen
  1029. pvData
  1030. ulDataLen
  1031. Return Value:
  1032. STATUS_SUCCESS
  1033. STATUS_NO_MEMORY
  1034. --*/
  1035. {
  1036. PVOID pvCopy;
  1037. ULONG ulLeft, ulCopyLen;
  1038. PNOTIFICATION_MSG pMsg;
  1039. KeQueryTickCount((PLARGE_INTEGER)&((pIf->if_lastupcall)));
  1040. pMsg = ExAllocateFromNPagedLookasideList(&g_llMsgBlocks);
  1041. if(!pMsg)
  1042. {
  1043. Trace(FWD, ERROR,
  1044. ("SendWrongIfUpcall: Could not create msg\n"));
  1045. TraceLeave(FWD, "SendWrongIfUpcall");
  1046. return STATUS_NO_MEMORY;
  1047. }
  1048. pMsg->inMessage.dwEvent = IPMCAST_WRONG_IF_MSG;
  1049. pMsg->inMessage.ipmPkt.dwInIfIndex = pIf->if_index;
  1050. pMsg->inMessage.ipmPkt.dwInNextHopAddress =
  1051. pLink ? pLink->link_NextHop : 0;
  1052. ulLeft = PKT_COPY_SIZE;
  1053. pvCopy = pMsg->inMessage.ipmPkt.rgbyData;
  1054. RtlCopyMemory(pvCopy,
  1055. pHeader,
  1056. ulHdrLen);
  1057. ulLeft -= ulHdrLen;
  1058. pvCopy = (PVOID)((ULONG_PTR)pvCopy + ulHdrLen);
  1059. if(pvOptions)
  1060. {
  1061. RtAssert(ulOptLen);
  1062. //
  1063. // Ok, lets copy out the options
  1064. //
  1065. RtlCopyMemory(pvCopy,
  1066. pvOptions,
  1067. ulOptLen);
  1068. ulLeft -= ulOptLen;
  1069. pvCopy = (PVOID)((ULONG_PTR)pvCopy + ulOptLen);
  1070. }
  1071. ulCopyLen = MIN(ulLeft, ulDataLen);
  1072. RtlCopyMemory(pvCopy,
  1073. pvData,
  1074. ulCopyLen);
  1075. //
  1076. // The length of the data copied
  1077. //
  1078. pMsg->inMessage.ipmPkt.cbyDataLen = (ULONG)
  1079. (((ULONG_PTR)pvCopy + ulCopyLen) - (ULONG_PTR)(pMsg->inMessage.ipmPkt.rgbyData));
  1080. CompleteNotificationIrp(pMsg);
  1081. TraceLeave(FWD, "SendWrongIfUpcall");
  1082. return STATUS_SUCCESS;
  1083. }
  1084. //
  1085. // MUST BE PAGED IN
  1086. //
  1087. #pragma alloc_text(PAGEIPMc, QueuePacketToSource)
  1088. NTSTATUS
  1089. QueuePacketToSource(
  1090. IN PSOURCE pSource,
  1091. IN PNDIS_PACKET pnpPacket
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. Queues an FWPacket to the source.
  1096. If the queue length would go over the limit, the packet is
  1097. not queued.
  1098. Locks:
  1099. The source must be Referenced and Locked
  1100. Arguments:
  1101. pSource Pointer to SOURCE to which packet needs to be queued
  1102. pnpPacket Pointer to NDIS_PACKET (must be an FWPacket) to queue
  1103. Return Value:
  1104. STATUS_PENDING
  1105. STATUS_INSUFFICIENT_RESOURCES
  1106. --*/
  1107. {
  1108. FWContext *pFWC;
  1109. KIRQL kiIrql;
  1110. pFWC = (FWContext *)pnpPacket->ProtocolReserved;
  1111. RtAssert(pFWC->fc_buffhead is pnpPacket->Private.Head);
  1112. if(pSource->ulNumPending >= MAX_PENDING)
  1113. {
  1114. pSource->ulQueueOverflow++;
  1115. return STATUS_INSUFFICIENT_RESOURCES;
  1116. }
  1117. pSource->ulNumPending++;
  1118. InsertTailFwq(&(pSource->fwqPending),
  1119. &(pFWC->fc_q));
  1120. return STATUS_PENDING;
  1121. }
  1122. //
  1123. // MUST BE PAGED IN
  1124. //
  1125. #pragma alloc_text(PAGEIPMc, DeleteSource)
  1126. VOID
  1127. DeleteSource(
  1128. IN PSOURCE pSource
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. Deletes all resource associated with a SOURCE
  1133. It is only called from DereferenceSource() when the
  1134. refcount goes to 0
  1135. Locks:
  1136. Can be called with our without the group lock held
  1137. The SOURCE itself is not locked
  1138. When this routine is called, exclusive access to the SOURCE is
  1139. guaranteed, so no locks need to be taken
  1140. Arguments:
  1141. pSource Pointer to SOURCE to be freed
  1142. Return Value:
  1143. None
  1144. --*/
  1145. {
  1146. POUT_IF pOutIf, pTempIf;
  1147. FWQ *pfqNode;
  1148. FWContext *pFWC;
  1149. PNDIS_PACKET pnpPacket;
  1150. TraceEnter(MFE, "DeleteSource");
  1151. Trace(MFE, TRACE,
  1152. ("DeleteSource: Deleting %x (%d.%d.%d.%d)\n",
  1153. pSource,
  1154. PRINT_IPADDR(pSource->dwSource)));
  1155. //
  1156. // Delete any queued packets. Since we do not keep
  1157. // any refcount of packets pending in the lower layers
  1158. // (we depend on IP's SendComplete()) we dont need to do anything
  1159. // special over here
  1160. //
  1161. while(!IsFwqEmpty(&(pSource->fwqPending)))
  1162. {
  1163. pfqNode = RemoveHeadFwq(&(pSource->fwqPending));
  1164. pFWC = CONTAINING_RECORD(pfqNode,
  1165. FWContext,
  1166. fc_q);
  1167. pnpPacket = CONTAINING_RECORD(pFWC,
  1168. NDIS_PACKET,
  1169. ProtocolReserved);
  1170. FreeFWPacket(pnpPacket);
  1171. }
  1172. pOutIf = pSource->pFirstOutIf;
  1173. while(pOutIf)
  1174. {
  1175. //
  1176. // Free each of the OIFs
  1177. //
  1178. pTempIf = pOutIf->pNextOutIf;
  1179. RtAssert(pOutIf->pIpIf);
  1180. if((pOutIf->pIpIf isnot &LoopInterface) and
  1181. (pOutIf->pIpIf isnot &DummyInterface))
  1182. {
  1183. DerefMIF(pOutIf->pIpIf);
  1184. }
  1185. ExFreeToNPagedLookasideList(&g_llOifBlocks,
  1186. pOutIf);
  1187. pOutIf = pTempIf;
  1188. }
  1189. if((pSource->pInIpIf isnot NULL) and
  1190. (pSource->pInIpIf isnot &LoopInterface) and
  1191. (pSource->pInIpIf isnot &DummyInterface))
  1192. {
  1193. DerefMIF(pSource->pInIpIf);
  1194. }
  1195. ExFreeToNPagedLookasideList(&g_llSourceBlocks,
  1196. pSource);
  1197. TraceLeave(MFE, "DeleteSource");
  1198. }
  1199. //
  1200. // MUST BE PAGED IN
  1201. //
  1202. #pragma alloc_text(PAGEIPMc, RemoveSource)
  1203. VOID
  1204. RemoveSource(
  1205. IN DWORD dwGroup,
  1206. IN DWORD dwSource,
  1207. IN DWORD dwSrcMask,
  1208. IN PGROUP pGroup, OPTIONAL
  1209. IN PSOURCE pSource OPTIONAL
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Removes a source from the group list. We remove any stored pointers to
  1214. the SOURCE and then deref the source. If no one is using the SOURCE, it
  1215. will get deleted. Otherwise no new thread can get access to it (since all
  1216. stored pointers have been removed) and when the last currently using thread
  1217. is done with the source, the deref will cause it to be deleted
  1218. The function can either take a group address, source address and source
  1219. mask or if the calling routine has already looked up the source, it can
  1220. take a pointer to GROUP and SOURCE
  1221. Locks:
  1222. The group bucket lock must be held as WRITER
  1223. If the function is called with pointers to GROUP and SOURCE, then the
  1224. SOURCE must be ref'ed and locked
  1225. Arguments:
  1226. dwGroup Class D Group IP Address
  1227. dwSource Source IP Address
  1228. dwSrcMask Mask (not used)
  1229. pGroup Pointer to GROUP to which source belongs
  1230. pSource Pointer to SOURCE to which packet needs to be removed
  1231. Return Value:
  1232. NONE
  1233. --*/
  1234. {
  1235. BOOLEAN bDelGroup;
  1236. TraceEnter(MFE, "RemoveSource");
  1237. Trace(MFE, TRACE,
  1238. ("RemoveSource: Asked to remove %d.%d.%d.%d %d.%d.%d.%d. Also given pGroup %x pSource %x\n",
  1239. PRINT_IPADDR(dwGroup), PRINT_IPADDR(dwSource), pGroup, pSource));
  1240. if(!ARGUMENT_PRESENT(pSource))
  1241. {
  1242. RtAssert(!ARGUMENT_PRESENT(pGroup));
  1243. //
  1244. // Find the group and the source
  1245. //
  1246. pGroup = LookupGroup(dwGroup);
  1247. if(pGroup is NULL)
  1248. {
  1249. //
  1250. // We may have deleted it before
  1251. //
  1252. Trace(MFE, INFO,
  1253. ("RemoveSource: Group not found"));
  1254. TraceLeave(MFE, "RemoveSource");
  1255. return;
  1256. }
  1257. pSource = FindSourceGivenGroup(pGroup,
  1258. dwSource,
  1259. dwSrcMask);
  1260. if(pSource is NULL)
  1261. {
  1262. //
  1263. // Again, may have been deleted because of inactivity
  1264. //
  1265. Trace(MFE, INFO,
  1266. ("RemoveMfe: Source not found"));
  1267. TraceLeave(MFE, "RemoveMfe");
  1268. return;
  1269. }
  1270. }
  1271. RtAssert(pSource isnot NULL);
  1272. RtAssert(pGroup isnot NULL);
  1273. //
  1274. // So lets unlink the source (and possibly the group) and
  1275. // then we can let go of the lock
  1276. //
  1277. RemoveEntryList(&pSource->leGroupLink);
  1278. pGroup->ulNumSources--;
  1279. bDelGroup = FALSE;
  1280. if(pGroup->ulNumSources is 0)
  1281. {
  1282. ULONG ulIndex;
  1283. //
  1284. // No more sources, blow away the group
  1285. //
  1286. RemoveEntryList(&pGroup->leHashLink);
  1287. ulIndex = GROUP_HASH(dwGroup);
  1288. if(g_rgGroupTable[ulIndex].pGroup is pGroup)
  1289. {
  1290. g_rgGroupTable[ulIndex].pGroup = NULL;
  1291. }
  1292. #if DBG
  1293. g_rgGroupTable[ulIndex].ulGroupCount--;
  1294. #endif
  1295. Trace(MFE, TRACE,
  1296. ("RemoveSource: No more sources, will remove group\n"));
  1297. bDelGroup = TRUE;
  1298. }
  1299. //
  1300. // The source has been ref'ed and locked because we called
  1301. // FindSourceGivenGroup(). Undo that
  1302. //
  1303. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  1304. DereferenceSource(pSource);
  1305. //
  1306. // Remove all store pointers to the source
  1307. //
  1308. // TODO - If we want to cache, the cleanup will need to be done here
  1309. //
  1310. // Just dereference the source. This causes the reference kept due to the
  1311. // fact the the pointer is on the list to be removed. If no one else is
  1312. // using the source, then this will cause it to be deleted
  1313. //
  1314. DereferenceSource(pSource);
  1315. if(bDelGroup)
  1316. {
  1317. ExFreeToNPagedLookasideList(&g_llGroupBlocks,
  1318. pGroup);
  1319. }
  1320. TraceLeave(MFE, "RemoveSource");
  1321. }
  1322. #endif