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.

956 lines
20 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. Revision History:
  6. --*/
  7. #include "allinc.h"
  8. PCHAR g_pszMsg[] = {
  9. "Packet Received",
  10. "MFE Deleted",
  11. "Wrong I/f Upcall"
  12. };
  13. DWORD
  14. QueueAsyncFunction(
  15. WORKERFUNCTION pfnFunction,
  16. PVOID pvContext,
  17. BOOL bAlertable
  18. );
  19. DWORD
  20. ValidateMfe(
  21. IN OUT PIPMCAST_MFE pMfe
  22. );
  23. VOID
  24. HandleRcvPkt(
  25. PVOID pvContext
  26. )
  27. /*++
  28. Routine Description:
  29. Locks:
  30. Arguments:
  31. Return Value:
  32. NO_ERROR
  33. --*/
  34. {
  35. PIP_HEADER pHdr;
  36. DWORD dwResult, dwOldIf;
  37. ULONG ulIndex;
  38. PIPMCAST_PKT_MSG pPktInfo;
  39. PIPMCAST_NOTIFICATION pMsg;
  40. ulIndex = PtrToUlong(pvContext);
  41. pMsg = &(g_rginMcastMsg[ulIndex].msg);
  42. pPktInfo = &(pMsg->ipmPkt);
  43. pHdr = (PIP_HEADER)(pPktInfo->rgbyData);
  44. Trace3(MCAST,
  45. "HandleRcvPkt: Rcvd pkt from %d.%d.%d.%d to %d.%d.%d.%d on %d",
  46. PRINT_IPADDR(pHdr->dwSrc),
  47. PRINT_IPADDR(pHdr->dwDest),
  48. pPktInfo->dwInIfIndex);
  49. dwResult = g_pfnMgmNewPacket(pHdr->dwSrc,
  50. pHdr->dwDest,
  51. pPktInfo->dwInIfIndex,
  52. pPktInfo->dwInNextHopAddress,
  53. pPktInfo->cbyDataLen,
  54. pPktInfo->rgbyData);
  55. if(dwResult isnot NO_ERROR)
  56. {
  57. Trace1(MCAST,
  58. "HandleRcvPkt: MGM returned error %d\n", dwResult);
  59. }
  60. PostNotificationForMcastEvents(&(g_rginMcastMsg[ulIndex]),
  61. g_hMcastEvents[ulIndex]);
  62. ExitRouterApi();
  63. }
  64. VOID
  65. HandleDeleteMfe(
  66. PVOID pvContext
  67. )
  68. /*++
  69. Routine Description:
  70. Locks:
  71. Arguments:
  72. Return Value:
  73. NO_ERROR
  74. --*/
  75. {
  76. DWORD dwResult;
  77. ULONG ulIndex, i;
  78. PIPMCAST_MFE_MSG pMfeInfo;
  79. PIPMCAST_NOTIFICATION pMsg;
  80. ulIndex = PtrToUlong(pvContext);
  81. pMsg = &(g_rginMcastMsg[ulIndex].msg);
  82. pMfeInfo = &(pMsg->immMfe);
  83. Trace1(MCAST,
  84. "HandleDeleteMfe: Kernel deleted %d MFEs\n",
  85. pMfeInfo->ulNumMfes);
  86. for(i = 0; i < pMfeInfo->ulNumMfes; i++)
  87. {
  88. Trace3(MCAST,
  89. "HandleDeleteMfe: Group %d.%d.%d.%d Source %d.%d.%d.%d/%d.%d.%d.%d\n",
  90. PRINT_IPADDR(pMsg->immMfe.idmMfe[i].dwGroup),
  91. PRINT_IPADDR(pMsg->immMfe.idmMfe[i].dwSource),
  92. PRINT_IPADDR(pMsg->immMfe.idmMfe[i].dwSrcMask));
  93. }
  94. dwResult = g_pfnMgmMfeDeleted(pMfeInfo->ulNumMfes,
  95. pMfeInfo->idmMfe);
  96. if(dwResult isnot NO_ERROR)
  97. {
  98. Trace1(MCAST,
  99. "HandleDeleteMfe: MGM returned error %d\n", dwResult);
  100. }
  101. PostNotificationForMcastEvents(&(g_rginMcastMsg[ulIndex]),
  102. g_hMcastEvents[ulIndex]);
  103. ExitRouterApi();
  104. }
  105. VOID
  106. HandleWrongIfUpcall(
  107. PVOID pvContext
  108. )
  109. /*++
  110. Routine Description:
  111. Locks:
  112. Arguments:
  113. Return Value:
  114. NO_ERROR
  115. --*/
  116. {
  117. PIP_HEADER pHdr;
  118. DWORD dwResult, dwOldIf;
  119. ULONG ulIndex;
  120. PIPMCAST_PKT_MSG pPktInfo;
  121. PIPMCAST_NOTIFICATION pMsg;
  122. ulIndex = PtrToUlong(pvContext);
  123. pMsg = &(g_rginMcastMsg[ulIndex].msg);
  124. pPktInfo = &(pMsg->ipmPkt);
  125. pHdr = (PIP_HEADER)(pPktInfo->rgbyData);
  126. Trace3(MCAST,
  127. "HandleWrongIfUpcall: Pkt from %d.%d.%d.%d to %d.%d.%d.%d on %d is wrong",
  128. PRINT_IPADDR(pHdr->dwSrc),
  129. PRINT_IPADDR(pHdr->dwDest),
  130. pPktInfo->dwInIfIndex);
  131. dwResult = g_pfnMgmWrongIf(pHdr->dwSrc,
  132. pHdr->dwDest,
  133. pPktInfo->dwInIfIndex,
  134. pPktInfo->dwInNextHopAddress,
  135. pPktInfo->cbyDataLen,
  136. pPktInfo->rgbyData);
  137. if(dwResult isnot NO_ERROR)
  138. {
  139. Trace1(MCAST,
  140. "HandleWrongIfUpcall: MGM returned error %d\n", dwResult);
  141. }
  142. PostNotificationForMcastEvents(&(g_rginMcastMsg[ulIndex]),
  143. g_hMcastEvents[ulIndex]);
  144. ExitRouterApi();
  145. }
  146. VOID
  147. HandleMcastNotification(
  148. DWORD dwIndex
  149. )
  150. /*++
  151. Routine Description:
  152. Locks:
  153. Arguments:
  154. Return Value:
  155. NO_ERROR
  156. --*/
  157. {
  158. DWORD dwResult;
  159. ULONG i;
  160. PIPMCAST_NOTIFICATION pMsg;
  161. pMsg = &(g_rginMcastMsg[dwIndex].msg);
  162. //
  163. // read the notification
  164. //
  165. Trace1(MCAST,
  166. "HandleMcastNotification: Notification received for %s\n",
  167. g_pszMsg[pMsg->dwEvent]);
  168. switch(pMsg->dwEvent)
  169. {
  170. case IPMCAST_RCV_PKT_MSG:
  171. {
  172. QueueAsyncFunction(HandleRcvPkt,
  173. (PVOID)(ULONG_PTR)dwIndex,
  174. FALSE);
  175. break;
  176. }
  177. case IPMCAST_DELETE_MFE_MSG:
  178. {
  179. QueueAsyncFunction(HandleDeleteMfe,
  180. (PVOID)(ULONG_PTR)dwIndex,
  181. FALSE);
  182. break;
  183. }
  184. case IPMCAST_WRONG_IF_MSG:
  185. {
  186. QueueAsyncFunction(HandleWrongIfUpcall,
  187. (PVOID)(ULONG_PTR)dwIndex,
  188. FALSE);
  189. break;
  190. }
  191. default:
  192. {
  193. Trace1(MCAST,
  194. "HandleMcastNotification: Bad event code %d\n",
  195. pMsg->dwEvent);
  196. PostNotificationForMcastEvents(&(g_rginMcastMsg[dwIndex]),
  197. g_hMcastEvents[dwIndex]);
  198. break;
  199. }
  200. }
  201. }
  202. VOID
  203. PostNotificationForMcastEvents(
  204. PMCAST_OVERLAPPED pOverlapped,
  205. HANDLE hEvent
  206. )
  207. /*++
  208. Routine Description:
  209. Locks:
  210. Arguments:
  211. Return Value:
  212. NO_ERROR
  213. --*/
  214. {
  215. NTSTATUS nsStatus;
  216. nsStatus = SendIoctlToMcastDevice(IOCTL_IPMCAST_POST_NOTIFICATION,
  217. hEvent,
  218. &pOverlapped->ioStatus,
  219. &pOverlapped->msg,
  220. sizeof(IPMCAST_NOTIFICATION),
  221. &pOverlapped->msg,
  222. sizeof(IPMCAST_NOTIFICATION));
  223. if((nsStatus isnot STATUS_SUCCESS) and
  224. (nsStatus isnot STATUS_PENDING))
  225. {
  226. Trace1(ERR,
  227. "PostNotificationForMcastEvents: Error %X",
  228. nsStatus);
  229. }
  230. }
  231. DWORD
  232. SendIoctlToMcastDevice(
  233. DWORD dwIoctl,
  234. HANDLE hEvent,
  235. PIO_STATUS_BLOCK pIoStatus,
  236. PVOID pvInBuffer,
  237. DWORD dwInBufLen,
  238. PVOID pvOutBuffer,
  239. DWORD dwOutBufLen
  240. )
  241. {
  242. NTSTATUS ntStatus;
  243. ntStatus = NtDeviceIoControlFile(g_hMcastDevice,
  244. hEvent,
  245. NULL,
  246. NULL,
  247. pIoStatus,
  248. dwIoctl,
  249. pvInBuffer,
  250. dwInBufLen,
  251. pvOutBuffer,
  252. dwOutBufLen);
  253. return ntStatus;
  254. }
  255. DWORD
  256. SetMfe(
  257. PIPMCAST_MFE pMfe
  258. )
  259. /*++
  260. Routine Description:
  261. Locks:
  262. Arguments:
  263. Return Value:
  264. NO_ERROR
  265. --*/
  266. {
  267. DWORD dwResult;
  268. IO_STATUS_BLOCK ioStatus;
  269. dwResult = ValidateMfe(pMfe);
  270. if(dwResult isnot NO_ERROR)
  271. {
  272. //
  273. // Something bad happened while validating the MFE
  274. //
  275. Trace1(ERR,
  276. "SetMfe: Error %d validating MFE",
  277. dwResult);
  278. return dwResult;
  279. }
  280. dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_SET_MFE,
  281. NULL,
  282. &ioStatus,
  283. pMfe,
  284. SIZEOF_MFE(pMfe->ulNumOutIf),
  285. NULL,
  286. 0);
  287. if(dwResult isnot NO_ERROR)
  288. {
  289. Trace1(MCAST,
  290. "SetMfe: NtStatus %x while setting MFE",
  291. dwResult);
  292. }
  293. return dwResult;
  294. }
  295. DWORD
  296. GetMfe(
  297. PIPMCAST_MFE_STATS pMfeStats
  298. )
  299. {
  300. DWORD dwResult;
  301. IO_STATUS_BLOCK ioStatus;
  302. dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_GET_MFE,
  303. NULL,
  304. &ioStatus,
  305. pMfeStats,
  306. SIZEOF_MFE_STATS(pMfeStats->ulNumOutIf),
  307. pMfeStats,
  308. SIZEOF_MFE_STATS(pMfeStats->ulNumOutIf));
  309. if(dwResult isnot NO_ERROR)
  310. {
  311. Trace1(MCAST,
  312. "GetMfe: NtStatus %x while getting MFE",
  313. dwResult);
  314. }
  315. return dwResult;
  316. }
  317. DWORD
  318. DeleteMfe(
  319. PIPMCAST_DELETE_MFE pDelMfe
  320. )
  321. {
  322. DWORD dwResult;
  323. IO_STATUS_BLOCK ioStatus;
  324. dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_DELETE_MFE,
  325. NULL,
  326. &ioStatus,
  327. pDelMfe,
  328. sizeof(IPMCAST_DELETE_MFE),
  329. NULL,
  330. 0);
  331. if(dwResult isnot NO_ERROR)
  332. {
  333. Trace1(MCAST,
  334. "DeleteMfe: NtStatus %x while deleting MFE",
  335. dwResult);
  336. }
  337. return dwResult;
  338. }
  339. DWORD
  340. ActivateMcastLimits(
  341. PICB picb
  342. )
  343. {
  344. DWORD dwResult;
  345. IO_STATUS_BLOCK ioStatus;
  346. IPMCAST_IF_TTL iitTtl;
  347. DWORD dwTtl = picb->dwMcastTtl;
  348. // Set the TTL threshold
  349. iitTtl.dwIfIndex = picb->dwIfIndex;
  350. iitTtl.byTtl = LOBYTE(LOWORD(dwTtl));
  351. dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_SET_TTL,
  352. NULL,
  353. &ioStatus,
  354. &iitTtl,
  355. sizeof(IPMCAST_IF_TTL),
  356. NULL,
  357. 0);
  358. if(dwResult isnot NO_ERROR)
  359. {
  360. Trace2(ERR,
  361. "SetMcastTtl: NtStatus %x from SendIoctl when setting TTL for %S",
  362. dwResult,
  363. picb->pwszName);
  364. return ERROR_CAN_NOT_COMPLETE;
  365. }
  366. //
  367. // Set the rate limit for multicast traffic on an interface.
  368. // Currently, the kernel does not support rate limiting.
  369. //
  370. return NO_ERROR;
  371. }
  372. DWORD
  373. SetMcastLimits(
  374. PICB picb,
  375. DWORD dwTtl,
  376. DWORD dwRateLimit
  377. )
  378. {
  379. if (dwTtl > 255)
  380. {
  381. Trace2(ERR,
  382. "SetMcastTtl: TTL for %S is %d which is invalid",
  383. picb->pwszName,
  384. dwTtl);
  385. return ERROR_INVALID_DATA;
  386. }
  387. picb->dwMcastTtl = dwTtl;
  388. //
  389. // Set the rate limit for multicast traffic on an interface.
  390. // Currently, the kernel does not support rate limiting, so
  391. // the only valid value is 0 (=none).
  392. //
  393. if (dwRateLimit != 0)
  394. {
  395. Trace2(ERR,
  396. "SetMcastRateLimit: RateLimit for %S is %d which is invalid",
  397. picb->pwszName,
  398. dwRateLimit);
  399. return ERROR_INVALID_DATA;
  400. }
  401. picb->dwMcastRateLimit = dwRateLimit;
  402. if ( picb->dwOperationalState is IF_OPER_STATUS_OPERATIONAL )
  403. {
  404. return ActivateMcastLimits(picb);
  405. }
  406. return NO_ERROR;
  407. }
  408. DWORD
  409. SetMcastLimitInfo(
  410. PICB picb,
  411. PRTR_INFO_BLOCK_HEADER pInfoHdr
  412. )
  413. /*++
  414. Routine Description:
  415. Sets the TTL and rate limit info associated with an interface.
  416. Arguments:
  417. picb The ICB of the interface
  418. Called by:
  419. AddInterface() in iprtrmgr.c
  420. SetInterfaceInfo() in iprtrmgr.c
  421. Locks:
  422. BOUNDARY_TABLE for writing
  423. --*/
  424. {
  425. DWORD dwResult = NO_ERROR,
  426. i, j;
  427. PRTR_TOC_ENTRY pToc;
  428. PMIB_MCAST_LIMIT_ROW pLimit;
  429. BOOL bFound;
  430. Trace1( MCAST, "ENTERED SetMcastLimitInfo for If %x", picb->dwIfIndex );
  431. pToc = GetPointerToTocEntry(IP_MCAST_LIMIT_INFO, pInfoHdr);
  432. if (pToc is NULL)
  433. {
  434. // No TOC means no change
  435. Trace0( MCAST, "LEFT SetMcastLimitInfo" );
  436. return NO_ERROR;
  437. }
  438. pLimit = (PMIB_MCAST_LIMIT_ROW)GetInfoFromTocEntry(pInfoHdr, pToc);
  439. if (pLimit is NULL)
  440. {
  441. Trace0( MCAST, "LEFT SetMcastLimitInfo" );
  442. return NO_ERROR;
  443. }
  444. dwResult = SetMcastLimits( picb, pLimit->dwTtl, pLimit->dwRateLimit );
  445. Trace0( MCAST, "LEFT SetMcastLimitInfo" );
  446. return dwResult;
  447. }
  448. DWORD
  449. SetMcastOnIf(
  450. PICB picb,
  451. BOOL bActivate
  452. )
  453. {
  454. DWORD dwResult;
  455. IO_STATUS_BLOCK ioStatus;
  456. IPMCAST_IF_STATE iisState;
  457. iisState.dwIfIndex = picb->dwIfIndex;
  458. iisState.byState = bActivate?1:0;
  459. dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_SET_IF_STATE,
  460. NULL,
  461. &ioStatus,
  462. &iisState,
  463. sizeof(IPMCAST_IF_STATE),
  464. NULL,
  465. 0);
  466. if(dwResult isnot NO_ERROR)
  467. {
  468. Trace2(ERR,
  469. "SetMcastOnIf: NtStatus %x from SendIoctl for %S",
  470. dwResult,
  471. picb->pwszName);
  472. return ERROR_CAN_NOT_COMPLETE;
  473. }
  474. return NO_ERROR;
  475. }
  476. DWORD
  477. StartMulticast(
  478. VOID
  479. )
  480. /*++
  481. Routine Description:
  482. Locks:
  483. Arguments:
  484. Return Value:
  485. NO_ERROR
  486. --*/
  487. {
  488. DWORD i, dwStart;
  489. NTSTATUS nStatus;
  490. IO_STATUS_BLOCK ioStatus;
  491. dwStart = 1;
  492. nStatus = SendIoctlToMcastDevice(IOCTL_IPMCAST_START_STOP,
  493. NULL,
  494. &ioStatus,
  495. &dwStart,
  496. sizeof(DWORD),
  497. NULL,
  498. 0);
  499. if(nStatus isnot STATUS_SUCCESS)
  500. {
  501. Trace1(MCAST, "StartMulticast: Error %x starting driver",
  502. nStatus);
  503. return ERROR_OPEN_FAILED;
  504. }
  505. for(i = 0; i < NUM_MCAST_IRPS; i++)
  506. {
  507. PostNotificationForMcastEvents(&(g_rginMcastMsg[i]),
  508. g_hMcastEvents[i]);
  509. }
  510. // Start up mrinfo and mtrace services
  511. StartMcMisc();
  512. return NO_ERROR;
  513. }
  514. DWORD
  515. ValidateMfe(
  516. IN OUT PIPMCAST_MFE pMfe
  517. )
  518. /*++
  519. Routine Description:
  520. Locks:
  521. Arguments:
  522. Return Value:
  523. NO_ERROR
  524. --*/
  525. {
  526. PADAPTER_INFO pBinding;
  527. ULONG i;
  528. ENTER_READER(BINDING_LIST);
  529. //
  530. // First find the interface index for incoming i/f
  531. // If there are no outgoing interfaces, then this is a NEGATIVE
  532. // MFE and the incoming interface index must be 0 (and need not
  533. // be mapped)
  534. //
  535. #if DBG
  536. if(pMfe->ulNumOutIf is 0)
  537. {
  538. IpRtAssert(pMfe->dwInIfIndex is 0);
  539. pMfe->dwInIfIndex = 0;
  540. }
  541. #endif
  542. for(i = 0; i < pMfe->ulNumOutIf; i++)
  543. {
  544. pBinding = GetInterfaceBinding(pMfe->rgioOutInfo[i].dwOutIfIndex);
  545. if(!pBinding)
  546. {
  547. Trace1(ERR,
  548. "ValidateMfe: Unable to find binding for outgoing i/f %d",
  549. pMfe->rgioOutInfo[i].dwOutIfIndex);
  550. EXIT_LOCK(BINDING_LIST);
  551. return ERROR_INVALID_INDEX;
  552. }
  553. if(pBinding->bBound)
  554. {
  555. //
  556. // valid index
  557. //
  558. pMfe->rgioOutInfo[i].dwOutIfIndex = pBinding->dwIfIndex;
  559. }
  560. else
  561. {
  562. //
  563. // Demand dial interface
  564. //
  565. pMfe->rgioOutInfo[i].dwOutIfIndex = INVALID_IF_INDEX;
  566. pMfe->rgioOutInfo[i].dwDialContext = pBinding->dwSeqNumber;
  567. }
  568. }
  569. EXIT_LOCK(BINDING_LIST);
  570. return NO_ERROR;
  571. }
  572. DWORD
  573. GetInterfaceMcastCounters(
  574. IN PICB picb,
  575. OUT PIP_MCAST_COUNTER_INFO pOutBuffer
  576. )
  577. {
  578. DWORD dwAdapterId,dwResult;
  579. PPROTO_CB pcbOwner;
  580. IO_STATUS_BLOCK ioStatus;
  581. ULONG Request = picb->dwIfIndex;
  582. HANDLE hEvent;
  583. dwResult = NO_ERROR;
  584. hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  585. if(hEvent is NULL)
  586. {
  587. dwResult = GetLastError();
  588. Trace1(ERR,
  589. "GetInterfaceMcastCounters: Error %d creating event",
  590. dwResult);
  591. return dwResult;
  592. }
  593. dwResult = NtDeviceIoControlFile(g_hIpDevice,
  594. hEvent,
  595. NULL,
  596. NULL,
  597. &ioStatus,
  598. IOCTL_IP_GET_MCAST_COUNTERS,
  599. &Request,
  600. sizeof(Request),
  601. pOutBuffer,
  602. sizeof(IP_MCAST_COUNTER_INFO));
  603. if(dwResult is STATUS_PENDING)
  604. {
  605. Trace0(ERR,
  606. "GetInterfaceMcastCounters: Pending from ioctl");
  607. dwResult = WaitForSingleObject(hEvent,
  608. INFINITE);
  609. if(dwResult isnot WAIT_OBJECT_0) // 0
  610. {
  611. Trace1(ERR,
  612. "GetInterfaceMcastCounters: Error %d from wait",
  613. dwResult);
  614. dwResult = GetLastError();
  615. }
  616. else
  617. {
  618. dwResult = STATUS_SUCCESS;
  619. }
  620. }
  621. return dwResult;
  622. }
  623. DWORD
  624. GetInterfaceMcastStatistics(
  625. IN PICB picb,
  626. OUT PMIB_IPMCAST_IF_ENTRY pOutBuffer
  627. )
  628. {
  629. DWORD dwAdapterId,dwResult;
  630. PPROTO_CB pcbOwner;
  631. IO_STATUS_BLOCK ioStatus;
  632. IP_MCAST_COUNTER_INFO ifStats;
  633. dwResult = NO_ERROR;
  634. TraceEnter("GetInterfaceMcastStatistics");
  635. pOutBuffer->dwIfIndex = picb->dwIfIndex;
  636. pOutBuffer->dwTtl = picb->dwMcastTtl;
  637. pOutBuffer->dwRateLimit = 0; // XXX change when we have rate limiting
  638. dwResult = GetInterfaceMcastCounters(picb, &ifStats);
  639. if (dwResult isnot STATUS_SUCCESS)
  640. {
  641. return dwResult;
  642. }
  643. pOutBuffer->ulOutMcastOctets = (ULONG)ifStats.OutMcastOctets;
  644. pOutBuffer->ulInMcastOctets = (ULONG)ifStats.InMcastOctets;
  645. pOutBuffer->dwProtocol = 2; // "local" (static only) is default
  646. dwResult = MulticastOwner(picb, &pcbOwner, NULL);
  647. if (dwResult == NO_ERROR && pcbOwner != NULL) {
  648. switch(pcbOwner->dwProtocolId) {
  649. #ifdef MS_IP_DVMRP
  650. case MS_IP_DVMRP: pOutBuffer->dwProtocol = 4; break;
  651. #endif
  652. #ifdef MS_IP_MOSPF
  653. case MS_IP_MOSPF: pOutBuffer->dwProtocol = 5; break;
  654. #endif
  655. #ifdef MS_IP_CBT
  656. case MS_IP_CBT : pOutBuffer->dwProtocol = 7; break;
  657. #endif
  658. #ifdef MS_IP_PIMSM
  659. case MS_IP_PIMSM: pOutBuffer->dwProtocol = 8; break;
  660. #endif
  661. #ifdef MS_IP_PIMDM
  662. case MS_IP_PIMDM: pOutBuffer->dwProtocol = 9; break;
  663. #endif
  664. case MS_IP_IGMP : pOutBuffer->dwProtocol = 10; break;
  665. }
  666. }
  667. TraceLeave("GetInterfaceMcastStatistics");
  668. return dwResult;
  669. }
  670. DWORD
  671. SetInterfaceMcastStatistics(
  672. IN PICB picb,
  673. IN PMIB_IPMCAST_IF_ENTRY lpInBuffer
  674. )
  675. {
  676. DWORD dwResult = NO_ERROR;
  677. TraceEnter("SetInterfaceMcastStatistics");
  678. dwResult = SetMcastLimits(picb, lpInBuffer->dwTtl, lpInBuffer->dwRateLimit);
  679. if(dwResult isnot NO_ERROR) {
  680. Trace2(ERR,
  681. "SetInterfaceStatistics: Error %d setting %S",
  682. dwResult,
  683. picb->pwszName);
  684. }
  685. TraceLeave("SetInterfaceMcastStatistics");
  686. return dwResult;
  687. }