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.

1286 lines
42 KiB

  1. //=============================================================================
  2. // Copyright (c) 1997 Microsoft Corporation
  3. // File Name: mgmigmp.c
  4. //
  5. // Abstract:
  6. // This file the calls and callbacks with respect to mgm
  7. //
  8. // Author: K.S.Lokesh (lokeshs@) 11-1-97
  9. //=============================================================================
  10. #include "pchigmp.h"
  11. #pragma hdrstop
  12. VOID
  13. DebugPrintProxyGroupTable (
  14. );
  15. #define DISABLE_FLAG 0
  16. #define ENABLE_FLAG 1
  17. //------------------------------------------------------------------------------
  18. // _MgmDisableIgmprtrCallback
  19. //
  20. // This call is made by mgm to igmp. After this call, till igmp is enabled
  21. // again, no more AddMembership calls will be made to Mgm. However, igmp
  22. // will be owning the interface and will be functioning normally.
  23. //------------------------------------------------------------------------------
  24. DWORD
  25. MgmDisableIgmprtrCallback(
  26. DWORD IfIndex,
  27. DWORD NHAddr //not used
  28. )
  29. {
  30. return MgmChangeIgmprtrStatus(IfIndex, DISABLE_FLAG);
  31. }
  32. //------------------------------------------------------------------------------
  33. // _MgmEnableIgmprtrCallback
  34. //
  35. // This call is made by mgm to igmprtr. igmprtr should refresh all group joins.
  36. //------------------------------------------------------------------------------
  37. DWORD
  38. MgmEnableIgmprtrCallback(
  39. DWORD IfIndex,
  40. DWORD NHAddr //not used
  41. )
  42. {
  43. return MgmChangeIgmprtrStatus(IfIndex, ENABLE_FLAG);
  44. }
  45. //------------------------------------------------------------------------------
  46. // MgmChangeIgmprtrStatus
  47. //------------------------------------------------------------------------------
  48. DWORD
  49. MgmChangeIgmprtrStatus (
  50. DWORD IfIndex,
  51. BOOL Flag
  52. )
  53. {
  54. PIF_TABLE_ENTRY pite;
  55. DWORD Error=NO_ERROR, dwRetval;
  56. BOOL PrevCanAddGroupsToMgm;
  57. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  58. Trace0(ENTER1, "Entering MgmDisableIgmpCallback");
  59. ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "MgmDisableIgmpCallback");
  60. BEGIN_BREAKOUT_BLOCK1 {
  61. //
  62. // retrieve the interface entry
  63. //
  64. pite = GetIfByIndex(IfIndex);
  65. //
  66. // return error if interface does not exist, or it is not activated
  67. // or is already in that state
  68. //
  69. if ( (pite == NULL)||(!IS_IF_ACTIVATED(pite))
  70. || ((Flag==ENABLE_FLAG)&&(IS_IGMPRTR_ENABLED_BY_MGM(pite)))
  71. || ((Flag==DISABLE_FLAG)&&(!IS_IGMPRTR_ENABLED_BY_MGM(pite)))
  72. )
  73. {
  74. if (Flag==ENABLE_FLAG) {
  75. Trace1(ERR,
  76. "MgmEnableIgmpCallback(): interface:%0x nonexistant or active",
  77. IfIndex);
  78. IgmpAssertOnError(FALSE);
  79. }
  80. else {
  81. Trace1(ERR,
  82. "MgmDisableIgmpCallback(): interface:%0x nonexistant or inactive",
  83. IfIndex);
  84. IgmpAssertOnError(FALSE);
  85. }
  86. Error = ERROR_INVALID_PARAMETER;
  87. GOTO_END_BLOCK1;
  88. }
  89. PrevCanAddGroupsToMgm = CAN_ADD_GROUPS_TO_MGM(pite);
  90. if (Flag==ENABLE_FLAG) {
  91. DWORD dwProtoId, dwComponentId;
  92. // set the status field to enabled.
  93. MGM_ENABLE_IGMPRTR(pite);
  94. MgmGetProtocolOnInterface(IfIndex, 0, &dwProtoId, &dwComponentId);
  95. if (dwProtoId!=PROTO_IP_IGMP)
  96. SET_MPROTOCOL_PRESENT_ON_IGMPRTR(pite);
  97. }
  98. else {
  99. // set the flag to disabled and also reset MProtocol present field
  100. MGM_DISABLE_IGMPRTR(pite);
  101. }
  102. if (PrevCanAddGroupsToMgm && !CAN_ADD_GROUPS_TO_MGM(pite))
  103. Trace1(MGM, "Igmp Router stop propagating groups to MGM on If:%0x",
  104. IfIndex);
  105. if (!PrevCanAddGroupsToMgm && CAN_ADD_GROUPS_TO_MGM(pite))
  106. Trace1(MGM, "Igmp Router start propagating groups to MGM on If:%0x",
  107. IfIndex);
  108. //
  109. // for all the groups for this interface, call MgmDeleteGroupMembershipEntry
  110. //
  111. if (CAN_ADD_GROUPS_TO_MGM(pite)) {
  112. if (Flag==ENABLE_FLAG)
  113. RefreshMgmIgmprtrGroups(pite, ADD_FLAG);
  114. else
  115. RefreshMgmIgmprtrGroups(pite, DELETE_FLAG);
  116. }
  117. } END_BREAKOUT_BLOCK1;
  118. RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "MgmDisableIgmpCallback");
  119. Trace1(LEAVE1, "Leaving MgmDisableIgmpCallback(%d)", Error);
  120. LeaveIgmpApi();
  121. return Error;
  122. }
  123. //------------------------------------------------------------------------------
  124. // RefreshMgmIgmprtrGroups
  125. //------------------------------------------------------------------------------
  126. DWORD
  127. RefreshMgmIgmprtrGroups (
  128. PIF_TABLE_ENTRY pite,
  129. BOOL Flag
  130. )
  131. {
  132. PLIST_ENTRY pHead, ple;
  133. PGI_ENTRY pgie;
  134. DWORD Error=NO_ERROR;
  135. PGI_SOURCE_ENTRY pSourceEntry;
  136. ACQUIRE_ENUM_LOCK_EXCLUSIVE("_RefreshMgmIgmprtrGroups");
  137. ACQUIRE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_RefreshMgmIgmprtrGroups");
  138. pHead = &pite->ListOfSameIfGroups;
  139. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  140. pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
  141. if (Flag==ADD_FLAG) {
  142. if (pgie->Version==1 || pgie->Version==2
  143. || (pgie->Version==3 && pgie->FilterType==EXCLUSION) )
  144. {
  145. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr, 0, 0,
  146. pgie->pGroupTableEntry->Group,
  147. 0xffffffff, MGM_JOIN_STATE_FLAG);
  148. }
  149. else {//ver3 inclusion
  150. PLIST_ENTRY pSourceHead, pSourceLE;
  151. pSourceHead = &pgie->V3InclusionListSorted;
  152. for (pSourceLE=pSourceHead->Flink; pSourceLE!=pSourceHead;
  153. pSourceLE=pSourceLE->Flink)
  154. {
  155. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
  156. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr, pSourceEntry->IpAddr, 0xffffffff,
  157. pgie->pGroupTableEntry->Group,
  158. 0xffffffff, MGM_JOIN_STATE_FLAG);
  159. }
  160. }
  161. }
  162. else {
  163. if (pgie->Version==1 || pgie->Version==2
  164. || (pgie->Version==3 && pgie->FilterType==EXCLUSION) )
  165. {
  166. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr, 0, 0,
  167. pgie->pGroupTableEntry->Group,
  168. 0xffffffff, MGM_JOIN_STATE_FLAG);
  169. }
  170. else {//ver3 inclusion
  171. PLIST_ENTRY pSourceHead, pSourceLE;
  172. pSourceHead = &pgie->V3InclusionListSorted;
  173. for (pSourceLE=pSourceHead->Flink; pSourceLE!=pSourceHead;
  174. pSourceLE=pSourceLE->Flink)
  175. {
  176. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
  177. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr,
  178. pSourceEntry->IpAddr, 0xffffffff,
  179. pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG);
  180. }
  181. }
  182. }
  183. }
  184. RELEASE_ENUM_LOCK_EXCLUSIVE("_RefreshMgmIgmprtrGroups");
  185. RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_RefreshMgmIgmprtrGroups");
  186. return Error;
  187. }
  188. //------------------------------------------------------------------------------
  189. // RegisterProtocolWithMgm
  190. //------------------------------------------------------------------------------
  191. DWORD
  192. RegisterProtocolWithMgm(
  193. DWORD ProxyOrRouter
  194. )
  195. {
  196. DWORD Error=NO_ERROR;
  197. ROUTING_PROTOCOL_CONFIG rpiInfo; //for mgm
  198. // register router with mgm
  199. if (ProxyOrRouter==PROTO_IP_IGMP) {
  200. ZeroMemory(&rpiInfo, sizeof(rpiInfo));
  201. rpiInfo.dwCallbackFlags = 0;
  202. rpiInfo.pfnRpfCallback
  203. = (PMGM_RPF_CALLBACK)IgmpRpfCallback;
  204. rpiInfo.pfnCreationAlertCallback
  205. = (PMGM_CREATION_ALERT_CALLBACK)IgmpRtrCreationAlertCallback;
  206. rpiInfo.pfnPruneAlertCallback
  207. = NULL;
  208. rpiInfo.pfnJoinAlertCallback
  209. = NULL;
  210. rpiInfo.pfnWrongIfCallback
  211. = NULL;
  212. rpiInfo.pfnLocalJoinCallback
  213. = NULL;
  214. rpiInfo.pfnLocalLeaveCallback
  215. = NULL;
  216. rpiInfo.pfnEnableIgmpCallback
  217. = MgmEnableIgmprtrCallback;
  218. rpiInfo.pfnDisableIgmpCallback
  219. = MgmDisableIgmprtrCallback;
  220. Error = MgmRegisterMProtocol( &rpiInfo, PROTO_IP_IGMP, IGMP_ROUTER_V2,
  221. &g_MgmIgmprtrHandle);
  222. if (Error!=NO_ERROR) {
  223. Trace1(ERR, "Error:%d registering IGMP Router with MGM", Error);
  224. IgmpAssertOnError(FALSE);
  225. Logerr0(MGM_REGISTER_FAILED, Error);
  226. return Error;
  227. }
  228. }
  229. // register proxy with mgm
  230. else {
  231. //
  232. // register Igmp proxy with MGM. I register Proxy irrespective of whether
  233. // this router might be setup as a proxy or not.
  234. //
  235. rpiInfo.dwCallbackFlags = 0;
  236. rpiInfo.pfnRpfCallback
  237. = (PMGM_RPF_CALLBACK)ProxyRpfCallback;
  238. rpiInfo.pfnCreationAlertCallback
  239. = (PMGM_CREATION_ALERT_CALLBACK)ProxyCreationAlertCallback;
  240. rpiInfo.pfnPruneAlertCallback
  241. = (PMGM_PRUNE_ALERT_CALLBACK)ProxyPruneAlertCallback;
  242. rpiInfo.pfnJoinAlertCallback
  243. = (PMGM_JOIN_ALERT_CALLBACK)ProxyJoinAlertCallback;
  244. rpiInfo.pfnWrongIfCallback
  245. = NULL;
  246. rpiInfo.pfnLocalJoinCallback
  247. = NULL;
  248. rpiInfo.pfnLocalLeaveCallback
  249. = NULL;
  250. Error = MgmRegisterMProtocol( &rpiInfo, PROTO_IP_IGMP_PROXY, IGMP_PROXY,
  251. &g_MgmProxyHandle);
  252. if (Error!=NO_ERROR) {
  253. Trace1(ERR, "Error:%d registering Igmp Proxy with Mgm", Error);
  254. IgmpAssertOnError(FALSE);
  255. Logerr0(MGM_PROXY_REGISTER_FAILED, Error);
  256. return Error;
  257. }
  258. }
  259. return Error;
  260. }
  261. //------------------------------------------------------------------------------
  262. // IgmpRpfCallback
  263. //------------------------------------------------------------------------------
  264. DWORD
  265. IgmpRpfCallback (
  266. DWORD dwSourceAddr,
  267. DWORD dwSourceMask,
  268. DWORD dwGroupAddr,
  269. DWORD dwGroupMask,
  270. PDWORD dwInIfIndex,
  271. PDWORD dwInIfNextHopAddr,
  272. PDWORD dwUpstreamNeighbor,
  273. DWORD dwHdrSize,
  274. PBYTE pbPacketHdr,
  275. PBYTE pbBuffer
  276. )
  277. /*++
  278. Routine Description:
  279. Called by MGM when a packet is received on an interface owned by Igmp to see
  280. if it can go ahead and create an MFE. Igmp does an Rpf check with RTM
  281. and returns the value. No check is done to see if the interface is really
  282. owned by igmp. It doesnt matter if the interface is activated or not.
  283. --*/
  284. {
  285. DWORD Error = NO_ERROR;
  286. #if RTMv2
  287. return Error;
  288. #else
  289. PRTM_IP_ROUTE prirRpfRoute = (PRTM_IP_ROUTE) pbBuffer;
  290. // enterIgmpApi not required, as this call cannot be made when igmp is not up
  291. //
  292. // Perform Rpf check with Rtm
  293. //
  294. if (RtmLookupIPDestination(dwSourceAddr, prirRpfRoute)==TRUE) {
  295. if (prirRpfRoute->RR_InterfaceID!=*dwInIfIndex) {
  296. *dwInIfIndex = prirRpfRoute->RR_InterfaceID;
  297. // the route was found, but the interface is incorrect
  298. Error = ERROR_INVALID_PARAMETER;
  299. }
  300. else {
  301. // rpf check successful
  302. Error = NO_ERROR;
  303. }
  304. }
  305. else {
  306. // route not found
  307. Error = ERROR_NOT_FOUND;
  308. }
  309. Trace4(MGM,
  310. "Rpf callback for MGroup(%d.%d.%d.%d) Src(%d.%d.%d.%d) IncomingIf(%0x):%d",
  311. PRINT_IPADDR(dwGroupAddr), PRINT_IPADDR(dwSourceAddr), *dwInIfIndex, Error);
  312. return Error;
  313. #endif
  314. }
  315. //------------------------------------------------------------------------------
  316. // ProxyRpfCallback
  317. //------------------------------------------------------------------------------
  318. DWORD
  319. ProxyRpfCallback (
  320. DWORD dwSourceAddr,
  321. DWORD dwSourceMask,
  322. DWORD dwGroupAddr,
  323. DWORD dwGroupMask,
  324. DWORD *dwInIfIndex,
  325. DWORD *dwInIfNextHopAddr,
  326. DWORD *dwUpstreamNeighbor,
  327. DWORD dwHdrSize,
  328. PBYTE pbPacketHdr,
  329. PBYTE pbBuffer
  330. )
  331. /*++
  332. Routine Description:
  333. Called by MGM when a packet is received on an interface owned by Proxy to see
  334. if it can go ahead and create an MFE. Proxy does an Rpf check with RTM
  335. and returns the value. No check is done to see if the interface is really
  336. owned by igmp. It doesnt matter if the interface is activated or not.
  337. --*/
  338. {
  339. DWORD Error = NO_ERROR;
  340. #if RTMv2
  341. return Error;
  342. #else
  343. // enterIgmpApi not required, as this call cannot be made when igmp is not up
  344. PRTM_IP_ROUTE prirRpfRoute = (PRTM_IP_ROUTE) pbBuffer;
  345. //
  346. // Perform Rpf check with Rtm
  347. //
  348. if (RtmLookupIPDestination(dwSourceAddr, prirRpfRoute)==TRUE) {
  349. if (prirRpfRoute->RR_InterfaceID!=*dwInIfIndex) {
  350. *dwInIfIndex = prirRpfRoute->RR_InterfaceID;
  351. // the route was found, but the interface is incorrect
  352. Error = ERROR_INVALID_PARAMETER;
  353. }
  354. else {
  355. // rpf check successful
  356. Error = NO_ERROR;
  357. }
  358. }
  359. else {
  360. // route not found
  361. Error = ERROR_NOT_FOUND;
  362. }
  363. Trace4(MGM,
  364. "Rpf callback for MGroup(%d.%d.%d.%d) Src(%d.%d.%d.%d) IncomingIf(%0x):%d",
  365. PRINT_IPADDR(dwGroupAddr), PRINT_IPADDR(dwSourceAddr), *dwInIfIndex, Error);
  366. return Error;
  367. #endif
  368. }
  369. //------------------------------------------------------------------------------
  370. // IgmpRtrCreationAlertCallback
  371. //------------------------------------------------------------------------------
  372. DWORD
  373. IgmpRtrCreationAlertCallback (
  374. DWORD Source,
  375. DWORD dwSourceMask,
  376. DWORD Group,
  377. DWORD dwGroupMask,
  378. DWORD dwInIfIndex,
  379. DWORD dwInIfNextHopAddr,
  380. DWORD dwIfCount,
  381. PMGM_IF_ENTRY Oif
  382. )
  383. /*++
  384. Routine Description:
  385. Called when the first interface owned by some other protocol joins any group.
  386. This routine does nothing, as igmp does not send any joins upstream.
  387. Return Value:
  388. NO_ERROR
  389. --*/
  390. {
  391. DWORD i, IfIndex, NextHop;
  392. DWORD Error=NO_ERROR;
  393. PIF_TABLE_ENTRY pite;
  394. PGROUP_TABLE_ENTRY pge;
  395. PGI_ENTRY pgie;
  396. PGI_SOURCE_ENTRY pSourceEntry;
  397. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  398. for (i=0; i<dwIfCount; i++) {
  399. IfIndex = Oif[i].dwIfIndex;
  400. NextHop = Oif[i].dwIfNextHopAddr;
  401. if (!Oif[i].bIGMP)
  402. continue;
  403. ACQUIRE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
  404. //
  405. // retrieve the interface
  406. //
  407. pite = GetIfByIndex(IfIndex);
  408. if ( (pite==NULL) || !IS_IF_ACTIVATED(pite) ) {
  409. Oif[i].bIsEnabled = FALSE;
  410. Trace1(IF,
  411. "_IgmpRtrCreationAlertCallback: interface %0x not found/activated",
  412. IfIndex);
  413. RELEASE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
  414. continue;
  415. }
  416. // if interface is not version 3, then return true immediately
  417. if (!IS_IF_VER3(pite)) {
  418. Oif[i].bIsEnabled = TRUE;
  419. RELEASE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
  420. continue;
  421. }
  422. ACQUIRE_GROUP_LOCK(Group, "_IgmpRtrCreationAlertCallback");
  423. BEGIN_BREAKOUT_BLOCK1 {
  424. pge = GetGroupFromGroupTable(Group, NULL, 0);
  425. if (pge==NULL) {
  426. Oif[i].bIsEnabled = FALSE;
  427. Error = ERROR_CAN_NOT_COMPLETE;
  428. GOTO_END_BLOCK1;
  429. }
  430. pgie = GetGIFromGIList(pge, pite, NextHop, FALSE, NULL, 0);
  431. if (pgie==NULL) {
  432. Oif[i].bIsEnabled = FALSE;
  433. Error = ERROR_CAN_NOT_COMPLETE;
  434. GOTO_END_BLOCK1;
  435. }
  436. // if pgie not ver3 return true immediately
  437. if (pgie->Version != 3) {
  438. Oif[i].bIsEnabled = TRUE;
  439. GOTO_END_BLOCK1;
  440. }
  441. pSourceEntry = GetSourceEntry(pgie, Source,
  442. pgie->FilterType, NULL, 0, 0);
  443. if ( (pgie->FilterType==INCLUSION && pSourceEntry==NULL)
  444. || (pgie->FilterType==EXCLUSION && pSourceEntry!=NULL) )
  445. {
  446. Oif[i].bIsEnabled = FALSE;
  447. }
  448. else {
  449. Oif[i].bIsEnabled = TRUE;
  450. }
  451. } END_BREAKOUT_BLOCK1;
  452. RELEASE_GROUP_LOCK(Group, "_IgmpRtrCreationAlertCallback");
  453. RELEASE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
  454. }//for all IFs in Oif
  455. for (i=0; i<dwIfCount; i++) {
  456. Trace6(MGM,
  457. "[%d] IGMP-Rtr Creation Alert: <%d.%d.%d.%d : %d.%d.%d.%d> : <%0x:%0x> : :bIgmp:%d",
  458. Oif[i].bIsEnabled, PRINT_IPADDR(Group), PRINT_IPADDR(Source),
  459. Oif[i].dwIfIndex, Oif[i].dwIfNextHopAddr,
  460. Oif[i].bIGMP
  461. );
  462. }
  463. LeaveIgmpApi();
  464. return NO_ERROR;
  465. }
  466. //------------------------------------------------------------------------------
  467. // ProxyCreationAlertCallback
  468. //------------------------------------------------------------------------------
  469. DWORD
  470. ProxyCreationAlertCallback (
  471. DWORD dwSourceAddr,
  472. DWORD dwSourceMask,
  473. DWORD dwGroupAddr,
  474. DWORD dwGroupMask,
  475. DWORD dwInIfIndex,
  476. DWORD dwInIfNextHopAddr,
  477. DWORD dwIfCount,
  478. PMGM_IF_ENTRY pmieOutIfList
  479. )
  480. /*++
  481. Routine Description:
  482. Called when the first interface owned by some other protocol joins any group.
  483. This routine does nothing, as igmp does not send any joins upstream.
  484. Return Value:
  485. NO_ERROR
  486. --*/
  487. {
  488. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  489. LeaveIgmpApi();
  490. return NO_ERROR;
  491. }
  492. //------------------------------------------------------------------------------
  493. // ProxyPruneAlertCallback
  494. //------------------------------------------------------------------------------
  495. DWORD
  496. ProxyPruneAlertCallback (
  497. DWORD dwSourceAddr,
  498. DWORD dwSourceMask,
  499. DWORD dwGroupAddr,
  500. DWORD dwGroupMask,
  501. DWORD dwIfIndex,
  502. DWORD dwIfNextHopAddr,//not used
  503. BOOL bMemberDelete,
  504. PDWORD pdwTimeout
  505. )
  506. /*++
  507. Routine Description:
  508. Called by MGM when the outgoing interface list of an MFE becomes empty,
  509. or when the last interface for a group goes off.
  510. Proxy owns the incoming interface. Proxy leaves the Group on the incoming
  511. interface if no more members exist for that group. Also sets the timeout
  512. value for the negative MFE.
  513. --*/
  514. {
  515. DWORD Error=NO_ERROR;
  516. PPROXY_ALERT_ENTRY pProxyAlertEntry;
  517. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  518. if (pdwTimeout!=NULL)
  519. *pdwTimeout = 300000;
  520. // ignoring ProxyPruneAlertCallback for MFE deletion
  521. if (!bMemberDelete) {
  522. LeaveIgmpApi();
  523. return NO_ERROR;
  524. }
  525. ACQUIRE_PROXY_ALERT_LOCK("_ProxyPruneAlertCallback");
  526. BEGIN_BREAKOUT_BLOCK1 {
  527. pProxyAlertEntry = IGMP_ALLOC(sizeof(PROXY_ALERT_ENTRY), 0xa00,g_ProxyIfIndex);
  528. PROCESS_ALLOC_FAILURE2(pProxyAlertEntry,
  529. "error %d allocating %d bytes",
  530. Error, sizeof(PROXY_ALERT_ENTRY),
  531. GOTO_END_BLOCK1);
  532. pProxyAlertEntry->Group = dwGroupAddr;
  533. pProxyAlertEntry->Source = dwSourceAddr;
  534. pProxyAlertEntry->bPrune = TRUE;
  535. InsertTailList(&g_ProxyAlertsList, &pProxyAlertEntry->Link);
  536. Trace0(WORKER, "Queueing _WF_ProcessProxyAlert() to prune");
  537. QueueIgmpWorker(WF_ProcessProxyAlert, NULL);
  538. } END_BREAKOUT_BLOCK1;
  539. RELEASE_PROXY_ALERT_LOCK("_ProxyPruneAlertCallback");
  540. LeaveIgmpApi();
  541. return NO_ERROR;
  542. }
  543. VOID
  544. WF_ProcessProxyAlert (
  545. PVOID pContext
  546. )
  547. {
  548. DWORD ProxyIfIndex, Error = NO_ERROR;
  549. PIF_TABLE_ENTRY pite;
  550. if (!EnterIgmpWorker()) return;
  551. Trace0(ENTER1, "Entering WF_ProcessProxyAlert()");
  552. //
  553. // acquire lock on the interface and make sure that it exists
  554. //
  555. while (1) {
  556. ProxyIfIndex = g_ProxyIfIndex;
  557. ACQUIRE_IF_LOCK_EXCLUSIVE(ProxyIfIndex, "_Wf_ProcessProxyAlert");
  558. // the interface was a proxy interface
  559. if (ProxyIfIndex==g_ProxyIfIndex)
  560. break;
  561. // someone changed the proxy interface. so try to access it again.
  562. else {
  563. RELEASE_IF_LOCK_EXCLUSIVE(ProxyIfIndex,
  564. "_Wf_ProcessProxyAlert");
  565. }
  566. }
  567. BEGIN_BREAKOUT_BLOCK1 {
  568. //
  569. // make sure that the Proxy handle is correct
  570. //
  571. pite = g_pProxyIfEntry;
  572. if ( (g_ProxyIfIndex==0)||(pite==NULL) )
  573. {
  574. Trace1(ERR,
  575. "Proxy(Deletion/Creation)Alert Callback by MGM for "
  576. "interface(%0x) not owned by Igmp-Proxy",
  577. g_ProxyIfIndex);
  578. IgmpAssertOnError(FALSE);
  579. Error = ERROR_NO_SUCH_INTERFACE;
  580. GOTO_END_BLOCK1;
  581. }
  582. if (!(IS_IF_ACTIVATED(g_pProxyIfEntry))) {
  583. Trace1(ERR,
  584. "Proxy(Deletion/Creation)Alert Callback by MGM for "
  585. "inactivated Proxy interface(%0x)",
  586. g_ProxyIfIndex);
  587. IgmpAssertOnError(FALSE);
  588. Error = ERROR_CAN_NOT_COMPLETE;
  589. GOTO_END_BLOCK1;
  590. }
  591. while (TRUE) {
  592. PPROXY_ALERT_ENTRY pProxyAlertEntry;
  593. DWORD Group, Source;
  594. BOOL bPrune;
  595. ACQUIRE_PROXY_ALERT_LOCK("_WF_ProcessProxyAlert");
  596. if (IsListEmpty(&g_ProxyAlertsList)) {
  597. RELEASE_PROXY_ALERT_LOCK("_WF_ProcessProxyAlert");
  598. break;
  599. }
  600. pProxyAlertEntry = CONTAINING_RECORD(g_ProxyAlertsList.Flink,
  601. PROXY_ALERT_ENTRY, Link);
  602. Group = pProxyAlertEntry->Group;
  603. Source = pProxyAlertEntry->Source;
  604. bPrune = pProxyAlertEntry->bPrune;
  605. RemoveEntryList(&pProxyAlertEntry->Link);
  606. IGMP_FREE(pProxyAlertEntry);
  607. Trace3(MGM, "Received %s for Grp(%d.%d.%d.%d), Src(%d.%d.%d.%d)",
  608. (bPrune)? "ProxyPruneAlertCallback"
  609. :"ProxyJoinAlertCallback",
  610. PRINT_IPADDR(Group), PRINT_IPADDR(Source)
  611. );
  612. RELEASE_PROXY_ALERT_LOCK("_WF_ProcessProxyAlert");
  613. //
  614. // delete/add group from Proxy's group list. decrement/increment refcount
  615. //
  616. ProcessProxyGroupChange(Source, Group,
  617. bPrune?DELETE_FLAG:ADD_FLAG, NOT_STATIC_GROUP);
  618. }
  619. } END_BREAKOUT_BLOCK1;
  620. RELEASE_IF_LOCK_EXCLUSIVE(g_ProxyIfIndex, "_ProcessProxyGroupChange");
  621. LeaveIgmpWorker();
  622. Trace0(LEAVE1, "Leaving _Wf_ProcessProxyAlert()");
  623. return;
  624. } //_wf_processProxyAlert
  625. //------------------------------------------------------------------------------
  626. // _ProxyNewMemberCallback
  627. //------------------------------------------------------------------------------
  628. DWORD
  629. ProxyJoinAlertCallback (
  630. DWORD dwSourceAddr,
  631. DWORD dwSourceMask,
  632. DWORD dwGroupAddr,
  633. DWORD dwGroupMask,
  634. BOOL bMemberDelete
  635. )
  636. {
  637. DWORD Error=NO_ERROR;
  638. PPROXY_ALERT_ENTRY pProxyAlertEntry;
  639. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  640. // ignoring ProxyJoinAlertCallback for MFE deletion
  641. if (!bMemberDelete) {
  642. LeaveIgmpApi();
  643. return NO_ERROR;
  644. }
  645. ACQUIRE_PROXY_ALERT_LOCK("_ProxyJoinAlertCallback");
  646. BEGIN_BREAKOUT_BLOCK1 {
  647. pProxyAlertEntry = IGMP_ALLOC(sizeof(PROXY_ALERT_ENTRY), 0x200,g_ProxyIfIndex);
  648. PROCESS_ALLOC_FAILURE2(pProxyAlertEntry,
  649. "error %d allocating %d bytes",
  650. Error, sizeof(PROXY_ALERT_ENTRY),
  651. GOTO_END_BLOCK1);
  652. pProxyAlertEntry->Group = dwGroupAddr;
  653. pProxyAlertEntry->Source = dwSourceAddr;
  654. pProxyAlertEntry->bPrune = FALSE;
  655. InsertTailList(&g_ProxyAlertsList, &pProxyAlertEntry->Link);
  656. Trace0(WORKER, "Queueing _WF_ProcessProxyAlert() to Join");
  657. QueueIgmpWorker(WF_ProcessProxyAlert, NULL);
  658. } END_BREAKOUT_BLOCK1;
  659. RELEASE_PROXY_ALERT_LOCK("_ProxyJoinAlertCallback");
  660. LeaveIgmpApi();
  661. return NO_ERROR;
  662. }
  663. //------------------------------------------------------------------------------
  664. // ProcessProxyGroupChange
  665. //------------------------------------------------------------------------------
  666. DWORD
  667. ProcessProxyGroupChange (
  668. DWORD dwSourceAddr,
  669. DWORD dwGroup,
  670. BOOL bAddFlag,
  671. BOOL bStaticGroup
  672. )
  673. /*++
  674. Routine Description:
  675. Called when a group is being joined/left by some interface. As proxy acts
  676. as an igmp host on that interface, it does a join/leave for that group
  677. on that interface.
  678. There can be both static and dynamic joins. There is no distinction between
  679. them. They will just bump up the refcount.
  680. Return Value:
  681. ERROR_NO_SUCH_INTERFACE, ERROR_CAN_NOT_COMPLETE, NO_ERROR
  682. Called by:
  683. --*/
  684. {
  685. PIF_TABLE_ENTRY pite;
  686. PLIST_ENTRY ple, pHead;
  687. DWORD Error = NO_ERROR;
  688. DWORD GroupLittleEndian = NETWORK_TO_LITTLE_ENDIAN(dwGroup);
  689. PLIST_ENTRY pHeadSrc, pleSrc;
  690. PPROXY_SOURCE_ENTRY pSourceEntry = NULL;
  691. //
  692. // if Proxy does not exist, or is not activated, then return error
  693. //
  694. if ( (g_pProxyIfEntry==NULL)
  695. || (!(IS_IF_ACTIVATED(g_pProxyIfEntry))) )
  696. {
  697. Trace0(ERR, "Leaving ProcessProxyGroupChange(): Proxy not active");
  698. IgmpAssertOnError(FALSE);
  699. if (g_pProxyIfEntry==NULL)
  700. return ERROR_NO_SUCH_INTERFACE;
  701. else
  702. return ERROR_CAN_NOT_COMPLETE;
  703. }
  704. pite = g_pProxyIfEntry;
  705. BEGIN_BREAKOUT_BLOCK1 {
  706. PPROXY_GROUP_ENTRY ppge, ppgeNew;
  707. pHead = &pite->pProxyHashTable[PROXY_HASH_VALUE(dwGroup)];
  708. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  709. ppge = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, HT_Link);
  710. if ( GroupLittleEndian <= ppge->GroupLittleEndian )
  711. break;
  712. }
  713. //
  714. // adding group to proxy
  715. //
  716. if (bAddFlag) {
  717. //new group addition
  718. //
  719. // the group entry does not exist
  720. //
  721. //ppge may not be valid(if ple==pHead)
  722. if ( (ple==pHead)||(dwGroup!=ppge->Group) ) {
  723. ppgeNew = IGMP_ALLOC(sizeof(PROXY_GROUP_ENTRY), 0x400,0xaaaa);
  724. PROCESS_ALLOC_FAILURE2(ppgeNew,
  725. "error %d allocating %d bytes for Proxy group entry",
  726. Error, sizeof(PROXY_GROUP_ENTRY),
  727. GOTO_END_BLOCK1);
  728. InitializeListHead(&ppgeNew->ListSources);
  729. ppgeNew->NumSources = 0;
  730. ppgeNew->Group = dwGroup;
  731. ppgeNew->GroupLittleEndian = GroupLittleEndian;
  732. ppgeNew->RefCount = 0;
  733. InsertTailList(ple, &ppgeNew->HT_Link);
  734. InsertInProxyList(pite, ppgeNew);
  735. // set the time when the entry was created.
  736. ppgeNew->InitTime = GetCurrentIgmpTime();
  737. ppgeNew->bStaticGroup = (dwSourceAddr==0)? bStaticGroup : FALSE;
  738. //
  739. // update stats
  740. //
  741. InterlockedIncrement(&pite->Info.CurrentGroupMemberships);
  742. InterlockedIncrement(&pite->Info.GroupMembershipsAdded);
  743. ppge = ppgeNew;
  744. // join the group
  745. if (dwSourceAddr==0) {
  746. Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  747. pite->IfIndex, pite->IpAddr, 0);
  748. ppgeNew->RefCount = 1;
  749. }
  750. // else process source entry later
  751. ppge->FilterType = (dwSourceAddr==0)? EXCLUSION : INCLUSION;
  752. } //end new group entry created
  753. // increase group refcount
  754. else if (dwSourceAddr==0) {
  755. //
  756. // leave all source mode joins and join *,G
  757. //
  758. if (ppge->RefCount==0) {
  759. pHeadSrc = &ppge->ListSources;
  760. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
  761. pSourceEntry = CONTAINING_RECORD(pleSrc,
  762. PROXY_SOURCE_ENTRY, LinkSources);
  763. Error = LeaveMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  764. pite->IfIndex, pite->IpAddr,
  765. pSourceEntry->IpAddr);
  766. pSourceEntry->JoinMode = IGMP_GROUP_NO_STATE;
  767. pSourceEntry->JoinModeIntended = IGMP_GROUP_ALLOW;
  768. }
  769. Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  770. pite->IfIndex, pite->IpAddr, 0);
  771. ppge->FilterType = EXCLUSION;
  772. }
  773. ppge->RefCount++;
  774. ppge->bStaticGroup |= bStaticGroup;
  775. } //group entry exists. group join
  776. if (dwSourceAddr!=0) {
  777. // check if source already present
  778. pHeadSrc = &ppge->ListSources;
  779. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
  780. pSourceEntry = CONTAINING_RECORD(pleSrc,
  781. PROXY_SOURCE_ENTRY, LinkSources);
  782. if (pSourceEntry->IpAddr >= dwSourceAddr)
  783. break;
  784. }
  785. // create new source
  786. if (pleSrc==pHeadSrc ||
  787. (pSourceEntry //(dont need to check pSourceEntry)
  788. && pSourceEntry->IpAddr!=dwSourceAddr))
  789. {
  790. pSourceEntry = (PPROXY_SOURCE_ENTRY) IGMP_ALLOC_AND_ZERO(sizeof(PROXY_SOURCE_ENTRY),
  791. 0x800,g_ProxyIfIndex);
  792. PROCESS_ALLOC_FAILURE2(pSourceEntry,
  793. "error %d allocating %d bytes",
  794. Error,
  795. sizeof(PROXY_SOURCE_ENTRY),
  796. GOTO_END_BLOCK1);
  797. InsertTailList(pleSrc, &pSourceEntry->LinkSources);
  798. pSourceEntry->IpAddr = dwSourceAddr;
  799. pSourceEntry->RefCount = 1;
  800. pSourceEntry->bStaticSource = bStaticGroup;
  801. ppge->NumSources++;
  802. //
  803. // if not joined the whole group. have to join individual
  804. // sources
  805. //
  806. if (ppge->FilterType==INCLUSION) {
  807. Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  808. pite->IfIndex, pite->IpAddr,
  809. dwSourceAddr);
  810. pSourceEntry->JoinMode = IGMP_GROUP_ALLOW;
  811. }
  812. else {
  813. pSourceEntry->JoinMode = IGMP_GROUP_NO_STATE;
  814. }
  815. pSourceEntry->JoinModeIntended = IGMP_GROUP_ALLOW;
  816. } //end new source
  817. // join: source already exists
  818. else
  819. if (pSourceEntry) // dont need to check this. suppress warning
  820. {
  821. //
  822. // join back an excluded source
  823. //
  824. if (pSourceEntry->JoinMode==IGMP_GROUP_BLOCK) {
  825. if (!pSourceEntry->bStaticSource) {
  826. UnBlockSource(pite->SocketEntry.Socket, dwGroup,
  827. pite->IfIndex, pite->IpAddr,
  828. dwSourceAddr);
  829. RemoveEntryList(&pSourceEntry->LinkSources);
  830. IGMP_FREE(pSourceEntry);
  831. }
  832. }
  833. else {//fix this
  834. if (bStaticGroup)
  835. pSourceEntry->bStaticSource = TRUE;
  836. pSourceEntry->RefCount++;
  837. }
  838. }//end: join when existing source
  839. }
  840. }
  841. //
  842. // deleting group from proxy
  843. //
  844. else {
  845. if ((ple==pHead) || (dwGroup>ppge->Group) ) {
  846. Error = ERROR_CAN_NOT_COMPLETE;
  847. GOTO_END_BLOCK1;
  848. }
  849. else {
  850. // leave source
  851. if (dwSourceAddr!=0) {
  852. pHeadSrc = &ppge->ListSources;
  853. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
  854. pSourceEntry = CONTAINING_RECORD(pleSrc,
  855. PROXY_SOURCE_ENTRY, LinkSources);
  856. if (pSourceEntry->IpAddr >= dwSourceAddr)
  857. break;
  858. }
  859. // leave source: source does not exist
  860. if ((pleSrc==pHeadSrc) || (pSourceEntry->IpAddr!=dwSourceAddr)) {
  861. // if in exclude mode then create an exclusion entry
  862. if (ppge->FilterType==EXCLUSION) {
  863. pSourceEntry = (PPROXY_SOURCE_ENTRY) IGMP_ALLOC_AND_ZERO(sizeof(PROXY_SOURCE_ENTRY),
  864. 0x800,g_ProxyIfIndex);
  865. PROCESS_ALLOC_FAILURE2(pSourceEntry,
  866. "error %d allocating %d bytes",
  867. Error,
  868. sizeof(PROXY_SOURCE_ENTRY),
  869. GOTO_END_BLOCK1);
  870. InsertTailList(pleSrc, &pSourceEntry->LinkSources);
  871. pSourceEntry->IpAddr = dwSourceAddr;
  872. pSourceEntry->RefCount = 1;
  873. pSourceEntry->bStaticSource = bStaticGroup;
  874. ppge->NumSources++;
  875. Error = BlockSource(pite->SocketEntry.Socket, dwGroup,
  876. pite->IfIndex, pite->IpAddr,
  877. dwSourceAddr);
  878. pSourceEntry->JoinMode = IGMP_GROUP_BLOCK;
  879. pSourceEntry->JoinModeIntended = IGMP_GROUP_BLOCK;
  880. }
  881. else { //include mode. trying to leave non-existing source
  882. IgmpAssert(FALSE);
  883. }
  884. GOTO_END_BLOCK1;
  885. }
  886. // leave source: source exists
  887. else {
  888. if ( (pSourceEntry->JoinMode==IGMP_GROUP_ALLOW)
  889. ||(pSourceEntry->JoinMode==IGMP_GROUP_NO_STATE)
  890. ) {
  891. if (--pSourceEntry->RefCount==0) {
  892. if (pSourceEntry->JoinMode==IGMP_GROUP_ALLOW) {
  893. Error = LeaveMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  894. pite->IfIndex, pite->IpAddr, dwSourceAddr);
  895. }
  896. RemoveEntryList(&pSourceEntry->LinkSources);
  897. IGMP_FREE(pSourceEntry);
  898. if (--ppge->NumSources==0) {
  899. if (ppge->RefCount==0) {
  900. RemoveEntryList(&ppge->HT_Link);
  901. RemoveEntryList(&ppge->LinkBySameIfGroups);
  902. IGMP_FREE(ppge);
  903. InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
  904. }
  905. }
  906. }
  907. else {
  908. if (bStaticGroup)
  909. pSourceEntry->bStaticSource = FALSE;
  910. }
  911. }
  912. else {
  913. //if (!pSourceEntry->bStaticSource || ++pSourceEntry->RefCount>2)
  914. //IgmpAssert(FALSE);
  915. // do nothing. this might happen
  916. }
  917. }
  918. } // end leave source
  919. // leave group
  920. else if (--ppge->RefCount == 0) {
  921. Error = LeaveMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  922. pite->IfIndex, pite->IpAddr, 0);
  923. // if no S,G then delete this group, else join the
  924. // individual sources
  925. if (ppge->NumSources==0) {
  926. RemoveEntryList(&ppge->HT_Link);
  927. RemoveEntryList(&ppge->LinkBySameIfGroups);
  928. IGMP_FREE(ppge);
  929. //
  930. // update stats
  931. //
  932. InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
  933. }
  934. else {
  935. pHeadSrc = &ppge->ListSources;
  936. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
  937. pSourceEntry = CONTAINING_RECORD(pleSrc,
  938. PROXY_SOURCE_ENTRY, LinkSources);
  939. Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
  940. pite->IfIndex, pite->IpAddr,
  941. pSourceEntry->IpAddr);
  942. pSourceEntry->JoinMode = IGMP_GROUP_ALLOW;
  943. pSourceEntry->JoinModeIntended = IGMP_GROUP_ALLOW;
  944. }
  945. }
  946. }
  947. else {
  948. if (bStaticGroup)
  949. ppge->bStaticGroup = FALSE;
  950. }
  951. }
  952. }
  953. } END_BREAKOUT_BLOCK1;
  954. return NO_ERROR;
  955. } //end ProcessProxyGroupChange
  956. VOID
  957. DebugPrintProxyGroupTable (
  958. )
  959. {
  960. PIF_TABLE_ENTRY pite;
  961. PLIST_ENTRY ple, pHead;
  962. DWORD Error = NO_ERROR, dwCount;
  963. PPROXY_GROUP_ENTRY ppge;
  964. //
  965. // if Proxy does not exist, or is not activated, then return error
  966. //
  967. if ( (g_pProxyIfEntry==NULL)
  968. || (!(IS_IF_ACTIVATED(g_pProxyIfEntry))) )
  969. {
  970. return;
  971. }
  972. pite = g_pProxyIfEntry;
  973. pHead = &pite->ListOfSameIfGroups;
  974. Trace0(KSL, "---------------------------");
  975. Trace0(KSL, "Printing Proxy GroupTable");
  976. Trace0(KSL, "---------------------------");
  977. for (ple=pHead->Flink,dwCount=1; ple!=pHead; ple=ple->Flink,dwCount++) {
  978. ppge = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, LinkBySameIfGroups);
  979. Trace3(KSL, "%2d. %d.%d.%d.%d %10d",
  980. dwCount, PRINT_IPADDR(ppge->Group), ppge->RefCount);
  981. }
  982. return;
  983. }