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.

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