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.

1445 lines
28 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. tcpip\ip\mcastioc.c
  5. Abstract:
  6. IOCTL handlers for IP Multicasting
  7. Author:
  8. Amritansh Raghav
  9. Revision History:
  10. AmritanR Created
  11. Notes:
  12. --*/
  13. #include "precomp.h"
  14. #if IPMCAST
  15. #define __FILE_SIG__ IOCT_SIG
  16. #include "ipmcast.h"
  17. #include "ipmcstxt.h"
  18. #include "mcastioc.h"
  19. #include "mcastmfe.h"
  20. //
  21. // The table of IOCTL handlers.
  22. //
  23. //#pragma data_seg(PAGE)
  24. PFN_IOCTL_HNDLR g_rgpfnProcessIoctl[] = {
  25. SetMfe,
  26. GetMfe,
  27. DeleteMfe,
  28. SetTtl,
  29. GetTtl,
  30. ProcessNotification,
  31. StartStopDriver,
  32. SetIfState,
  33. };
  34. //#pragma data_seg()
  35. NTSTATUS
  36. StartDriver(
  37. VOID
  38. );
  39. NTSTATUS
  40. StopDriver(
  41. VOID
  42. );
  43. #pragma alloc_text(PAGE, SetMfe)
  44. NTSTATUS
  45. SetMfe(
  46. IN PIRP pIrp,
  47. IN ULONG ulInLength,
  48. IN ULONG ulOutLength
  49. )
  50. /*++
  51. Routine Description:
  52. This is the handler for IOCTL_IPMCAST_SET_MFE. We do the normal
  53. buffer length checks. We try and find the MFE. If it exists, we ovewrite it
  54. with the given MFE, otherwise create a new MFE
  55. Locks:
  56. None
  57. Arguments:
  58. pIrp IRP
  59. ulInLength The length of the Input Buffer
  60. ulOutLength The length of the Output Buffer
  61. Return Value:
  62. STATUS_SUCCESS
  63. STATUS_BUFFER_TOO_SMALL
  64. STATUS_INFO_LENGTH_MISMATCH
  65. --*/
  66. {
  67. PVOID pvIoBuffer;
  68. PIPMCAST_MFE pMfe, pOldMfe;
  69. ULONG i;
  70. NTSTATUS nsStatus;
  71. TraceEnter(MFE, "SetMfe");
  72. //
  73. // Get the user buffer
  74. //
  75. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  76. pMfe = (PIPMCAST_MFE)pvIoBuffer;
  77. //
  78. // Always clean out the information field
  79. //
  80. pIrp->IoStatus.Information = 0;
  81. //
  82. // If we have dont even have enough for the basic MFE
  83. // there is something bad going on
  84. //
  85. if(ulInLength < SIZEOF_BASIC_MFE)
  86. {
  87. Trace(MFE, ERROR,
  88. ("SetMfe: In Length %d is less than smallest MFE %d\n",
  89. ulInLength,
  90. SIZEOF_BASIC_MFE));
  91. TraceLeave(MFE, "SetMfe");
  92. return STATUS_BUFFER_TOO_SMALL;
  93. }
  94. //
  95. // The in length doesnt match with the MFE
  96. //
  97. if(ulInLength < SIZEOF_MFE(pMfe->ulNumOutIf))
  98. {
  99. Trace(MFE, ERROR,
  100. ("SetMfe: In length %d is less than required (%d) for %d out i/f\n",
  101. ulInLength,
  102. SIZEOF_MFE(pMfe->ulNumOutIf),
  103. pMfe->ulNumOutIf));
  104. TraceLeave(MFE, "SetMfe");
  105. return STATUS_INFO_LENGTH_MISMATCH;
  106. }
  107. //
  108. // Ok, so we got a good MFE
  109. //
  110. Trace(MFE, TRACE,
  111. ("SetMfe: Group %d.%d.%d.%d Source %d.%d.%d.%d(%d.%d.%d.%d). In If %d Num Out %d\n",
  112. PRINT_IPADDR(pMfe->dwGroup),
  113. PRINT_IPADDR(pMfe->dwSource),
  114. PRINT_IPADDR(pMfe->dwSrcMask),
  115. pMfe->dwInIfIndex,
  116. pMfe->ulNumOutIf));
  117. #if DBG
  118. for(i = 0; i < pMfe->ulNumOutIf; i++)
  119. {
  120. Trace(MFE, TRACE,
  121. ("Out If %d Dial Ctxt %d NextHop %d.%d.%d.%d\n",
  122. pMfe->rgioOutInfo[i].dwOutIfIndex,
  123. pMfe->rgioOutInfo[i].dwDialContext,
  124. PRINT_IPADDR(pMfe->rgioOutInfo[i].dwNextHopAddr)));
  125. }
  126. #endif // DBG
  127. nsStatus = CreateOrUpdateMfe(pMfe);
  128. TraceLeave(MFE, "SetMfe");
  129. return nsStatus;
  130. }
  131. //
  132. // MUST BE PAGED IN
  133. //
  134. #pragma alloc_text(PAGEIPMc, DeleteMfe)
  135. NTSTATUS
  136. DeleteMfe(
  137. IN PIRP pIrp,
  138. IN ULONG ulInLength,
  139. IN ULONG ulOutLength
  140. )
  141. /*++
  142. Routine Description:
  143. Handler for IOCTL_IPMCAST_DELETE_MFE. We check the buffer lengths, and if
  144. valid call RemoveSource to remove the MFE
  145. Locks:
  146. Takes the lock for the hash bucket as writer
  147. Arguments:
  148. pIrp IRP
  149. ulInLength The length of the Input Buffer
  150. ulOutLength The length of the Output Buffer
  151. Return Value:
  152. STATUS_SUCCESS
  153. STATUS_BUFFER_TOO_SMALL
  154. --*/
  155. {
  156. PVOID pvIoBuffer;
  157. KIRQL kiCurrIrql;
  158. ULONG ulIndex;
  159. PLIST_ENTRY pleNode;
  160. PIPMCAST_DELETE_MFE pDelMfe;
  161. TraceEnter(MFE, "DeleteMfe");
  162. //
  163. // Get the user buffer
  164. //
  165. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  166. pDelMfe = (PIPMCAST_DELETE_MFE)pvIoBuffer;
  167. pIrp->IoStatus.Information = 0;
  168. //
  169. // Check the length
  170. //
  171. if(ulInLength < sizeof(IPMCAST_DELETE_MFE))
  172. {
  173. Trace(MFE, ERROR,
  174. ("DeleteMfe: In Length %d is less required size %d\n",
  175. ulInLength,
  176. sizeof(IPMCAST_DELETE_MFE)));
  177. TraceLeave(MFE, "DeleteMfe");
  178. return STATUS_BUFFER_TOO_SMALL;
  179. }
  180. Trace(MFE, TRACE,
  181. ("DeleteMfe: Group %d.%d.%d.%d Source %d.%d.%d.%d Mask %d.%d.%d.%d\n",
  182. PRINT_IPADDR(pDelMfe->dwGroup),
  183. PRINT_IPADDR(pDelMfe->dwSource),
  184. PRINT_IPADDR(pDelMfe->dwSrcMask)));
  185. //
  186. // Get exclusive access to the group bucket
  187. //
  188. ulIndex = GROUP_HASH(pDelMfe->dwGroup);
  189. EnterWriter(&g_rgGroupTable[ulIndex].rwlLock,
  190. &kiCurrIrql);
  191. RemoveSource(pDelMfe->dwGroup,
  192. pDelMfe->dwSource,
  193. pDelMfe->dwSrcMask,
  194. NULL,
  195. NULL);
  196. ExitWriter(&g_rgGroupTable[ulIndex].rwlLock,
  197. kiCurrIrql);
  198. TraceLeave(MFE, "DeleteMfe");
  199. return STATUS_SUCCESS;
  200. }
  201. //
  202. // MUST BE PAGED IN
  203. //
  204. #pragma alloc_text(PAGEIPMc, GetMfe)
  205. NTSTATUS
  206. GetMfe(
  207. IN PIRP pIrp,
  208. IN ULONG ulInLength,
  209. IN ULONG ulOutLength
  210. )
  211. /*++
  212. Routine Description:
  213. Handler for IOCTL_IPMCAST_GET_MFE
  214. If the buffer is smaller than SIZEOF_BASIC_MFE_STATS, we return with an
  215. error
  216. If the buffer is larger than SIZEOF_BASIC_MFE_STATS but not large enough
  217. to hold the MFE, we fill in the basic MFE (which has the number of OIFs)
  218. and return with STATUS_SUCCESS. This allows the caller to determine what
  219. size buffer should be passed.
  220. If the buffer is large enough to hold all the info, we fill it out and
  221. return STATUS_SUCCESS.
  222. Locks:
  223. Takes the group bucket lock as reader
  224. Arguments:
  225. pIrp IRP
  226. ulInLength The length of the Input Buffer
  227. ulOutLength The length of the Output Buffer
  228. Return Value:
  229. STATUS_SUCCESS
  230. STATUS_BUFFER_TOO_SMALL
  231. STATUS_NOT_FOUND
  232. --*/
  233. {
  234. PVOID pvIoBuffer;
  235. ULONG i;
  236. KIRQL kiCurrIrql;
  237. PGROUP pGroup;
  238. PSOURCE pSource;
  239. POUT_IF pOutIf, pTempIf;
  240. ULONG ulIndex;
  241. PLIST_ENTRY pleNode;
  242. PIPMCAST_MFE_STATS pOutMfe;
  243. TraceEnter(MFE, "GetMfe");
  244. //
  245. // Get the user buffer
  246. //
  247. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  248. pOutMfe = (PIPMCAST_MFE_STATS)pvIoBuffer;
  249. pIrp->IoStatus.Information = 0;
  250. //
  251. // Check the length
  252. //
  253. if(ulOutLength < SIZEOF_BASIC_MFE_STATS)
  254. {
  255. Trace(MFE, ERROR,
  256. ("GetMfe: Out Length %d is less than smallest MFE %d\n",
  257. ulOutLength,
  258. SIZEOF_BASIC_MFE_STATS));
  259. TraceLeave(MFE, "GetMfe");
  260. return STATUS_BUFFER_TOO_SMALL;
  261. }
  262. Trace(MFE, TRACE,
  263. ("GetMfe: Group %d.%d.%d.%d Source %d.%d.%d.%d Mask %d.%d.%d.%d\n",
  264. PRINT_IPADDR(pOutMfe->dwGroup),
  265. PRINT_IPADDR(pOutMfe->dwSource),
  266. PRINT_IPADDR(pOutMfe->dwSrcMask)));
  267. //
  268. // Get shared access to the group bucket
  269. //
  270. ulIndex = GROUP_HASH(pOutMfe->dwGroup);
  271. EnterReader(&g_rgGroupTable[ulIndex].rwlLock,
  272. &kiCurrIrql);
  273. //
  274. // Find the group and the source
  275. //
  276. pGroup = LookupGroup(pOutMfe->dwGroup);
  277. if(pGroup is NULL)
  278. {
  279. //
  280. // We may have deleted it before
  281. //
  282. Trace(MFE, INFO,
  283. ("GetMfe: Group not found"));
  284. ExitReader(&g_rgGroupTable[ulIndex].rwlLock,
  285. kiCurrIrql);
  286. TraceLeave(MFE, "GetMfe");
  287. return STATUS_NOT_FOUND;
  288. }
  289. pSource = FindSourceGivenGroup(pGroup,
  290. pOutMfe->dwSource,
  291. pOutMfe->dwSrcMask);
  292. if(pSource is NULL)
  293. {
  294. //
  295. // Again, may have been deleted because of inactivity
  296. //
  297. Trace(MFE, INFO,
  298. ("GetMfe: Source not found"));
  299. ExitReader(&g_rgGroupTable[ulIndex].rwlLock,
  300. kiCurrIrql);
  301. TraceLeave(MFE, "GetMfe");
  302. return STATUS_NOT_FOUND;
  303. }
  304. //
  305. // Check the length needed again
  306. //
  307. if(ulOutLength < SIZEOF_MFE_STATS(pSource->ulNumOutIf))
  308. {
  309. //
  310. // Not big enough to hold all data. It is, however
  311. // large enough to hold the number of out interfaces
  312. // Let the user know that, so the next time around
  313. // she can supply a buffer with enough space
  314. //
  315. Trace(MFE, ERROR,
  316. ("SetMfe: Out len %d is less than required (%d) for %d out i/f\n",
  317. ulOutLength,
  318. SIZEOF_MFE_STATS(pSource->ulNumOutIf),
  319. pSource->ulNumOutIf));
  320. pOutMfe->ulNumOutIf = pSource->ulNumOutIf;
  321. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  322. DereferenceSource(pSource);
  323. ExitReader(&g_rgGroupTable[ulIndex].rwlLock,
  324. kiCurrIrql);
  325. pIrp->IoStatus.Information = SIZEOF_BASIC_MFE;
  326. TraceLeave(MFE, "GetMfe");
  327. //
  328. // Just the way NT is. You have to return success for the
  329. // I/O subsystem to copy out the data.
  330. //
  331. return STATUS_SUCCESS;
  332. }
  333. //
  334. // Copy out the information and set the length in
  335. // the IRP
  336. //
  337. pOutMfe->ulNumOutIf = pSource->ulNumOutIf;
  338. pOutMfe->dwInIfIndex = pSource->dwInIfIndex;
  339. pOutMfe->ulInPkts = pSource->ulInPkts;
  340. pOutMfe->ulPktsDifferentIf = pSource->ulPktsDifferentIf;
  341. pOutMfe->ulInOctets = pSource->ulInOctets;
  342. pOutMfe->ulQueueOverflow = pSource->ulQueueOverflow;
  343. pOutMfe->ulUninitMfe = pSource->ulUninitMfe;
  344. pOutMfe->ulNegativeMfe = pSource->ulNegativeMfe;
  345. pOutMfe->ulInDiscards = pSource->ulInDiscards;
  346. pOutMfe->ulInHdrErrors = pSource->ulInHdrErrors;
  347. pOutMfe->ulTotalOutPackets = pSource->ulTotalOutPackets;
  348. for(pOutIf = pSource->pFirstOutIf, i = 0;
  349. pOutIf isnot NULL;
  350. pOutIf = pOutIf->pNextOutIf, i++)
  351. {
  352. pOutMfe->rgiosOutStats[i].dwOutIfIndex = pOutIf->dwIfIndex;
  353. pOutMfe->rgiosOutStats[i].dwNextHopAddr = pOutIf->dwNextHopAddr;
  354. pOutMfe->rgiosOutStats[i].dwDialContext = pOutIf->dwDialContext;
  355. pOutMfe->rgiosOutStats[i].ulTtlTooLow = pOutIf->ulTtlTooLow;
  356. pOutMfe->rgiosOutStats[i].ulFragNeeded = pOutIf->ulFragNeeded;
  357. pOutMfe->rgiosOutStats[i].ulOutPackets = pOutIf->ulOutPackets;
  358. pOutMfe->rgiosOutStats[i].ulOutDiscards = pOutIf->ulOutDiscards;
  359. }
  360. pIrp->IoStatus.Information = SIZEOF_MFE_STATS(pSource->ulNumOutIf);
  361. RtReleaseSpinLockFromDpcLevel(&(pSource->mlLock));
  362. DereferenceSource(pSource);
  363. ExitReader(&g_rgGroupTable[ulIndex].rwlLock,
  364. kiCurrIrql);
  365. return STATUS_SUCCESS;
  366. }
  367. //
  368. // MUST BE PAGED IN
  369. //
  370. #pragma alloc_text(PAGEIPMc, SetTtl)
  371. NTSTATUS
  372. SetTtl(
  373. IN PIRP pIrp,
  374. IN ULONG ulInLength,
  375. IN ULONG ulOutLength
  376. )
  377. /*++
  378. Routine Description:
  379. The handler for IOCTL_IPMCAST_SET_TTL
  380. We find the IP Interface referred to by the IOCTL and if found, set the
  381. if_mcastttl field.
  382. No checks are made on the TTL value, so the caller must ensure that it is
  383. between 1 and 255
  384. Locks:
  385. None currently, but when IP puts locks around the IFList, we will need to
  386. take that lock
  387. Arguments:
  388. pIrp IRP
  389. ulInLength The length of the Input Buffer
  390. ulOutLength The length of the Output Buffer
  391. Return Value:
  392. STATUS_SUCCESS
  393. STATUS_BUFFER_TOO_SMALL
  394. STATUS_NOT_FOUND
  395. --*/
  396. {
  397. PVOID pvIoBuffer;
  398. Interface *pIpIf;
  399. BOOLEAN bFound;
  400. PIPMCAST_IF_TTL pTtl;
  401. CTELockHandle Handle;
  402. //
  403. // Get the user buffer
  404. //
  405. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  406. pTtl = (PIPMCAST_IF_TTL)pvIoBuffer;
  407. pIrp->IoStatus.Information = 0;
  408. //
  409. // Check the length
  410. //
  411. if(ulInLength < sizeof(IPMCAST_IF_TTL))
  412. {
  413. Trace(IF, ERROR,
  414. ("SetTtl: In Length %d is less required size %d\n",
  415. ulInLength,
  416. sizeof(IPMCAST_IF_TTL)));
  417. return STATUS_BUFFER_TOO_SMALL;
  418. }
  419. Trace(IF, TRACE,
  420. ("SetTtl: Index %d Ttl %d\n",
  421. pTtl->dwIfIndex,
  422. pTtl->byTtl));
  423. bFound = FALSE;
  424. CTEGetLock(&RouteTableLock.Lock, &Handle);
  425. for(pIpIf = IFList; pIpIf isnot NULL; pIpIf = pIpIf->if_next)
  426. {
  427. if(pIpIf->if_index is pTtl->dwIfIndex)
  428. {
  429. bFound = TRUE;
  430. break;
  431. }
  432. }
  433. if(!bFound)
  434. {
  435. Trace(IF, ERROR,
  436. ("SetTtl: If %d not found\n",
  437. pTtl->dwIfIndex));
  438. CTEFreeLock(&RouteTableLock.Lock, Handle);
  439. return STATUS_NOT_FOUND;
  440. }
  441. pIpIf->if_mcastttl = pTtl->byTtl;
  442. CTEFreeLock(&RouteTableLock.Lock, Handle);
  443. return STATUS_SUCCESS;
  444. }
  445. //
  446. // MUST BE PAGED IN
  447. //
  448. #pragma alloc_text(PAGEIPMc, GetTtl)
  449. NTSTATUS
  450. GetTtl(
  451. IN PIRP pIrp,
  452. IN ULONG ulInLength,
  453. IN ULONG ulOutLength
  454. )
  455. /*++
  456. Routine Description:
  457. The handler for IOCTL_IPMCAST_GET_TTL
  458. We find the IP Interface referred to by the IOCTL and if found, copy out
  459. its if_mcastttl field.
  460. No checks are made on the TTL value, so the caller must ensure that it is
  461. between 1 and 255
  462. Locks:
  463. None currently, but when IP puts locks around the IFList, we will need to
  464. take that lock
  465. Arguments:
  466. pIrp IRP
  467. ulInLength The length of the Input Buffer
  468. ulOutLength The length of the Output Buffer
  469. Return Value:
  470. STATUS_SUCCESS
  471. STATUS_BUFFER_TOO_SMALL
  472. STATUS_NOT_FOUND
  473. --*/
  474. {
  475. PVOID pvIoBuffer;
  476. Interface *pIpIf;
  477. BOOLEAN bFound;
  478. PIPMCAST_IF_TTL pTtl;
  479. CTELockHandle Handle;
  480. //
  481. // Get the user buffer
  482. //
  483. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  484. pTtl = (PIPMCAST_IF_TTL)pvIoBuffer;
  485. pIrp->IoStatus.Information = 0;
  486. //
  487. // Check the length of both the in and the out buffers
  488. //
  489. if(ulInLength < sizeof(IPMCAST_IF_TTL))
  490. {
  491. Trace(IF, ERROR,
  492. ("GetTtl: In Length %d is less required size %d\n",
  493. ulOutLength,
  494. sizeof(IPMCAST_IF_TTL)));
  495. return STATUS_BUFFER_TOO_SMALL;
  496. }
  497. if(ulOutLength < sizeof(IPMCAST_IF_TTL))
  498. {
  499. Trace(IF, ERROR,
  500. ("GetTtl: Out Length %d is less required size %d\n",
  501. ulOutLength,
  502. sizeof(IPMCAST_IF_TTL)));
  503. return STATUS_BUFFER_TOO_SMALL;
  504. }
  505. Trace(IF, TRACE,
  506. ("GetTtl: Index %d\n", pTtl->dwIfIndex));
  507. bFound = FALSE;
  508. CTEGetLock(&RouteTableLock.Lock, &Handle);
  509. for(pIpIf = IFList; pIpIf isnot NULL; pIpIf = pIpIf->if_next)
  510. {
  511. if(pIpIf->if_index is pTtl->dwIfIndex)
  512. {
  513. bFound = TRUE;
  514. break;
  515. }
  516. }
  517. if(!bFound)
  518. {
  519. Trace(IF, ERROR,
  520. ("GetTtl: If %d not found\n",
  521. pTtl->dwIfIndex));
  522. CTEFreeLock(&RouteTableLock.Lock, Handle);
  523. return STATUS_NOT_FOUND;
  524. }
  525. pIrp->IoStatus.Information = sizeof(IPMCAST_IF_TTL);
  526. pTtl->byTtl = pIpIf->if_mcastttl;
  527. CTEFreeLock(&RouteTableLock.Lock, Handle);
  528. return STATUS_SUCCESS;
  529. }
  530. //
  531. // MUST BE PAGED IN
  532. //
  533. #pragma alloc_text(PAGEIPMc, SetIfState)
  534. NTSTATUS
  535. SetIfState(
  536. IN PIRP pIrp,
  537. IN ULONG ulInLength,
  538. IN ULONG ulOutLength
  539. )
  540. /*++
  541. Routine Description:
  542. The handler for IOCTL_IPMCAST_SET_IF_STATE
  543. We find the IP Interface referred to by the IOCTL and if found, set the
  544. if_mcaststate field.
  545. Locks:
  546. None currently, but when IP puts locks around the IFList, we will need to
  547. take that lock
  548. Arguments:
  549. pIrp IRP
  550. ulInLength The length of the Input Buffer
  551. ulOutLength The length of the Output Buffer
  552. Return Value:
  553. STATUS_SUCCESS
  554. STATUS_BUFFER_TOO_SMALL
  555. STATUS_NOT_FOUND
  556. --*/
  557. {
  558. PVOID pvIoBuffer;
  559. Interface *pIpIf;
  560. BOOLEAN bFound;
  561. PIPMCAST_IF_STATE pState;
  562. CTELockHandle Handle;
  563. //
  564. // Get the user buffer
  565. //
  566. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  567. pState = (PIPMCAST_IF_STATE)pvIoBuffer;
  568. pIrp->IoStatus.Information = 0;
  569. //
  570. // Check the length
  571. //
  572. if(ulInLength < sizeof(IPMCAST_IF_STATE))
  573. {
  574. Trace(IF, ERROR,
  575. ("SetState: In Length %d is less required size %d\n",
  576. ulInLength,
  577. sizeof(IPMCAST_IF_STATE)));
  578. return STATUS_BUFFER_TOO_SMALL;
  579. }
  580. Trace(IF, TRACE,
  581. ("SetState: Index %d State %d\n",
  582. pState->dwIfIndex,
  583. pState->byState));
  584. bFound = FALSE;
  585. CTEGetLock(&RouteTableLock.Lock, &Handle);
  586. for(pIpIf = IFList; pIpIf isnot NULL; pIpIf = pIpIf->if_next)
  587. {
  588. if(pIpIf->if_index is pState->dwIfIndex)
  589. {
  590. bFound = TRUE;
  591. break;
  592. }
  593. }
  594. if(!bFound)
  595. {
  596. Trace(IF, ERROR,
  597. ("SetState: If %d not found\n",
  598. pState->dwIfIndex));
  599. CTEFreeLock(&RouteTableLock.Lock, Handle);
  600. return STATUS_NOT_FOUND;
  601. }
  602. if(pState->byState)
  603. {
  604. pIpIf->if_mcastflags |= IPMCAST_IF_ENABLED;
  605. }
  606. CTEFreeLock(&RouteTableLock.Lock, Handle);
  607. return STATUS_SUCCESS;
  608. }
  609. //
  610. // MUST BE PAGED IN
  611. //
  612. #pragma alloc_text(PAGEIPMc, ProcessNotification)
  613. NTSTATUS
  614. ProcessNotification(
  615. IN PIRP pIrp,
  616. IN ULONG ulInLength,
  617. IN ULONG ulOutLength
  618. )
  619. /*++
  620. Routine Description:
  621. The handler for IOCTL_IPMCAST_POST_NOTIFICATION
  622. If we have a pending message, we copy it out and complete the IRP
  623. synchronously.
  624. Otherwise, we put it in the list of pending IRPs.
  625. Locks:
  626. Since this is a potentially cancellable IRP, it must be operated upon with
  627. the CancelSpinLock held
  628. Arguments:
  629. pIrp IRP
  630. ulInLength The length of the Input Buffer
  631. ulOutLength The length of the Output Buffer
  632. Return Value:
  633. STATUS_SUCCESS
  634. STATUS_PENDING
  635. STATUS_BUFFER_TOO_SMALL
  636. --*/
  637. {
  638. KIRQL kiIrql;
  639. PLIST_ENTRY pleNode;
  640. DWORD dwSize;
  641. PVOID pvIoBuffer;
  642. PNOTIFICATION_MSG pMsg;
  643. PIPMCAST_NOTIFICATION pinData;
  644. if(ulOutLength < sizeof(IPMCAST_NOTIFICATION))
  645. {
  646. Trace(GLOBAL,ERROR,
  647. ("ProcessNotification: Buffer size %d smaller than reqd %d\n",
  648. ulOutLength,
  649. sizeof(IPMCAST_NOTIFICATION)));
  650. return STATUS_BUFFER_TOO_SMALL;
  651. }
  652. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  653. //
  654. // use cancel spin lock to prevent irp being cancelled during this call.
  655. //
  656. IoAcquireCancelSpinLock(&kiIrql);
  657. //
  658. // If we have a pending notification then complete it - else
  659. // queue the notification IRP
  660. //
  661. if(!IsListEmpty(&g_lePendingNotification))
  662. {
  663. Trace(GLOBAL, TRACE,
  664. ("ProcessNotification: Pending notification being completed\n"));
  665. pleNode = RemoveHeadList(&g_lePendingNotification);
  666. pMsg = CONTAINING_RECORD(pleNode, NOTIFICATION_MSG, leMsgLink);
  667. pinData = &(pMsg->inMessage);
  668. switch(pinData->dwEvent)
  669. {
  670. case IPMCAST_RCV_PKT_MSG:
  671. {
  672. Trace(GLOBAL, TRACE,
  673. ("ProcessNotification: Pending notification is RCV_PKT\n"));
  674. dwSize = FIELD_OFFSET(IPMCAST_NOTIFICATION, ipmPkt) +
  675. SIZEOF_PKT_MSG(&(pinData->ipmPkt));
  676. break;
  677. }
  678. case IPMCAST_DELETE_MFE_MSG:
  679. {
  680. Trace(GLOBAL, TRACE,
  681. ("ProcessNotification: Pending notification is DELETE_MFE\n"));
  682. dwSize = FIELD_OFFSET(IPMCAST_NOTIFICATION, immMfe) +
  683. SIZEOF_MFE_MSG(&(pinData->immMfe));
  684. break;
  685. }
  686. }
  687. RtlCopyMemory(pvIoBuffer,
  688. pinData,
  689. dwSize);
  690. IoSetCancelRoutine(pIrp, NULL);
  691. //
  692. // Free the allocated notification
  693. //
  694. ExFreeToNPagedLookasideList(&g_llMsgBlocks,
  695. pMsg);
  696. pIrp->IoStatus.Information = dwSize;
  697. IoReleaseCancelSpinLock(kiIrql);
  698. return STATUS_SUCCESS ;
  699. }
  700. else
  701. {
  702. Trace(GLOBAL, TRACE,
  703. ("Notification being queued\n"));
  704. //
  705. // Mark the irp as pending
  706. //
  707. IoMarkIrpPending(pIrp);
  708. //
  709. // Queue up the irp at the end
  710. //
  711. InsertTailList (&g_lePendingIrpQueue, &(pIrp->Tail.Overlay.ListEntry));
  712. //
  713. // Set the cancel routine
  714. //
  715. IoSetCancelRoutine(pIrp, CancelNotificationIrp);
  716. IoReleaseCancelSpinLock(kiIrql);
  717. return STATUS_PENDING;
  718. }
  719. }
  720. //
  721. // MUST BE PAGED IN
  722. //
  723. #pragma alloc_text(PAGEIPMc, CancelNotificationIrp)
  724. VOID
  725. CancelNotificationIrp(
  726. IN PDEVICE_OBJECT DeviceObject,
  727. IN PIRP Irp
  728. )
  729. /*++
  730. Routine Description:
  731. Cancellation routine for a pending IRP
  732. We remove the IRP from the pending queue, and set its status as
  733. STATUS_CANCELLED
  734. Locks:
  735. IO Subsystem calls this with the CancelSpinLock held.
  736. We need to release it in this call.
  737. Arguments:
  738. Irp The IRP to be cancelled
  739. Return Value:
  740. None
  741. --*/
  742. {
  743. TraceEnter(GLOBAL, "CancelNotificationIrp");
  744. //
  745. // Mark this Irp as cancelled
  746. //
  747. Irp->IoStatus.Status = STATUS_CANCELLED;
  748. Irp->IoStatus.Information = 0;
  749. //
  750. // Take off our own list
  751. //
  752. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  753. //
  754. // Release cancel spin lock which the IO system acquired
  755. //
  756. IoReleaseCancelSpinLock(Irp->CancelIrql);
  757. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  758. }
  759. //
  760. // MUST BE PAGED IN
  761. //
  762. #pragma alloc_text(PAGEIPMc, CompleteNotificationIrp)
  763. VOID
  764. CompleteNotificationIrp(
  765. IN PNOTIFICATION_MSG pMsg
  766. )
  767. /*++
  768. Routine Description:
  769. Called to complete an IRP back to User space.
  770. If an IRP is pending, we copy out the message to the IRP and complete it
  771. Otherwise, we put the message on the pending message queue. The next time
  772. a notification IRP is posted to us, we will copy out the message.
  773. Locks:
  774. Since both the pending message and the pending IRP queue are locked by the
  775. CancelSpinLock, we need to acquire that in the function
  776. Arguments:
  777. pMsg Message to send to user
  778. Return Value:
  779. None
  780. --*/
  781. {
  782. KIRQL irql;
  783. PLIST_ENTRY pleNode = NULL ;
  784. PIRP pIrp ;
  785. PVOID pvIoBuffer;
  786. DWORD dwSize;
  787. PIPMCAST_NOTIFICATION pinData;
  788. TraceEnter(GLOBAL,"CompleteNotificationIrp");
  789. pinData = &(pMsg->inMessage);
  790. switch(pinData->dwEvent)
  791. {
  792. case IPMCAST_RCV_PKT_MSG:
  793. case IPMCAST_WRONG_IF_MSG:
  794. {
  795. dwSize = FIELD_OFFSET(IPMCAST_NOTIFICATION, ipmPkt) + SIZEOF_PKT_MSG(&(pinData->ipmPkt));
  796. break;
  797. }
  798. case IPMCAST_DELETE_MFE_MSG:
  799. {
  800. dwSize = FIELD_OFFSET(IPMCAST_NOTIFICATION, immMfe) + SIZEOF_MFE_MSG(&(pinData->immMfe));
  801. break;
  802. }
  803. default:
  804. {
  805. RtAssert(FALSE);
  806. dwSize = 0;
  807. break;
  808. }
  809. }
  810. //
  811. // grab cancel spin lock
  812. //
  813. IoAcquireCancelSpinLock (&irql);
  814. if(!IsListEmpty(&g_lePendingIrpQueue))
  815. {
  816. pleNode = RemoveHeadList(&g_lePendingIrpQueue) ;
  817. Trace(GLOBAL, TRACE,
  818. ("CompleteNotificationIrp: Found a pending Irp\n"));
  819. pIrp = CONTAINING_RECORD(pleNode, IRP, Tail.Overlay.ListEntry);
  820. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  821. memcpy(pvIoBuffer,
  822. pinData,
  823. dwSize);
  824. Trace(GLOBAL, TRACE,
  825. ("CompleteNotificationIrp: Returning Irp with event code of %d\n",
  826. ((PIPMCAST_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer)->dwEvent));
  827. IoSetCancelRoutine(pIrp, NULL) ;
  828. pIrp->IoStatus.Information = dwSize;
  829. pIrp->IoStatus.Status = STATUS_SUCCESS;
  830. //
  831. // release lock
  832. //
  833. IoReleaseCancelSpinLock (irql);
  834. IoCompleteRequest(pIrp,
  835. IO_NETWORK_INCREMENT);
  836. //
  837. // Free the allocated notification
  838. //
  839. ExFreeToNPagedLookasideList(&g_llMsgBlocks,
  840. pMsg);
  841. }
  842. else
  843. {
  844. Trace(GLOBAL, TRACE,
  845. ("CompleteNotificationIrp: Found no pending Irp so queuing the notification\n"));
  846. InsertTailList(&g_lePendingNotification, &(pMsg->leMsgLink));
  847. //
  848. // release lock
  849. //
  850. IoReleaseCancelSpinLock (irql);
  851. }
  852. }
  853. //
  854. // MUST BE PAGED IN
  855. //
  856. #pragma alloc_text(PAGEIPMc, ClearPendingIrps)
  857. VOID
  858. ClearPendingIrps(
  859. VOID
  860. )
  861. /*++
  862. Routine Description:
  863. Called to shutdown time to complete any pending IRPS we may have
  864. Locks:
  865. Since both the pending message and the pending IRP queue are locked by the
  866. CancelSpinLock, we need to acquire that in the function
  867. Arguments:
  868. None
  869. Return Value:
  870. None
  871. --*/
  872. {
  873. KIRQL irql;
  874. PLIST_ENTRY pleNode = NULL;
  875. PIRP pIrp;
  876. TraceEnter(GLOBAL, "ClearPendingIrps");
  877. IoAcquireCancelSpinLock(&irql);
  878. while(!IsListEmpty(&g_lePendingIrpQueue))
  879. {
  880. pleNode = RemoveHeadList(&g_lePendingIrpQueue);
  881. pIrp = CONTAINING_RECORD(pleNode, IRP, Tail.Overlay.ListEntry);
  882. IoSetCancelRoutine(pIrp, NULL);
  883. pIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  884. pIrp->IoStatus.Information = 0;
  885. //
  886. // release lock to complete the IRP
  887. //
  888. IoReleaseCancelSpinLock(irql);
  889. IoCompleteRequest(pIrp,
  890. IO_NETWORK_INCREMENT);
  891. //
  892. // Reaquire the lock
  893. //
  894. IoAcquireCancelSpinLock(&irql);
  895. }
  896. IoReleaseCancelSpinLock(irql);
  897. TraceLeave(GLOBAL, "ClearPendingIrps");
  898. }
  899. //
  900. // MUST BE PAGED IN
  901. //
  902. #pragma alloc_text(PAGEIPMc, ClearPendingNotifications)
  903. VOID
  904. ClearPendingNotifications(
  905. VOID
  906. )
  907. /*++
  908. Routine Description:
  909. Called to shutdown time to complete any pending notification messages we
  910. may have
  911. Locks:
  912. Since both the pending message and the pending IRP queue are locked by the
  913. CancelSpinLock, we need to acquire that in the function
  914. Arguments:
  915. None
  916. Return Value:
  917. None
  918. --*/
  919. {
  920. KIRQL irql;
  921. PLIST_ENTRY pleNode;
  922. PNOTIFICATION_MSG pMsg;
  923. TraceEnter(GLOBAL, "ClearPendingNotifications");
  924. IoAcquireCancelSpinLock(&irql);
  925. while(!IsListEmpty(&g_lePendingNotification))
  926. {
  927. pleNode = RemoveHeadList(&g_lePendingNotification);
  928. pMsg = CONTAINING_RECORD(pleNode, NOTIFICATION_MSG, leMsgLink);
  929. ExFreeToNPagedLookasideList(&g_llMsgBlocks,
  930. pMsg);
  931. }
  932. IoReleaseCancelSpinLock(irql);
  933. TraceLeave(GLOBAL, "ClearPendingNotifications");
  934. }
  935. #pragma alloc_text(PAGE, StartStopDriver)
  936. NTSTATUS
  937. StartStopDriver(
  938. IN PIRP pIrp,
  939. IN ULONG ulInLength,
  940. IN ULONG ulOutLength
  941. )
  942. /*++
  943. Routine Description:
  944. This is the handler for IOCTL_IPMCAST_START_STOP. We do the normal
  945. buffer length checks.
  946. Locks:
  947. None
  948. Arguments:
  949. pIrp IRP
  950. ulInLength The length of the Input Buffer
  951. ulOutLength The length of the Output Buffer
  952. Return Value:
  953. STATUS_SUCCESS
  954. STATUS_BUFFER_TOO_SMALL
  955. --*/
  956. {
  957. PVOID pvIoBuffer;
  958. NTSTATUS nStatus;
  959. PDWORD pdwStart;
  960. TraceEnter(GLOBAL, "StartStopDriver");
  961. //
  962. // Get the user buffer
  963. //
  964. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  965. pdwStart = (PDWORD)pvIoBuffer;
  966. //
  967. // Always clean out the information field
  968. //
  969. pIrp->IoStatus.Information = 0;
  970. //
  971. // If we have dont even have enough for the basic MFE
  972. // there is something bad going on
  973. //
  974. if(ulInLength < sizeof(DWORD))
  975. {
  976. Trace(GLOBAL, ERROR,
  977. ("StartStopDriver: In Length %d is less than %d\n",
  978. ulInLength,
  979. sizeof(DWORD)));
  980. TraceLeave(GLOBAL, "StartStopDriver");
  981. return STATUS_BUFFER_TOO_SMALL;
  982. }
  983. if(*pdwStart)
  984. {
  985. nStatus = StartDriver();
  986. }
  987. else
  988. {
  989. nStatus = StopDriver();
  990. }
  991. TraceLeave(GLOBAL, "StartStopDriver");
  992. return nStatus;
  993. }
  994. #endif //IPMCAST