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.

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