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.

2893 lines
90 KiB

  1. //=============================================================================
  2. // Copyright (c) 1997 Microsoft Corporation
  3. // File: table.c
  4. //
  5. // Abstract:
  6. // This module implements some of the routines associated with creating,
  7. // initializing, deleting timers, GI entries, table entries etc
  8. //
  9. // Author: K.S.Lokesh (lokeshs@) 11-1-97
  10. //
  11. // Revision History:
  12. //=============================================================================
  13. #include "pchigmp.h"
  14. #pragma hdrstop
  15. //------------------------------------------------------------------------------
  16. // _CreateIfSockets
  17. //
  18. // Creates the sockets.
  19. // for proxy: a raw IPPROTO_IP socket so that igmp host functionality will
  20. // take over for all groups added on that interface.
  21. // for router: a raw IPPROTO_IGMP socket so that it receives all igmp packets
  22. // A router never does Add Memberships
  23. //
  24. // Called by: _ActivateInterface()
  25. // Locks: assumes exclusive lock on the interface, and socketsList
  26. //------------------------------------------------------------------------------
  27. DWORD
  28. CreateIfSockets (
  29. PIF_TABLE_ENTRY pite
  30. )
  31. {
  32. DWORD Error = NO_ERROR, dwRetval, SockType;
  33. DWORD IpAddr = pite->IpAddr;
  34. DWORD IfIndex = pite->IfIndex;
  35. SOCKADDR_IN saLocalIf;
  36. BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);
  37. PSOCKET_ENTRY pse = &pite->SocketEntry;
  38. BEGIN_BREAKOUT_BLOCK1 {
  39. //
  40. // for proxy, create a IPPROTO_IP socket so that igmp host functionality
  41. // takes over.
  42. // for igmp router, create a raw IPPROTO_IGMP socket
  43. //
  44. SockType = (bProxy)? IPPROTO_IP : IPPROTO_IGMP;
  45. //
  46. // create input socket
  47. //
  48. pse->Socket = WSASocket(AF_INET, SOCK_RAW, SockType, NULL, 0, 0);
  49. if (pse->Socket == INVALID_SOCKET) {
  50. Error = WSAGetLastError();
  51. Trace3(IF,
  52. "error %d creating socket for interface %d (%d.%d.%d.%d)",
  53. Error, IfIndex, PRINT_IPADDR(IpAddr));
  54. Logerr1(CREATE_SOCKET_FAILED_2, "%I", IpAddr, Error);
  55. GOTO_END_BLOCK1;
  56. }
  57. //
  58. // bind socket to local interface. If I dont bind multicast may
  59. // not work.
  60. //
  61. ZeroMemory(&saLocalIf, sizeof(saLocalIf));
  62. saLocalIf.sin_family = PF_INET;
  63. saLocalIf.sin_addr.s_addr = IpAddr;
  64. saLocalIf.sin_port = 0; //port shouldnt matter
  65. // bind the input socket
  66. Error = bind(pse->Socket, (SOCKADDR FAR *)&saLocalIf, sizeof(SOCKADDR));
  67. if (Error == SOCKET_ERROR) {
  68. Error = WSAGetLastError();
  69. Trace3(IF, "error %d binding on socket for interface %d (%d.%d.%d.%d)",
  70. Error, IfIndex, PRINT_IPADDR(IpAddr));
  71. Logerr1(BIND_FAILED, "%I", IpAddr, Error);
  72. GOTO_END_BLOCK1;
  73. }
  74. //
  75. // A proxy never sends/receives any packets. It is just expected to enable
  76. // igmp host functionality to take over for the groups on which it joins.
  77. //
  78. //------------------------------
  79. // if proxy then done
  80. //------------------------------
  81. if (bProxy)
  82. GOTO_END_BLOCK1;
  83. //------------------------------
  84. // NOT PROXY INTERFACE
  85. //------------------------------
  86. if (!bProxy) {
  87. // set ttl to 1: not required as it is set to 1 by default.
  88. McastSetTtl(pse->Socket, 1);
  89. //
  90. // disable multicast packets from being loopedback.
  91. // This may not work due to promiscuous mode,
  92. // so you still have to check the input packets
  93. //
  94. {
  95. BOOL bLoopBack = FALSE;
  96. DWORD dwRetval;
  97. dwRetval = setsockopt(pse->Socket, IPPROTO_IP, IP_MULTICAST_LOOP,
  98. (char *)&bLoopBack, sizeof(BOOL));
  99. if (dwRetval==SOCKET_ERROR) {
  100. Trace2(ERR, "error %d disabling multicast loopBack on IfIndex %d",
  101. WSAGetLastError(), IfIndex);
  102. IgmpAssertOnError(FALSE);
  103. }
  104. }
  105. //
  106. // if RasServerInterface, then activate hdrInclude option so that I can
  107. // send GenQuery to all RAS clients
  108. //
  109. if (IS_RAS_SERVER_IF(pite->IfType)) {
  110. INT iSetHdrIncl = 1;
  111. Error = setsockopt( pse->Socket, IPPROTO_IP, IP_HDRINCL,
  112. (char *) &iSetHdrIncl, sizeof(INT));
  113. if (Error!=NO_ERROR) {
  114. Error = WSAGetLastError();
  115. Trace2(ERR, "error %d unable to set IP_HDRINCL option on interface %d",
  116. Error, IfIndex,);
  117. IgmpAssertOnError(FALSE);
  118. Logerr1(SET_HDRINCL_FAILED, "%I", pite->IpAddr, Error);
  119. GOTO_END_BLOCK1;
  120. }
  121. }
  122. else {
  123. //
  124. // set the interface on which multicasts must be sent
  125. // set only for non rasserver (not internal) interfaces
  126. //
  127. dwRetval = setsockopt(pse->Socket, IPPROTO_IP, IP_MULTICAST_IF,
  128. (PBYTE)&saLocalIf.sin_addr, sizeof(IN_ADDR));
  129. if (dwRetval == SOCKET_ERROR) {
  130. Error = WSAGetLastError();
  131. Trace3(IF, "error %d setting interface %d (%d.%d.%d.%d) to send multicast",
  132. Error, IfIndex, PRINT_IPADDR(pite->IpAddr));
  133. Logerr1(SET_MCAST_IF_FAILED, "%I", pite->IpAddr, Error);
  134. Error = SOCKET_ERROR;
  135. GOTO_END_BLOCK1;
  136. }
  137. {
  138. //
  139. // set router alert option for packets sent. dont have to set it for
  140. // RasServerInterface where I do hdrInclude.
  141. //
  142. u_char Router_alert[4] = {148, 4, 0, 0};
  143. dwRetval = setsockopt(pse->Socket, IPPROTO_IP, IP_OPTIONS,
  144. (void *)Router_alert, sizeof(Router_alert));
  145. if (dwRetval!=0) {
  146. dwRetval = WSAGetLastError();
  147. Trace2(ERR,
  148. "error %d unable to set router alert option on interface %d",
  149. dwRetval, IfIndex
  150. );
  151. IgmpAssertOnError(FALSE);
  152. Logerr1(SET_ROUTER_ALERT_FAILED, "%I", pite->IpAddr, dwRetval);
  153. Error = dwRetval;
  154. GOTO_END_BLOCK1;
  155. }
  156. }
  157. }
  158. //
  159. // set the interface in promiscuous igmp multicast mode.
  160. //
  161. {
  162. DWORD dwEnable = 1;
  163. DWORD dwNum;
  164. dwRetval = WSAIoctl(pse->Socket, SIO_RCVALL_IGMPMCAST, (char *)&dwEnable,
  165. sizeof(dwEnable), NULL , 0, &dwNum, NULL, NULL);
  166. if (dwRetval !=0) {
  167. dwRetval = WSAGetLastError();
  168. Trace2(IF, "error %d setting interface %d as promiscuous multicast",
  169. dwRetval, IfIndex);
  170. Logerr1(SET_ROUTER_ALERT_FAILED, "%I", pite->IpAddr, dwRetval);
  171. Error = dwRetval;
  172. GOTO_END_BLOCK1;
  173. }
  174. else {
  175. Trace1(IF, "promiscuous igmp multicast enabled on If (%d)",
  176. IfIndex);
  177. }
  178. }
  179. //
  180. // Router doesnt have to join any group as it is in promiscuous mode
  181. //
  182. //
  183. // create entry in the SocketsEvents list
  184. //
  185. {
  186. BOOLEAN bCreateNewEntry;
  187. PLIST_ENTRY ple, pHead = &g_ListOfSocketEvents;
  188. PSOCKET_EVENT_ENTRY psee;
  189. bCreateNewEntry = TRUE;
  190. //
  191. // see if a new socket-event entry has to be created
  192. //
  193. if (g_pIfTable->NumInterfaces>NUM_SINGLE_SOCKET_EVENTS) {
  194. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  195. psee = CONTAINING_RECORD(ple, SOCKET_EVENT_ENTRY,
  196. LinkBySocketEvents);
  197. if (psee->NumInterfaces < MAX_SOCKETS_PER_EVENT) {
  198. bCreateNewEntry = FALSE;
  199. break;
  200. }
  201. }
  202. }
  203. //
  204. // create a new socket-event entry and insert in the list
  205. // register the event entry with the wait thread
  206. //
  207. if (bCreateNewEntry) {
  208. psee = IGMP_ALLOC(sizeof(SOCKET_EVENT_ENTRY),
  209. 0x80000,pite->IfIndex);
  210. PROCESS_ALLOC_FAILURE2(psee,
  211. "error %d allocating %d bytes for SocketEventEntry",
  212. Error, sizeof(SOCKET_EVENT_ENTRY),
  213. GOTO_END_BLOCK1);
  214. InitializeListHead(&psee->ListOfInterfaces);
  215. psee->NumInterfaces = 0;
  216. InsertHeadList(pHead, &psee->LinkBySocketEvents);
  217. psee->InputEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  218. if (psee->InputEvent == NULL) {
  219. Error = GetLastError();
  220. Trace1(ERR,
  221. "error %d creating InputEvent in CreateIfSockets",
  222. Error);
  223. IgmpAssertOnError(FALSE);
  224. Logerr0(CREATE_EVENT_FAILED, Error);
  225. GOTO_END_BLOCK1;
  226. }
  227. if (! RegisterWaitForSingleObject(
  228. &psee->InputWaitEvent,
  229. psee->InputEvent,
  230. WT_ProcessInputEvent, psee,
  231. INFINITE,
  232. (WT_EXECUTEINWAITTHREAD)|(WT_EXECUTEONLYONCE)
  233. ))
  234. {
  235. Error = GetLastError();
  236. Trace1(ERR, "error %d RegisterWaitForSingleObject", Error);
  237. IgmpAssertOnError(FALSE);
  238. GOTO_END_BLOCK1;
  239. }
  240. }
  241. //
  242. // put the socketEntry in the list
  243. //
  244. InsertTailList(&psee->ListOfInterfaces, &pse->LinkByInterfaces);
  245. pse->pSocketEventsEntry = psee;
  246. //
  247. // if the socket-event entry cannot take any more sockets,
  248. // then put it at end of list
  249. //
  250. if (++psee->NumInterfaces==MAX_SOCKETS_PER_EVENT) {
  251. RemoveEntryList(&psee->LinkBySocketEvents);
  252. InsertTailList(pHead, &psee->LinkBySocketEvents);
  253. }
  254. } //end:create entry in the sockets list
  255. //
  256. // create socket for static joins.
  257. //
  258. {
  259. pite->StaticGroupSocket =
  260. WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, 0);
  261. if (pite->StaticGroupSocket == INVALID_SOCKET) {
  262. Error = WSAGetLastError();
  263. Trace3(IF,
  264. "error %d creating static group socket for interface "
  265. "%d (%d.%d.%d.%d)",
  266. Error, pite->IfIndex, PRINT_IPADDR(pite->IpAddr));
  267. Logerr1(CREATE_SOCKET_FAILED_2, "%I", pite->IpAddr, Error);
  268. GOTO_END_BLOCK1;
  269. }
  270. //
  271. // bind socket to local interface. If I dont bind multicast may
  272. // not work.
  273. //
  274. saLocalIf.sin_family = PF_INET;
  275. saLocalIf.sin_addr.s_addr = pite->IpAddr;
  276. saLocalIf.sin_port = 0; //port shouldnt matter
  277. Error = bind(pite->StaticGroupSocket, (SOCKADDR FAR *)&saLocalIf,
  278. sizeof(SOCKADDR));
  279. }
  280. } // end: not proxy interface
  281. } END_BREAKOUT_BLOCK1;
  282. if (Error!=NO_ERROR)
  283. DeleteIfSockets(pite);
  284. return Error;
  285. } //end _CreateIfSockets
  286. //------------------------------------------------------------------------------
  287. // _DeleteIfSockets
  288. //
  289. // Called by: _DeActivateInterfaceComplete()
  290. //------------------------------------------------------------------------------
  291. VOID
  292. DeleteIfSockets (
  293. PIF_TABLE_ENTRY pite
  294. )
  295. {
  296. PSOCKET_ENTRY pse = &pite->SocketEntry;
  297. PSOCKET_EVENT_ENTRY psee = pse->pSocketEventsEntry;
  298. BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);
  299. // close input socket
  300. if (pse->Socket!=INVALID_SOCKET) {
  301. if (closesocket(pse->Socket) == SOCKET_ERROR) {
  302. Trace1(IF, "error %d closing socket", WSAGetLastError());
  303. }
  304. pse->Socket = INVALID_SOCKET;
  305. }
  306. //
  307. // if router interface. delete socket from socketEventList
  308. // and free the socketEventEntry only if they were initialized.
  309. //
  310. if ((!bProxy)&&(pse->pSocketEventsEntry!=NULL)) {
  311. PSOCKET_EVENT_ENTRY psee = pse->pSocketEventsEntry;
  312. RemoveEntryList(&pse->LinkByInterfaces);
  313. if (--psee->NumInterfaces==0) {
  314. if (psee->InputWaitEvent) {
  315. HANDLE WaitHandle ;
  316. WaitHandle = InterlockedExchangePointer(&psee->InputWaitEvent, NULL);
  317. if (WaitHandle)
  318. UnregisterWaitEx( WaitHandle, NULL ) ;
  319. }
  320. CloseHandle(psee->InputEvent);
  321. RemoveEntryList(&psee->LinkBySocketEvents);
  322. IGMP_FREE(psee);
  323. }
  324. if (pite->StaticGroupSocket!=INVALID_SOCKET) {
  325. closesocket(pite->StaticGroupSocket);
  326. pite->StaticGroupSocket = INVALID_SOCKET;
  327. }
  328. }
  329. return;
  330. }
  331. //------------------------------------------------------------------------------
  332. // _DeleteAllTimers
  333. //
  334. // Deletes all timers associated with a GI entry.
  335. //
  336. // Called by: _DeActivateInterfaceComplete()
  337. // Locks: Assumes Timer lock and GroupBucket lock.
  338. //------------------------------------------------------------------------------
  339. VOID
  340. DeleteAllTimers (
  341. PLIST_ENTRY pHead,
  342. DWORD bEntryType
  343. )
  344. {
  345. PLIST_ENTRY ple;
  346. PGI_ENTRY pgie;
  347. Trace0(ENTER1, "entering _DeleteAllTimers()");
  348. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  349. pgie = (bEntryType==RAS_CLIENT)
  350. ? CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups)
  351. : CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
  352. if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer))
  353. RemoveTimer(&pgie->GroupMembershipTimer, DBG_N);
  354. if (IS_TIMER_ACTIVE(pgie->LastMemQueryTimer))
  355. RemoveTimer(&pgie->LastMemQueryTimer, DBG_N);
  356. if (IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer))
  357. RemoveTimer(&pgie->LastVer1ReportTimer, DBG_N);
  358. if (IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer))
  359. RemoveTimer(&pgie->LastVer2ReportTimer, DBG_N);
  360. if (IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer))
  361. RemoveTimer(&pgie->V3SourcesQueryTimer, DBG_N);
  362. // delete all sources timers
  363. if (pgie->Version==3) {
  364. PLIST_ENTRY pleSrc, pHeadSrc;
  365. pHeadSrc = &pgie->V3InclusionListSorted;
  366. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink){
  367. PGI_SOURCE_ENTRY pSourceEntry;
  368. pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
  369. if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
  370. RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_Y);
  371. }
  372. pHeadSrc = &pgie->V3ExclusionList;
  373. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink){
  374. PGI_SOURCE_ENTRY pSourceEntry;
  375. pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
  376. if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
  377. RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_Y);
  378. }
  379. }
  380. }
  381. Trace0(LEAVE1, "Leaving _DeleteAllTimers()");
  382. return;
  383. }
  384. //------------------------------------------------------------------------------
  385. // _DeleteGIEntry
  386. //
  387. // Locks: Assumes lock on the group bucket. takes lock on IfGroup list.
  388. // takes lock on groupList if group being deleted.
  389. //------------------------------------------------------------------------------
  390. DWORD
  391. DeleteGIEntry (
  392. PGI_ENTRY pgie, //group interface entry
  393. BOOL bUpdateStats,
  394. BOOL bCallMgm
  395. )
  396. {
  397. PIF_TABLE_ENTRY pite = pgie->pIfTableEntry;
  398. PRAS_TABLE_ENTRY prte = pgie->pRasTableEntry;
  399. PGROUP_TABLE_ENTRY pge = pgie->pGroupTableEntry;
  400. PGI_ENTRY pgieCur;
  401. BOOL bRas = (prte!=NULL);
  402. DWORD NHAddr;
  403. DWORD dwRetval;
  404. Trace0(ENTER1, "Entering _DeleteGIEntry()");
  405. NHAddr = (bRas) ? prte->NHAddr : 0;
  406. Trace4(GROUP, "Deleting group(%d.%d.%d.%d) on Interface(%d)(%d.%d.%d.%d) "
  407. "NHAddr(%d.%d.%d.%d)",
  408. PRINT_IPADDR(pge->Group), pite->IfIndex,
  409. PRINT_IPADDR(pite->IpAddr), PRINT_IPADDR(NHAddr));
  410. bCallMgm = bCallMgm && (CAN_ADD_GROUPS_TO_MGM(pite));
  411. //
  412. // exclusion mode. remove all exclusion entries
  413. // dont have to call MGM as it still has to be excluded
  414. //
  415. if (pgie->Version==3) {
  416. PLIST_ENTRY pleSrc, pHeadSrc;
  417. pHeadSrc = &pgie->V3InclusionListSorted;
  418. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
  419. PGI_SOURCE_ENTRY pSourceEntry;
  420. pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
  421. pleSrc=pleSrc->Flink;
  422. DeleteSourceEntry(pSourceEntry, bCallMgm);
  423. }
  424. pHeadSrc = &pgie->V3ExclusionList;
  425. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
  426. PGI_SOURCE_ENTRY pSourceEntry;
  427. pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
  428. pleSrc=pleSrc->Flink;
  429. DeleteSourceEntry(pSourceEntry, bCallMgm);
  430. }
  431. }
  432. //
  433. // call mgm to remove this group
  434. //
  435. if ( bCallMgm ) {
  436. if ( (pgie->Version==3 && pgie->FilterType==EXCLUSION)
  437. || pgie->Version!=3)
  438. {
  439. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pite, NHAddr,
  440. 0, 0,
  441. pge->Group, 0xffffffff, MGM_JOIN_STATE_FLAG);
  442. }
  443. }
  444. //
  445. // remove all timers
  446. //
  447. ACQUIRE_TIMER_LOCK("_DeleteGIEntry");
  448. if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer))
  449. RemoveTimer(&pgie->GroupMembershipTimer, DBG_N);
  450. if (IS_TIMER_ACTIVE(pgie->LastMemQueryTimer))
  451. RemoveTimer(&pgie->LastMemQueryTimer, DBG_N);
  452. if (IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer))
  453. RemoveTimer(&pgie->LastVer1ReportTimer, DBG_N);
  454. if (IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer))
  455. RemoveTimer(&pgie->LastVer2ReportTimer, DBG_N);
  456. if (IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer))
  457. RemoveTimer(&pgie->V3SourcesQueryTimer, DBG_Y);
  458. RELEASE_TIMER_LOCK("_DeleteGIEntry");
  459. //
  460. // Remove from IfGroupList. needs lock on IfGroupList
  461. //
  462. ACQUIRE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeleteGIEntry");
  463. // if interface being deleted, then return from here
  464. if (IS_IF_DELETED(pgie->pIfTableEntry)) {
  465. RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeleteGIEntry");
  466. return NO_ERROR;
  467. }
  468. // remove GI entry from group's GI list
  469. RemoveEntryList(&pgie->LinkByGI);
  470. //
  471. // remove entry from interface list
  472. //
  473. RemoveEntryList(&pgie->LinkBySameIfGroups);
  474. if (bRas)
  475. RemoveEntryList(&pgie->LinkBySameClientGroups);
  476. RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeleteGIEntry");
  477. //
  478. // decrement the number of virtual interfaces. I have to do
  479. // interlocked decrement as I dont take group_list lock
  480. //
  481. InterlockedDecrement(&pge->NumVifs);
  482. //
  483. // if group has no more interfaces hanging from it, then delete it
  484. // and update statistics
  485. //
  486. if (IsListEmpty(&pge->ListOfGIs)) {
  487. // take groupList lock before deleting it from the group list
  488. ACQUIRE_GROUP_LIST_LOCK("_DeleteGIEntry");
  489. RemoveEntryList(&pge->LinkByGroup);
  490. RELEASE_GROUP_LIST_LOCK("_DeleteGIEntry");
  491. // remove group entry from the group hash table
  492. RemoveEntryList(&pge->HTLinkByGroup);
  493. IGMP_FREE(pge);
  494. pge = NULL;
  495. //global stats (has to be updated even if bUpdateStats==FALSE)
  496. InterlockedDecrement(&g_Info.CurrentGroupMemberships);
  497. #if DBG
  498. DebugPrintGroupsList(1);
  499. #endif
  500. }
  501. //
  502. // update statistics
  503. //
  504. if (bUpdateStats) {
  505. //
  506. // ras interface statistics (decrement only if last GI for ras)
  507. //
  508. if (bRas) {
  509. // see if GI entry exists for that ras client. very inefficient
  510. if (pge!=NULL) {
  511. PLIST_ENTRY pHead, ple;
  512. pHead = &pge->ListOfGIs;
  513. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  514. pgieCur = CONTAINING_RECORD(ple, GI_ENTRY, LinkByGI);
  515. if (pgieCur->IfIndex>=pite->IfIndex)
  516. break;
  517. }
  518. if ( (ple==pHead)||(pgieCur->IfIndex!=pite->IfIndex) ) {
  519. InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
  520. }
  521. }
  522. // last GI entry
  523. else {
  524. InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
  525. }
  526. // update ras client stats
  527. if (g_Config.RasClientStats) {
  528. InterlockedDecrement(&prte->Info.CurrentGroupMemberships);
  529. }
  530. }
  531. // not ras interace
  532. else {
  533. InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
  534. }
  535. }
  536. IGMP_FREE_NOT_NULL(pgie->V3InclusionList);
  537. IGMP_FREE(pgie);
  538. Trace0(LEAVE1, "Leaving _DeleteGIEntry");
  539. return NO_ERROR;
  540. }//end _DeleteGIEntry
  541. //------------------------------------------------------------------------------
  542. // _DeleteAllGIEntries
  543. //
  544. // Repeatedly calls _DeleteGIEntryFromIf() to delete each GI entry from the list.
  545. // If there are a lot of GI entries, optimizes on the GroupBucket locks
  546. // by grouping all GI entries hashing to the same bucket and then acquiring
  547. // GroupBucket locks to delete them.
  548. //
  549. // Locks: interface_group_list lock not req. exclusive interface lock not req.
  550. // as the interface has been removed from external lists.
  551. // Calls: Repeatedly calls _DeleteGIEntryFromIf() to remove each GI entry
  552. // Called by: _DeActivateInterfaceComplete()
  553. //------------------------------------------------------------------------------
  554. VOID
  555. DeleteAllGIEntries(
  556. PIF_TABLE_ENTRY pite
  557. )
  558. {
  559. PLIST_ENTRY pHead, ple, pleOld;
  560. PGI_ENTRY pgie;
  561. DWORD dwGroup;
  562. //
  563. // concatenate ListOfSameIfGroupsNew at the end of ListOfSameIfGroups so
  564. // that I have to delete only one list
  565. //
  566. CONCATENATE_LISTS(pite->ListOfSameIfGroups, pite->ListOfSameIfGroupsNew);
  567. // if ras interface then return as list will be deleted through RAS clients
  568. if (IS_RAS_SERVER_IF(pite->IfType))
  569. return;
  570. pHead = &pite->ListOfSameIfGroups;
  571. if (IsListEmpty(pHead))
  572. return;
  573. //--------------------------------------------------------
  574. // do optimization only if there are lots of GI entries
  575. //--------------------------------------------------------
  576. if (pite->Info.CurrentGroupMemberships > GROUP_HASH_TABLE_SZ*2) {
  577. DWORD i;
  578. LIST_ENTRY TmpGroupTable[GROUP_HASH_TABLE_SZ];
  579. // initialize the temp group table
  580. for (i=0; i<GROUP_HASH_TABLE_SZ; i++) {
  581. InitializeListHead(&TmpGroupTable[i]);
  582. }
  583. // move the GI entries to the temp group table using LinkBySameIfGroups
  584. // LinkBySameIfGroups is not used anymore
  585. pHead = &pite->ListOfSameIfGroups;
  586. for (ple=pHead->Flink; ple!=pHead; ) {
  587. // remove from old list
  588. pleOld = ple;
  589. ple = ple->Flink;
  590. RemoveEntryList(pleOld);
  591. pgie = CONTAINING_RECORD(pleOld, GI_ENTRY, LinkBySameIfGroups);
  592. dwGroup = pgie->pGroupTableEntry->Group;
  593. // put in appropriate bucket
  594. InsertHeadList(&TmpGroupTable[GROUP_HASH_VALUE(dwGroup)],
  595. &pgie->LinkBySameIfGroups);
  596. }
  597. //
  598. // now delete GI entries going by all groups which hash to same bucket
  599. //
  600. for (i=0; i<GROUP_HASH_TABLE_SZ; i++) {
  601. if (IsListEmpty(&TmpGroupTable[i]))
  602. continue;
  603. //
  604. // LOCK GROUP BUCKET (done use ACQUIRE_GROUP_LOCK macros)
  605. //
  606. ACQUIRE_GROUP_LOCK(i, "_DeleteAllGIEntries");
  607. pHead = &TmpGroupTable[i];
  608. // delete all GI entries that hash to that bucket
  609. for (ple=pHead->Flink; ple!=pHead; ) {
  610. pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
  611. ple=ple->Flink;
  612. //
  613. // remove the entry from the group's GI list and update
  614. // statistics. If group's GI list becomes empty, removes group
  615. //
  616. DeleteGIEntryFromIf(pgie);
  617. }
  618. RELEASE_GROUP_LOCK(i, "_DeleteAllGIEntries");
  619. }
  620. InitializeListHead(&pite->ListOfSameIfGroups);
  621. return;
  622. }
  623. //-----------------------------------------------------------
  624. // NO OPTIMIZATION
  625. //-----------------------------------------------------------
  626. pHead = &pite->ListOfSameIfGroups;
  627. //
  628. // delete all GI entries hanging from that interface.
  629. //
  630. for (ple=pHead->Flink; ple!=pHead; ) {
  631. pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
  632. ple=ple->Flink;
  633. dwGroup = pgie->pGroupTableEntry->Group;
  634. // LOCK GROUP BUCKET
  635. ACQUIRE_GROUP_LOCK(dwGroup,
  636. "_DeActivateInterfaceComplete");
  637. DeleteGIEntryFromIf(pgie);
  638. RELEASE_GROUP_LOCK(dwGroup, "_DeActivateInterfaceComplete");
  639. }
  640. InitializeListHead(&pite->ListOfSameIfGroups);
  641. return;
  642. }
  643. //------------------------------------------------------------------------------
  644. // _DeleteGIEntryFromIf
  645. //
  646. // Called to delete a GI entry when an interface/RAS client is being deleted.
  647. // The GI entries cannot be accessed from anywhere except through enumeration of
  648. // group list.
  649. //
  650. // Locks: Assumes lock on the group bucket. lock on IfGroup list not req.
  651. // Called by: _DeleteAllGIEntries() which in turn called by
  652. // _DeActivateInterfaceComplete().
  653. //------------------------------------------------------------------------------
  654. VOID
  655. DeleteGIEntryFromIf (
  656. PGI_ENTRY pgie //group interface entry
  657. )
  658. {
  659. PIF_TABLE_ENTRY pite = pgie->pIfTableEntry;
  660. PGROUP_TABLE_ENTRY pge = pgie->pGroupTableEntry;
  661. PLIST_ENTRY pHead, ple;
  662. DWORD IfIndex = pite->IfIndex;
  663. Trace1(ENTER1, "Entering _DeleteGIEntryFromIf(): IfIndex(%0x)", IfIndex);
  664. //
  665. // delete sources
  666. //
  667. if (pgie->Version==3) {
  668. PLIST_ENTRY pleSrc, pHeadSrc;
  669. pHeadSrc = &pgie->V3InclusionListSorted;
  670. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
  671. PGI_SOURCE_ENTRY pSourceEntry;
  672. pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
  673. pleSrc=pleSrc->Flink;
  674. IGMP_FREE(pSourceEntry);
  675. }
  676. pHeadSrc = &pgie->V3ExclusionList;
  677. for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ){
  678. PGI_SOURCE_ENTRY pSourceEntry;
  679. pSourceEntry = CONTAINING_RECORD(pleSrc, GI_SOURCE_ENTRY, LinkSources);
  680. pleSrc=pleSrc->Flink;
  681. IGMP_FREE(pSourceEntry);
  682. }
  683. }
  684. //
  685. // Remove pgie from gi list. Dont have to remove from ListBySameIfGroups
  686. //
  687. RemoveEntryList(&pgie->LinkByGI);
  688. InterlockedDecrement(&pge->NumVifs);
  689. //
  690. // if group has no more interfaces hanging from it, then delete it
  691. // and update statistics
  692. //
  693. if (IsListEmpty(&pge->ListOfGIs)) {
  694. // have to lock the group-list before deleting any group
  695. ACQUIRE_GROUP_LIST_LOCK("_DeleteGIEntryFromIf");
  696. RemoveEntryList(&pge->LinkByGroup);
  697. RELEASE_GROUP_LIST_LOCK("_DeleteGIEntryFromIf");
  698. RemoveEntryList(&pge->HTLinkByGroup);
  699. IGMP_FREE(pge);
  700. InterlockedDecrement(&g_Info.CurrentGroupMemberships);
  701. }
  702. IGMP_FREE_NOT_NULL(pgie->V3InclusionList);
  703. IGMP_FREE(pgie);
  704. Trace1(LEAVE1, "Leaving _DeleteGIEntryFromIf(%d)", IfIndex);
  705. return;
  706. }//end _DeleteGIEntryFromIf
  707. //------------------------------------------------------------------------------
  708. // DebugPrintIfConfig
  709. //------------------------------------------------------------------------------
  710. VOID
  711. DebugPrintIfConfig (
  712. PIGMP_MIB_IF_CONFIG pConfigExt,
  713. DWORD IfIndex
  714. )
  715. {
  716. DWORD i;
  717. PCHAR StaticGroupStr[5];
  718. BOOL bVersion3 = IS_CONFIG_IGMP_V3(pConfigExt);
  719. Trace1(CONFIG, "Printing Config Info for interface(%0x)", IfIndex);
  720. Trace1(CONFIG, "Version: 0x%0x", pConfigExt->Version);
  721. Trace1(CONFIG, "IfType: %d", pConfigExt->IfType);
  722. {
  723. CHAR str[150];
  724. strcpy(str, "");
  725. if (pConfigExt->Flags&IGMP_INTERFACE_ENABLED_IN_CONFIG)
  726. strcat(str, "IF_ENABLED ");
  727. else
  728. strcat(str, "IF_DISABLED ");
  729. if (pConfigExt->Flags&IGMP_ACCEPT_RTRALERT_PACKETS_ONLY)
  730. strcat(str, "RTRALERT_PACKETS_ONLY ");
  731. Trace1(CONFIG, "Flags: %s", str);
  732. }
  733. Trace1(CONFIG, "IgmpProtocolType: %d", pConfigExt->IgmpProtocolType);
  734. Trace1(CONFIG, "RobustnessVariable: %d", pConfigExt->RobustnessVariable);
  735. Trace1(CONFIG, "StartupQueryInterval: %d",
  736. pConfigExt->StartupQueryInterval);
  737. Trace1(CONFIG, "StartupQueryCount : %d",
  738. pConfigExt->StartupQueryCount);
  739. Trace1(CONFIG, "GenQueryInterval: %d", pConfigExt->GenQueryInterval);
  740. Trace1(CONFIG, "GenQueryMaxResponseTime: %d",
  741. pConfigExt->GenQueryMaxResponseTime);
  742. Trace1(CONFIG, "LastMemQueryInterval: %d (ms)",
  743. pConfigExt->LastMemQueryInterval);
  744. Trace1(CONFIG, "LastMemQueryCount: %d", pConfigExt->LastMemQueryCount);
  745. Trace1(CONFIG, "OtherQuerierPresentInterval:%d",
  746. pConfigExt->OtherQuerierPresentInterval);
  747. Trace1(CONFIG, "GroupMembershipTimeout: %d",
  748. pConfigExt->GroupMembershipTimeout);
  749. if (pConfigExt->NumStaticGroups>0) {
  750. PIGMP_STATIC_GROUP pStaticGroup;
  751. PSTATIC_GROUP_V3 pStaticGroupV3;
  752. Trace1(CONFIG, "NumStaticGroups: %d",
  753. pConfigExt->NumStaticGroups);
  754. pStaticGroup = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt);
  755. if (bVersion3) {
  756. pStaticGroupV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
  757. Trace0(CONFIG, " Group Mode(Host/MGM) Filter(In/Ex) "
  758. "NumSources");
  759. }
  760. else
  761. Trace0(CONFIG, " Group Mode(Host/MGM)");
  762. for (i=0; i<pConfigExt->NumStaticGroups; i++){
  763. if (bVersion3) {
  764. DWORD j;
  765. Trace5(CONFIG, "%d. %15s %d %d %d",
  766. i+1, INET_NTOA(pStaticGroupV3->GroupAddr),
  767. pStaticGroupV3->Mode, pStaticGroupV3->FilterType,
  768. pStaticGroupV3->NumSources
  769. );
  770. for (j=0; j<pStaticGroupV3->NumSources; j++) {
  771. Trace1(CONFIG, " %d.%d.%d.%d",
  772. PRINT_IPADDR(pStaticGroupV3->Sources[j]));
  773. }
  774. pStaticGroupV3 = (PSTATIC_GROUP_V3)
  775. GET_NEXT_STATIC_GROUP_V3(pStaticGroupV3);
  776. }
  777. else {
  778. Trace3(CONFIG, "%d. %15s Mode:%d",
  779. i+1, INET_NTOA(pStaticGroup->GroupAddr),
  780. pStaticGroup->Mode
  781. );
  782. pStaticGroup++;
  783. }
  784. }
  785. }
  786. Trace0(CONFIG, "");
  787. return;
  788. }
  789. //------------------------------------------------------------------------------
  790. // CopyinIfConfigAndUpdate
  791. //
  792. // Copies the if config struct passed by mib to igmp and update the timers
  793. // and does static joins if req.
  794. // Called when the interface is activated
  795. //------------------------------------------------------------------------------
  796. DWORD
  797. CopyinIfConfigAndUpdate (
  798. PIF_TABLE_ENTRY pite,
  799. PIGMP_MIB_IF_CONFIG pConfigExt,
  800. ULONG IfIndex
  801. )
  802. {
  803. PIGMP_IF_CONFIG pConfig = &pite->Config;
  804. BOOL bGroupMembershipTimer=FALSE, bLastMemQueryTimer=FALSE;
  805. ULONG NewStartupQueryInterval, NewGenQueryInterval,
  806. NewGenQueryMaxResponseTime, NewLastMemQueryInterval,
  807. NewOtherQuerierPresentInterval, NewGroupMembershipTimeout;
  808. BOOL bFound;
  809. DWORD Error=NO_ERROR;
  810. DWORD bVer3=IS_CONFIG_IGMP_V3(pConfigExt);
  811. NewStartupQueryInterval
  812. = CONFIG_TO_INTERNAL_TIME(pConfigExt->StartupQueryInterval);
  813. NewGenQueryInterval
  814. = CONFIG_TO_INTERNAL_TIME(pConfigExt->GenQueryInterval);
  815. NewGenQueryMaxResponseTime
  816. = CONFIG_TO_INTERNAL_TIME(pConfigExt->GenQueryMaxResponseTime);
  817. NewOtherQuerierPresentInterval
  818. = CONFIG_TO_INTERNAL_TIME(pConfigExt->OtherQuerierPresentInterval);
  819. NewLastMemQueryInterval = pConfigExt->LastMemQueryInterval; //already in ms
  820. NewGroupMembershipTimeout
  821. = CONFIG_TO_INTERNAL_TIME(pConfigExt->GroupMembershipTimeout);
  822. //
  823. // used only in ver3
  824. //
  825. pConfig->RobustnessVariableOld = pConfigExt->RobustnessVariable;
  826. pConfig->GenQueryIntervalOld = NewGenQueryInterval;
  827. pConfig->OtherQuerierPresentIntervalOld
  828. = NewOtherQuerierPresentInterval;
  829. pConfig->GroupMembershipTimeoutOld = NewGroupMembershipTimeout;
  830. //
  831. // update values only if it is ver1,ver2 or ver3&&Querier
  832. //
  833. if (!IS_IF_VER3(pite) || (IS_IF_VER3(pite) && IS_QUERIER(pite)) ){
  834. ACQUIRE_TIMER_LOCK("_CopyinIfConfigAndUpdate");
  835. //
  836. // change Info.StartupQueryCountCurrent if it was set to some very high value.
  837. // During startup, Info.StartupQueryCountCurrent is used, and not the Config value.
  838. //
  839. if (pConfigExt->StartupQueryCount < pite->Info.StartupQueryCountCurrent)
  840. InterlockedExchange(&pite->Info.StartupQueryCountCurrent,
  841. pConfigExt->StartupQueryCount);
  842. // in startup mode. StartupQueryInterval active and to be reduced
  843. if (pite->Info.StartupQueryCountCurrent>0) {
  844. if ( (NewStartupQueryInterval < pConfig->StartupQueryInterval)
  845. && (IS_TIMER_ACTIVE(pite->QueryTimer)) )
  846. {
  847. UpdateLocalTimer(&pite->QueryTimer, NewStartupQueryInterval, DBG_Y);
  848. }
  849. }
  850. // in querier mode. GenQueryInterval is active and to be updated
  851. else {
  852. if ( (NewGenQueryInterval < pConfig->GenQueryInterval)
  853. && (IS_TIMER_ACTIVE(pite->QueryTimer)) )
  854. {
  855. UpdateLocalTimer(&pite->QueryTimer, NewGenQueryInterval, DBG_Y);
  856. }
  857. }
  858. // OtherQuerierPresentInterval active and to be updated
  859. if ( (NewOtherQuerierPresentInterval<pConfig->OtherQuerierPresentInterval)
  860. && (IS_TIMER_ACTIVE(pite->NonQueryTimer)) )
  861. {
  862. UpdateLocalTimer(&pite->NonQueryTimer, NewOtherQuerierPresentInterval, DBG_Y);
  863. }
  864. // NewLastMemQueryInterval is to be processed only if in ver-2 mode and not
  865. // server
  866. if ( (pConfigExt->IgmpProtocolType==IGMP_ROUTER_V2)
  867. && (pite->IfType!=IGMP_IF_RAS_SERVER) )
  868. {
  869. if (NewLastMemQueryInterval < pConfig->LastMemQueryInterval)
  870. bLastMemQueryTimer = TRUE;
  871. }
  872. // check if GroupMembership timeout is reduced
  873. if (NewGroupMembershipTimeout < pConfig->GroupMembershipTimeout)
  874. bGroupMembershipTimer = TRUE;
  875. //
  876. // Go through the GI list for that interface (all ras clients) and update
  877. // their timers if they are higher
  878. //
  879. if ( ((bLastMemQueryTimer||bGroupMembershipTimer)&&(!IS_RAS_SERVER_IF(pite->IfType)))
  880. || ((bGroupMembershipTimer)&&(IS_RAS_SERVER_IF(pite->IfType))) )
  881. {
  882. PLIST_ENTRY pHead, ple;
  883. PGI_ENTRY pgie;
  884. LONGLONG llNewLastMemQueryInterval, llNewGroupMembershipTimeout;
  885. LONGLONG llMaxTime, llCurTime = GetCurrentIgmpTime();
  886. //
  887. // get the absolute timeout values
  888. //
  889. llNewLastMemQueryInterval = llCurTime
  890. + CONFIG_TO_SYSTEM_TIME(NewLastMemQueryInterval);
  891. llNewGroupMembershipTimeout = llCurTime
  892. + CONFIG_TO_SYSTEM_TIME(NewGroupMembershipTimeout);
  893. // if not ras interface, then go through the list from interface
  894. if ( !IS_RAS_SERVER_IF(pite->IfType)) {
  895. // merge the IfGroup lists
  896. MergeIfGroupsLists(pite);
  897. pHead = &pite->ListOfSameIfGroups;
  898. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  899. pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
  900. // update LastMemQueryTimer/V3SourcesQueryTimer if it is active and has a higher value
  901. if (bLastMemQueryTimer && IS_TIMER_ACTIVE(pgie->LastMemQueryTimer)
  902. && (llNewLastMemQueryInterval<pgie->LastMemQueryTimer.Timeout))
  903. {
  904. UpdateLocalTimer(&pgie->LastMemQueryTimer,
  905. NewLastMemQueryInterval, DBG_Y);
  906. }
  907. if (bLastMemQueryTimer && IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer)
  908. && (llNewLastMemQueryInterval<pgie->V3SourcesQueryTimer.Timeout))
  909. {
  910. UpdateLocalTimer(&pgie->V3SourcesQueryTimer,
  911. NewLastMemQueryInterval, DBG_Y);
  912. }
  913. // update GroupMembershipTimeout if it is active and has a higher value
  914. if (bGroupMembershipTimer
  915. && IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)
  916. && (llNewGroupMembershipTimeout<pgie->GroupMembershipTimer.Timeout))
  917. {
  918. UpdateLocalTimer(&pgie->GroupMembershipTimer,
  919. NewGroupMembershipTimeout, DBG_Y);
  920. }
  921. // update LastVer1ReportTimer/LastVer2ReportTimer if it is active and has a higher value
  922. // LastVer1ReportTimeout is set to GroupMembershipTimeout
  923. if (bGroupMembershipTimer
  924. && IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer)
  925. && (llNewGroupMembershipTimeout<pgie->LastVer1ReportTimer.Timeout))
  926. {
  927. UpdateLocalTimer(&pgie->LastVer1ReportTimer,
  928. NewGroupMembershipTimeout, DBG_Y);
  929. }
  930. if (bGroupMembershipTimer
  931. && IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer)
  932. && (llNewGroupMembershipTimeout<pgie->LastVer2ReportTimer.Timeout))
  933. {
  934. UpdateLocalTimer(&pgie->LastVer2ReportTimer,
  935. NewGroupMembershipTimeout, DBG_Y);
  936. }
  937. }
  938. }
  939. // IS_RAS_SERVER_IF: process for all clients. have to process
  940. // GroupMembershipTimeout only
  941. else {
  942. PLIST_ENTRY pHeadClient, pleClient;
  943. PRAS_TABLE_ENTRY prte;
  944. PRAS_TABLE prt = pite->pRasTable;
  945. //
  946. // process GI list of each ras client
  947. //
  948. pHeadClient = &pite->pRasTable->ListByAddr;
  949. for (pleClient=pHeadClient->Flink; pleClient!=pHeadClient;
  950. pleClient=pleClient->Flink)
  951. {
  952. prte = CONTAINING_RECORD(pleClient, RAS_TABLE_ENTRY, LinkByAddr);
  953. pHead = &prte->ListOfSameClientGroups;
  954. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  955. pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups);
  956. if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)
  957. && (llNewGroupMembershipTimeout
  958. <pgie->GroupMembershipTimer.Timeout))
  959. {
  960. UpdateLocalTimer(&pgie->GroupMembershipTimer,
  961. NewGroupMembershipTimeout, DBG_Y);
  962. }
  963. }
  964. }
  965. }
  966. }
  967. RELEASE_TIMER_LOCK("_CopyinIfConfigAndUpdate");
  968. //
  969. // finally copy the new values
  970. //
  971. CopyMemory(pConfig, pConfigExt, sizeof(IGMP_MIB_IF_CONFIG));
  972. pConfig->StartupQueryInterval = NewStartupQueryInterval;
  973. pConfig->GenQueryInterval = NewGenQueryInterval;
  974. pConfig->GenQueryMaxResponseTime = NewGenQueryMaxResponseTime;
  975. pConfig->LastMemQueryInterval = NewLastMemQueryInterval;
  976. pConfig->OtherQuerierPresentInterval = NewOtherQuerierPresentInterval;
  977. pConfig->GroupMembershipTimeout = NewGroupMembershipTimeout;
  978. pConfig->IfIndex = IfIndex;
  979. }
  980. pConfig->NumStaticGroups = 0;
  981. return Error;
  982. #if 0
  983. {
  984. PSTATIC_GROUP_V3 pStaticGroupExt;
  985. PIF_STATIC_GROUP pStaticGroup;
  986. PLIST_ENTRY ple, pHead;
  987. DWORD i, GroupAddr;
  988. SOCKADDR_IN saLocalIf;
  989. //
  990. // delete all static groups which are different in the old config
  991. //
  992. pHead = &pite->Config.ListOfStaticGroups;
  993. for (ple=pHead->Flink; ple!=pHead; ) {
  994. pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
  995. GroupAddr = pStaticGroup->GroupAddr;
  996. ple = ple->Flink;
  997. bFound = FALSE;
  998. pStaticGroupExt = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
  999. for (i=0; i<pConfigExt->NumStaticGroups; i++) {
  1000. if ( (GroupAddr == pStaticGroupExt->GroupAddr)
  1001. && (pStaticGroup->Mode == pStaticGroupExt->Mode) )
  1002. {
  1003. bFound = TRUE;
  1004. break;
  1005. }
  1006. pStaticGroupExt = GET_NEXT_STATIC_GROUP_V3(pStaticGroupExt);
  1007. }
  1008. //
  1009. // group exists in old and new config. check for changes in sources.
  1010. //
  1011. if (bFound && bVer3) {
  1012. if (pStaticGroupExt->NumSources==0) {
  1013. //delete all static sources
  1014. }
  1015. if (pStaticGroupExt->NumSources==0 &&
  1016. pStaticGroupExt->FilterType!=EXCLUSION) {
  1017. // delete the static group
  1018. }
  1019. // check for differences in sources
  1020. }
  1021. // if old static group not found in new list, delete it
  1022. // Router
  1023. if (IS_CONFIG_IGMPRTR(pConfig)) {
  1024. if (pStaticGroup->Mode==IGMP_HOST_JOIN) {
  1025. LeaveMulticastGroup(pite->StaticGroupSocket, GroupAddr,
  1026. pite->IfIndex, pite->IpAddr, 0 );
  1027. }
  1028. else {
  1029. PGROUP_TABLE_ENTRY pge;
  1030. PGI_ENTRY pgie;
  1031. ACQUIRE_GROUP_LOCK(GroupAddr, "_CopyinIfConfigAndUpdate");
  1032. pge = GetGroupFromGroupTable(GroupAddr, NULL, 0);
  1033. pgie = GetGIFromGIList(pge, pite, 0, STATIC_GROUP, NULL, 0);
  1034. pgie->bStaticGroup = 0;
  1035. if (bVer3) {
  1036. PLIST_ENTRY pHead, ple;
  1037. PGI_SOURCE_ENTRY pSourceEntry;
  1038. //
  1039. // delete all static source entries
  1040. //
  1041. pHead = &pgie->V3ExclusionList;
  1042. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1043. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources);
  1044. // delete source entry (forward the packets)
  1045. if (pSourceEntry->bStaticSource) {
  1046. DeleteSourceEntry(pSourceEntry, MGM_YES);
  1047. }
  1048. }
  1049. pHead = &pgie->V3InclusionListSorted;
  1050. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1051. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
  1052. if (pSourceEntry->bStaticSource) {
  1053. pSourceEntry->bStaticSource = FALSE;
  1054. if (!IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
  1055. DeleteSourceEntry(pSourceEntry, MGM_YES);
  1056. }
  1057. }
  1058. }
  1059. else {
  1060. if (!(pgie->GroupMembershipTimer.Status&TIMER_STATUS_ACTIVE))
  1061. DeleteGIEntry(pgie, TRUE, TRUE);
  1062. }
  1063. RELEASE_GROUP_LOCK(GroupAddr, "_CopyinIfConfigAndUpdate");
  1064. }
  1065. }
  1066. // Proxy Interface
  1067. else {
  1068. if (bVer3){
  1069. for (i=0; i<pStaticGroup->NumSources; i++){
  1070. ProcessProxyGroupChange(pStaticGroup->Sources[i],
  1071. GroupAddr, DELETE_FLAG, STATIC_GROUP);
  1072. }
  1073. }
  1074. if (!bVer3 || pStaticGroup->NumSources==0)
  1075. ProcessProxyGroupChange(0,GroupAddr, DELETE_FLAG, STATIC_GROUP);
  1076. }
  1077. RemoveEntryList(&pStaticGroup->Link);
  1078. IGMP_FREE(pStaticGroup);
  1079. }
  1080. //
  1081. // for all new static groups, if not in old list, create it
  1082. //
  1083. pStaticGroupExt = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
  1084. for (i=0; i<pConfigExt->NumStaticGroups; i++,pStaticGroupExt++) {
  1085. pHead = &pite->Config.ListOfStaticGroups;
  1086. bFound = FALSE;
  1087. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1088. pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
  1089. if (pStaticGroup->GroupAddr==pStaticGroupExt->GroupAddr) {
  1090. bFound = TRUE;
  1091. break;
  1092. }
  1093. }
  1094. // not found: create the new static group
  1095. if (!bFound) {
  1096. pStaticGroup = IGMP_ALLOC(
  1097. IGMP_MIB_STATIC_GROUP_SIZE(pConfigExt,
  1098. pStaticGroupExt), 0x100000,IfIndex);
  1099. PROCESS_ALLOC_FAILURE3(pStaticGroup,
  1100. "error %d allocating %d bytes for static group for IF:%0x",
  1101. Error, sizeof(IF_STATIC_GROUP), pite->IfIndex,
  1102. return Error);
  1103. memcpy(pStaticGroup, pStaticGroupExt,
  1104. IGMP_MIB_STATIC_GROUP_SIZE(pConfigExt, pStaticGroupExt));
  1105. InsertHeadList(&pConfig->ListOfStaticGroups, &pStaticGroup->Link);
  1106. if (IS_IF_ACTIVATED(pite)) {
  1107. // if proxy
  1108. if (IS_CONFIG_IGMPPROXY(pConfig)) {
  1109. if (pStaticGroup->NumSources==0)
  1110. ProcessProxyGroupChange(0, pStaticGroup->GroupAddr,
  1111. ADD_FLAG, STATIC_GROUP);
  1112. else {
  1113. for (i=0; i<pStaticGroup->NumSources; i++) {
  1114. ProcessProxyGroupChange(pStaticGroup->Sources[i],
  1115. pStaticGroup->GroupAddr,
  1116. ADD_FLAG, STATIC_GROUP);
  1117. }
  1118. }
  1119. }
  1120. // Add static group to Router
  1121. else {
  1122. if (pStaticGroup->Mode==IGMP_HOST_JOIN) {
  1123. if (!bVer3) {
  1124. JoinMulticastGroup(pite->StaticGroupSocket,
  1125. pStaticGroup->GroupAddr,
  1126. pite->IfIndex,
  1127. pite->IpAddr,
  1128. 0
  1129. );
  1130. }
  1131. else {
  1132. // include filter
  1133. if (pStaticGroup->FilterType==INCLUSION) {
  1134. if (pStaticGroup->NumSources==0) {
  1135. JoinMulticastGroup(pite->StaticGroupSocket,
  1136. pStaticGroup->GroupAddr,
  1137. pite->IfIndex,
  1138. pite->IpAddr,
  1139. 0
  1140. );
  1141. }
  1142. for (i=0; i<pStaticGroup->NumSources; i++) {
  1143. JoinMulticastGroup(pite->StaticGroupSocket,
  1144. pStaticGroup->GroupAddr,
  1145. pite->IfIndex,
  1146. pite->IpAddr,
  1147. pStaticGroup->Sources[i]
  1148. );
  1149. }
  1150. }
  1151. // exclude filter
  1152. else {
  1153. if (pStaticGroup->NumSources==0) {
  1154. JoinMulticastGroup(pite->StaticGroupSocket,
  1155. pStaticGroup->GroupAddr,
  1156. pite->IfIndex,
  1157. pite->IpAddr,
  1158. 0
  1159. );
  1160. }
  1161. for (i=0; i<pStaticGroup->NumSources; i++) {
  1162. BlockSource(pite->StaticGroupSocket,
  1163. pStaticGroup->GroupAddr,
  1164. pite->IfIndex,
  1165. pite->IpAddr,
  1166. pStaticGroup->Sources[i]
  1167. );
  1168. }
  1169. }
  1170. }
  1171. }
  1172. // IGMPRTR_MGM_ONLY
  1173. else {
  1174. PGROUP_TABLE_ENTRY pge;
  1175. PGI_ENTRY pgie;
  1176. BOOL bCreate;
  1177. PGI_SOURCE_ENTRY pSourceEntry;
  1178. GroupAddr = pStaticGroup->GroupAddr;
  1179. ACQUIRE_GROUP_LOCK(GroupAddr,
  1180. "_CopyinIfConfigAndUpdate");
  1181. bCreate = TRUE;
  1182. pge = GetGroupFromGroupTable(GroupAddr, &bCreate, 0);
  1183. bCreate = TRUE;
  1184. pgie = GetGIFromGIList(pge, pite, 0,
  1185. (pStaticGroup->NumSources==0)
  1186. ?STATIC_GROUP:NOT_STATIC_GROUP,
  1187. &bCreate, 0);
  1188. for (i=0; i<pStaticGroup->NumSources; i++) {
  1189. if (pStaticGroup->FilterType!=pgie->FilterType) {
  1190. pSourceEntry = GetSourceEntry(pgie,
  1191. pStaticGroup->Sources[i],
  1192. pStaticGroup->FilterType ^ 1,
  1193. NULL, 0, 0);
  1194. if (pSourceEntry) {
  1195. pSourceEntry->bStaticSource = TRUE;
  1196. ChangeSourceFilterMode(pgie,
  1197. pSourceEntry);
  1198. continue;
  1199. }
  1200. }
  1201. bCreate = TRUE;
  1202. pSourceEntry = GetSourceEntry(pgie,
  1203. pStaticGroup->Sources[i],
  1204. pStaticGroup->FilterType,
  1205. &bCreate, STATIC, MGM_YES);
  1206. }
  1207. RELEASE_GROUP_LOCK(GroupAddr,
  1208. "_CopyinIfConfigAndUpdate");
  1209. }
  1210. }
  1211. }
  1212. }
  1213. }
  1214. }
  1215. return Error;
  1216. #endif
  1217. } //end _CopyinIfConfigAndUpdate
  1218. //------------------------------------------------------------------------------
  1219. // _CopyinIfConfig
  1220. // Copies the if config struct passed by mib to igmp.
  1221. // called after the interface is in disabled state
  1222. //------------------------------------------------------------------------------
  1223. DWORD
  1224. CopyinIfConfig (
  1225. PIGMP_IF_CONFIG pConfig,
  1226. PIGMP_MIB_IF_CONFIG pConfigExt,
  1227. ULONG IfIndex
  1228. )
  1229. {
  1230. DWORD Error=NO_ERROR;
  1231. CopyMemory(pConfig, pConfigExt, sizeof(IGMP_MIB_IF_CONFIG));
  1232. CONV_CONFIG_TO_INTERNAL_TIME(pConfig->StartupQueryInterval);
  1233. CONV_CONFIG_TO_INTERNAL_TIME(pConfig->GenQueryInterval);
  1234. CONV_CONFIG_TO_INTERNAL_TIME(pConfig->GenQueryMaxResponseTime);
  1235. // already in ms
  1236. //CONV_CONFIG_TO_INTERNAL_TIME(pConfig->LastMemQueryInterval);
  1237. CONV_CONFIG_TO_INTERNAL_TIME(pConfig->OtherQuerierPresentInterval);
  1238. CONV_CONFIG_TO_INTERNAL_TIME(pConfig->GroupMembershipTimeout);
  1239. pConfig->RobustnessVariableOld = pConfig->RobustnessVariable;
  1240. pConfig->GenQueryIntervalOld = pConfig->GenQueryInterval;
  1241. pConfig->OtherQuerierPresentIntervalOld
  1242. = pConfig->OtherQuerierPresentInterval;
  1243. pConfig->GroupMembershipTimeoutOld = pConfig->GroupMembershipTimeout;
  1244. pConfig->ExtSize = IgmpMibIfConfigSize(pConfigExt);
  1245. pConfig->IfIndex = IfIndex ;
  1246. pConfig->NumStaticGroups = 0;
  1247. return Error;
  1248. #if 0
  1249. {
  1250. PIGMP_STATIC_GROUP pStaticGroupExt;
  1251. PSTATIC_GROUP_V3 pStaticGroupExtV3;
  1252. PIF_STATIC_GROUP pStaticGroup;
  1253. DWORD i;
  1254. PLIST_ENTRY ple;
  1255. BOOL bVersion3=IS_CONFIG_IGMP_V3(pConfigExt);
  1256. // delete all old static groups
  1257. for (ple=pConfig->ListOfStaticGroups.Flink;
  1258. ple!=&pConfig->ListOfStaticGroups; )
  1259. {
  1260. pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
  1261. ple = ple->Flink;
  1262. IGMP_FREE(pStaticGroup);
  1263. }
  1264. // copy all static groups
  1265. InitializeListHead(&pConfig->ListOfStaticGroups);
  1266. if (bVersion3)
  1267. pStaticGroupExtV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
  1268. else
  1269. pStaticGroupExt = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt);
  1270. for (i=0; i<pConfig->NumStaticGroups; i++) {
  1271. DWORD Size = IGMP_MIB_STATIC_GROUP_SIZE(pConfigExt, pStaticGroupExtV3);
  1272. pStaticGroup = IGMP_ALLOC(Size, 0x200000,IfIndex);
  1273. PROCESS_ALLOC_FAILURE2(pStaticGroup,
  1274. "error %d allocating %d bytes for static group for IF:%0x",
  1275. Error, Size,return Error);
  1276. if (!bVersion3) {
  1277. pStaticGroup->GroupAddr = pStaticGroupExt->GroupAddr;
  1278. pStaticGroup->Mode = pStaticGroupExt->Mode;
  1279. pStaticGroupExt++;
  1280. }
  1281. else {
  1282. memcpy(pStaticGroup, pStaticGroupExtV3, Size);
  1283. pStaticGroupExtV3 = (PSTATIC_GROUP_V3)
  1284. ((PCHAR)pStaticGroupExtV3 + Size);
  1285. }
  1286. InsertHeadList(&pConfig->ListOfStaticGroups, &pStaticGroup->Link);
  1287. }
  1288. }
  1289. #endif
  1290. }
  1291. //------------------------------------------------------------------------------
  1292. // _CopyoutIfConfig
  1293. //------------------------------------------------------------------------------
  1294. VOID
  1295. CopyoutIfConfig (
  1296. PIGMP_MIB_IF_CONFIG pConfigMib,
  1297. PIF_TABLE_ENTRY pite
  1298. )
  1299. {
  1300. PIGMP_IF_CONFIG pConfig = &pite->Config;
  1301. BOOL bVersion3 = IS_CONFIG_IGMP_V3(pConfig);
  1302. //
  1303. // the initial IGMP_MIB_IF_CONFIG size of struct is common
  1304. //
  1305. CopyMemory(pConfigMib, pConfig, sizeof(IGMP_MIB_IF_CONFIG));
  1306. CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->StartupQueryInterval);
  1307. CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->GenQueryInterval);
  1308. CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->GenQueryMaxResponseTime);
  1309. // keep in ms
  1310. //CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->LastMemQueryInterval);
  1311. CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->OtherQuerierPresentInterval);
  1312. CONV_INTERNAL_TO_CONFIG_TIME(pConfigMib->GroupMembershipTimeout);
  1313. pConfigMib->IfIndex = pite->IfIndex;
  1314. pConfigMib->IpAddr = pite->IpAddr;
  1315. // have to convert the Iftype to external type
  1316. pConfigMib->IfType = GET_EXTERNAL_IF_TYPE(pite);
  1317. {
  1318. PLIST_ENTRY pHead, ple;
  1319. PIGMP_STATIC_GROUP pStaticGroupExt;
  1320. PSTATIC_GROUP_V3 pStaticGroupExtV3;
  1321. PIF_STATIC_GROUP pStaticGroup;
  1322. if (bVersion3)
  1323. pStaticGroupExtV3 = GET_FIRST_STATIC_GROUP_V3(pConfigMib);
  1324. else
  1325. pStaticGroupExt = GET_FIRST_IGMP_STATIC_GROUP(pConfigMib);
  1326. pHead = &pConfig->ListOfStaticGroups;
  1327. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1328. pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
  1329. if (bVersion3) {
  1330. memcpy(pStaticGroupExtV3,
  1331. (PCHAR)pStaticGroup+FIELD_OFFSET(IF_STATIC_GROUP,GroupAddr),
  1332. sizeof(STATIC_GROUP_V3)+pStaticGroup->NumSources*sizeof(IPADDR)
  1333. );
  1334. pStaticGroupExtV3 = GET_NEXT_STATIC_GROUP_V3(pStaticGroupExtV3);
  1335. }
  1336. else {
  1337. pStaticGroupExt->GroupAddr = pStaticGroup->GroupAddr;
  1338. pStaticGroupExt->Mode = pStaticGroup->Mode;
  1339. pStaticGroupExt++;
  1340. }
  1341. }
  1342. }
  1343. return;
  1344. }
  1345. //------------------------------------------------------------------------------
  1346. // _ValidateIfConfig
  1347. //
  1348. // Corrects some values, and returns error for some others.
  1349. // Return: ERROR_INVALID_DATA, NO_ERROR
  1350. //------------------------------------------------------------------------------
  1351. DWORD
  1352. ValidateIfConfig (
  1353. PIGMP_MIB_IF_CONFIG pConfigExt,
  1354. DWORD IfIndex,
  1355. DWORD IfType,
  1356. ULONG ulStructureVersion,
  1357. ULONG ulStructureSize
  1358. )
  1359. {
  1360. DWORD Error = NO_ERROR, i, Size;
  1361. BOOL bVersion3;
  1362. //
  1363. // verify config size
  1364. //
  1365. /*kslksl
  1366. if (ulStructureSize<sizeof(IGMP_MIB_IF_CONFIG)) {
  1367. Trace2(ERR, "IGMP config size %d very small. Expected:%d", ulStructureSize,
  1368. sizeof(IGMP_MIB_IF_CONFIG));
  1369. return ERROR_INVALID_DATA;
  1370. }
  1371. */
  1372. bVersion3 = IS_IGMP_VERSION_3(pConfigExt->Version);
  1373. {
  1374. if (!bVersion3) {
  1375. Size = sizeof(IGMP_MIB_IF_CONFIG)
  1376. + pConfigExt->NumStaticGroups*sizeof(IGMP_STATIC_GROUP);
  1377. }
  1378. else {
  1379. PSTATIC_GROUP_V3 pStaticGroupV3 = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
  1380. Size = sizeof(IGMP_MIB_IF_CONFIG)
  1381. +sizeof(STATIC_GROUP_V3)*pConfigExt->NumStaticGroups;
  1382. for (i=0; i<pConfigExt->NumStaticGroups; i++) {
  1383. Size += pStaticGroupV3->NumSources*sizeof(IPADDR);
  1384. if (ulStructureSize<Size)
  1385. break;
  1386. pStaticGroupV3 = GET_NEXT_STATIC_GROUP_V3(pStaticGroupV3);
  1387. }
  1388. }
  1389. /*kslksl
  1390. if (ulStructureSize!=Size) {
  1391. Trace0(ERR, "Invalid IGMP structure size");
  1392. return ERROR_INVALID_DATA;
  1393. }
  1394. */
  1395. }
  1396. // DebugPrintIfConfig
  1397. DebugPrintIfConfig(pConfigExt, IfIndex);
  1398. // check version
  1399. if (pConfigExt->Version >= IGMP_VERSION_3_5) {
  1400. Trace1(ERR, "Invalid version in interface config.\n"
  1401. "Create the Igmp configuration again", pConfigExt->Version);
  1402. IgmpAssertOnError(FALSE);
  1403. Logerr0(INVALID_VERSION, ERROR_INVALID_DATA);
  1404. return ERROR_INVALID_DATA;
  1405. }
  1406. //
  1407. // check the proxy/router common fields, and then check the router fields
  1408. //
  1409. //
  1410. // check the protocolType
  1411. //
  1412. switch (pConfigExt->IgmpProtocolType) {
  1413. case IGMP_ROUTER_V1 :
  1414. case IGMP_ROUTER_V2 :
  1415. {
  1416. if ( (pConfigExt->Version<IGMP_VERSION_1_2)
  1417. ||(pConfigExt->Version>=IGMP_VERSION_1_2_5) )
  1418. {
  1419. Trace1(ERR, "IGMP v1/v2 should have version %0x", IGMP_VERSION_1_2);
  1420. IgmpAssertOnError(FALSE);
  1421. return ERROR_INVALID_DATA;
  1422. }
  1423. break;
  1424. }
  1425. case IGMP_ROUTER_V3:
  1426. {
  1427. if (pConfigExt->Version<IGMP_VERSION_3 || pConfigExt->Version>=IGMP_VERSION_3_5) {
  1428. Trace1(ERR, "IGMP v3 should have version %0x", IGMP_VERSION_3);
  1429. IgmpAssertOnError(FALSE);
  1430. return ERROR_INVALID_DATA;
  1431. }
  1432. break;
  1433. }
  1434. case IGMP_PROXY :
  1435. case IGMP_PROXY_V3 :
  1436. break;
  1437. // if none of above, then return error
  1438. default : {
  1439. Trace2(ERR,
  1440. "Error: IGMP protocol type(%d) for interface(%0x) invalid",
  1441. pConfigExt->IgmpProtocolType, IfIndex);
  1442. IgmpAssertOnError(FALSE);
  1443. Logerr2(INVALID_PROTOTYPE, "%d%d", pConfigExt->IgmpProtocolType,
  1444. IfIndex, ERROR_INVALID_DATA);
  1445. return ERROR_INVALID_DATA;
  1446. }
  1447. }
  1448. // cannot configure a proxy on a ras server interface
  1449. if (IS_RAS_SERVER_IF(IfType) && IS_CONFIG_IGMPPROXY(pConfigExt)) {
  1450. Trace1(ERR,
  1451. "Error: Cannot configure Proxy on RAS server interface:%0x",
  1452. IfIndex);
  1453. IgmpAssertOnError(FALSE);
  1454. Logerr1(PROXY_ON_RAS_SERVER, "%d",IfIndex, ERROR_INVALID_DATA);
  1455. return ERROR_INVALID_DATA;
  1456. }
  1457. //
  1458. // check for static joins
  1459. //
  1460. if (pConfigExt->NumStaticGroups>0) {
  1461. DWORD i;
  1462. PIGMP_STATIC_GROUP pStaticGroup = GET_FIRST_IGMP_STATIC_GROUP(pConfigExt);
  1463. PSTATIC_GROUP_V3 pStaticGroupV3
  1464. = GET_FIRST_STATIC_GROUP_V3(pConfigExt);
  1465. for (i=0; i<pConfigExt->NumStaticGroups; i++) {
  1466. //
  1467. // make sure that the static group is a multicast address
  1468. //
  1469. if (!IS_MCAST_ADDR(pStaticGroup->GroupAddr)) {
  1470. Trace2(ERR,
  1471. "Error: Static group:%d.%d.%d.%d on IF:%0x not a multicast address",
  1472. PRINT_IPADDR(pStaticGroup->GroupAddr), IfIndex);
  1473. IgmpAssertOnError(FALSE);
  1474. Logerr2(INVALID_STATIC_GROUP, "%I%d", pStaticGroup->GroupAddr,
  1475. IfIndex, ERROR_INVALID_DATA);
  1476. return ERROR_INVALID_DATA;
  1477. }
  1478. //
  1479. // make sure that the mode of the static group is correct
  1480. //
  1481. if ( (pStaticGroup->Mode!=IGMP_HOST_JOIN
  1482. && pStaticGroup->Mode!=IGMPRTR_JOIN_MGM_ONLY)
  1483. ||(IS_CONFIG_IGMPPROXY(pConfigExt)
  1484. && pStaticGroup->Mode!=IGMP_HOST_JOIN) )
  1485. {
  1486. Trace2(ERR,
  1487. "Error: Invalid mode for static group:%d.%d.%d.%d on IF:%0x",
  1488. PRINT_IPADDR(pStaticGroup->GroupAddr), IfIndex);
  1489. IgmpAssertOnError(FALSE);
  1490. Logerr2(INVALID_STATIC_MODE, "%I%d", pStaticGroup->GroupAddr,
  1491. IfIndex, ERROR_INVALID_DATA);
  1492. return ERROR_INVALID_DATA;
  1493. }
  1494. if (bVersion3) {
  1495. DWORD EntrySize = sizeof(STATIC_GROUP_V3)
  1496. + pStaticGroupV3->NumSources*sizeof(IPADDR);
  1497. // check filter mode
  1498. if ( (pStaticGroupV3->FilterType!=INCLUSION)
  1499. && (pStaticGroupV3->FilterType!=EXCLUSION))
  1500. {
  1501. Trace2(ERR,
  1502. "Error: Invalid filter type for static group:%d.%d.%d.%d on IF:%0x",
  1503. PRINT_IPADDR(pStaticGroup->GroupAddr), IfIndex);
  1504. IgmpAssertOnError(FALSE);
  1505. Logerr2(INVALID_STATIC_FILTER, "%I%d", pStaticGroup->GroupAddr,
  1506. IfIndex, ERROR_INVALID_DATA);
  1507. return ERROR_INVALID_DATA;
  1508. }
  1509. // not checking source addresses
  1510. pStaticGroupV3 = (PSTATIC_GROUP_V3)
  1511. ((PCHAR)pStaticGroupV3 + EntrySize);
  1512. pStaticGroup = (PIGMP_STATIC_GROUP)pStaticGroupV3;
  1513. }
  1514. else {
  1515. pStaticGroup ++;
  1516. }
  1517. }
  1518. }
  1519. //
  1520. // if it is a proxy interface, then none of the config variables other than
  1521. // static group is used. I return no_error
  1522. //
  1523. if (IS_CONFIG_IGMPPROXY(pConfigExt))
  1524. return NO_ERROR;
  1525. // robustness variable must be greater than 0
  1526. if (pConfigExt->RobustnessVariable<=0) {
  1527. Trace1(ERR, "Error RobustnessVariable for Interface(%d) cannot be 0.",
  1528. IfIndex);
  1529. Logerr2(INVALID_ROBUSTNESS, "%d%d", pConfigExt->RobustnessVariable,
  1530. IfIndex, ERROR_INVALID_DATA);
  1531. return ERROR_INVALID_DATA;
  1532. }
  1533. // if robustness variable == 1, then log a warning
  1534. if (pConfigExt->RobustnessVariable==1) {
  1535. Trace1(ERR,
  1536. "Warning: Robustness variable for interface (%d) being set to 1",
  1537. IfIndex);
  1538. Logwarn0(ROBUSTNESS_VARIABLE_EQUAL_1, NO_ERROR);
  1539. }
  1540. // if robustness variable > 7, then I correct it to 7 and log a warning
  1541. if (pConfigExt->RobustnessVariable>7) {
  1542. Trace2(ERR, "RobustnessVariable for Interface(%0x) too high(%d)."
  1543. "Being set to 7", IfIndex, pConfigExt->RobustnessVariable);
  1544. Logwarn2(INVALID_ROBUSTNESS, "%d%d", pConfigExt->RobustnessVariable,
  1545. IfIndex, NO_ERROR);
  1546. pConfigExt->RobustnessVariable = 7;
  1547. }
  1548. // default value of GenQueryInterval is 125 sec. I force a minimum
  1549. // value of 10 secs to prevent trashing the network.
  1550. // max of 31744 as possible by exp value
  1551. if (pConfigExt->GenQueryInterval<10) {
  1552. Trace2(ERR, "GetQueryInterval for Interface(%0x) too low(%d)."
  1553. "Being set to 10", IfIndex, pConfigExt->GenQueryInterval);
  1554. pConfigExt->GenQueryInterval = 10;
  1555. }
  1556. if (pConfigExt->GenQueryInterval>31744) {
  1557. Trace2(ERR, "GetQueryInterval for Interface(%0x) too high(%d)."
  1558. "Being set to 31744", IfIndex, pConfigExt->GenQueryInterval);
  1559. pConfigExt->GenQueryInterval = 31744;
  1560. }
  1561. //
  1562. // StartupQueryInterval: default is 1/4 of GenQueryInterval
  1563. // I enforce a minimum of 1 sec and a max of GenQueryInterval
  1564. //
  1565. if (pConfigExt->StartupQueryInterval<1) {
  1566. Trace2(ERR, "StartupQueryInterval for Interface(%0x) too low(%d)."
  1567. "Being set to 1 sec", IfIndex, pConfigExt->StartupQueryInterval);
  1568. pConfigExt->StartupQueryInterval = 1;
  1569. }
  1570. if (pConfigExt->StartupQueryInterval>pConfigExt->GenQueryInterval) {
  1571. Trace3(ERR, "StartupQueryInterval(%d) for Interface(%0x) "
  1572. "higher than GenQueryInterval(%d). StartupQueryInterval set "
  1573. "to GenQueryInterval", pConfigExt->StartupQueryInterval, IfIndex,
  1574. pConfigExt->GenQueryInterval
  1575. );
  1576. pConfigExt->StartupQueryInterval = pConfigExt->GenQueryInterval;
  1577. }
  1578. //
  1579. // StartupQueryCount: default is Robustness variable
  1580. // I enforce a max of 7. (I am allowing someone to set it to 0??)
  1581. //
  1582. if (pConfigExt->StartupQueryCount>7) {
  1583. Trace2(ERR, "StartupQueryCount for IF(%0x) too high(%d). "
  1584. "Being set to 7.", IfIndex, pConfigExt->StartupQueryCount);
  1585. Logerr2(INVALID_STARTUPQUERYCOUNT, "%d%d",
  1586. pConfigExt->StartupQueryCount, IfIndex, ERROR_INVALID_DATA);
  1587. pConfigExt->StartupQueryCount = 7;
  1588. }
  1589. if ((int)pConfigExt->StartupQueryCount<0) {
  1590. Trace2(ERR,
  1591. "Error: StartupQueryCount(%d) for IF(%0x) cannot be < than 0.",
  1592. pConfigExt->StartupQueryCount, IfIndex);
  1593. Logerr2(INVALID_STARTUPQUERYCOUNT, "%d%d",
  1594. pConfigExt->StartupQueryCount, IfIndex, ERROR_INVALID_DATA);
  1595. return ERROR_INVALID_DATA;
  1596. }
  1597. //
  1598. // GenQueryMaxResponseTime: default is 10.
  1599. // Absurd if value is greater than GenQueryInterval.
  1600. // I correct the values, if required
  1601. //
  1602. if (pConfigExt->GenQueryMaxResponseTime > pConfigExt->GenQueryInterval) {
  1603. Trace3(ERR, "GenQueryMaxResponseTime(%d) for IF(%0x) "
  1604. "higher than GenQueryInterval(%d). GenQueryMaxResponseTime "
  1605. "set to GenQueryInterval", pConfigExt->GenQueryMaxResponseTime,
  1606. IfIndex, pConfigExt->GenQueryInterval);
  1607. pConfigExt->GenQueryMaxResponseTime = pConfigExt->GenQueryInterval;
  1608. }
  1609. if (pConfigExt->GenQueryMaxResponseTime > 3174) {
  1610. Trace2(ERR, "GenQueryMaxResponseTime(%d) for IF(%0x) "
  1611. "higher than 3174 "
  1612. "set to 1sec", pConfigExt->GenQueryMaxResponseTime,
  1613. IfIndex);
  1614. pConfigExt->GenQueryMaxResponseTime = 1;
  1615. }
  1616. if (pConfigExt->GenQueryMaxResponseTime <= 0) {
  1617. Trace2(ERR, "Error. GenQueryMaxResponseTime(%d) for Interface(%0x) "
  1618. "should be greater than 0.", pConfigExt->GenQueryMaxResponseTime,
  1619. IfIndex);
  1620. return ERROR_INVALID_DATA;
  1621. }
  1622. //
  1623. // check LastMemQueryCount and LastMemQueryInterval only if
  1624. // protocol type is not IGMP-Router-ver1 and it is not a ras server interface
  1625. //
  1626. if ( (pConfigExt->IgmpProtocolType!=IGMP_ROUTER_V1) && (!IS_RAS_SERVER_IF(IfType)) ) {
  1627. // LastMemQueryCount can be 0
  1628. // set max LastMemQueryCount to 7
  1629. if (pConfigExt->LastMemQueryCount>7) {
  1630. Trace2(ERR, "Warning. LastMemQueryCount(%d) for IF(%0x) "
  1631. "is too high. Resetting it to 10.", pConfigExt->LastMemQueryCount,
  1632. IfIndex);
  1633. pConfigExt->LastMemQueryCount = 10;
  1634. }
  1635. // limit LastMemQueryInterval(in ms) to GroupMembershipTimeout(in sec)
  1636. if (pConfigExt->LastMemQueryInterval>pConfigExt->GroupMembershipTimeout*1000) {
  1637. Trace3(ERR,
  1638. "Warning. LastMemberQueryInterval(%d) for IF(%0x) "
  1639. "is too high. Resetting it to GroupMembershipTimeout(%d ms).",
  1640. pConfigExt->LastMemQueryCount, IfIndex,
  1641. pConfigExt->GroupMembershipTimeout*1000
  1642. );
  1643. pConfigExt->LastMemQueryInterval = pConfigExt->GroupMembershipTimeout*1000;
  1644. }
  1645. // limit LastMemQueryInterval(in ms) to 3174(in sec)
  1646. if (pConfigExt->LastMemQueryInterval>3174*1000) {
  1647. Trace2(ERR,
  1648. "Warning. LastMemberQueryInterval(%d) for IF(%0x) "
  1649. "is too high. Resetting it to 1000ms).",
  1650. pConfigExt->LastMemQueryCount, IfIndex
  1651. );
  1652. pConfigExt->LastMemQueryInterval = 1000;
  1653. }
  1654. }
  1655. // check the value of OtherQuerierPresentInterval
  1656. if (pConfigExt->OtherQuerierPresentInterval !=
  1657. pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
  1658. + (pConfigExt->GenQueryMaxResponseTime)/2
  1659. )
  1660. {
  1661. pConfigExt->OtherQuerierPresentInterval =
  1662. pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
  1663. + (pConfigExt->GenQueryMaxResponseTime)/2;
  1664. Trace0(ERR, "Warning: OtherQuerierPresentInterval's value should be "
  1665. "RobustnessVariable*GenQueryInterval + (GenQueryMaxResponseTime)/2");
  1666. }
  1667. // check the value of GroupMembershipTimeout
  1668. if (pConfigExt->GroupMembershipTimeout !=
  1669. (pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
  1670. + pConfigExt->GenQueryMaxResponseTime) )
  1671. {
  1672. pConfigExt->GroupMembershipTimeout =
  1673. pConfigExt->RobustnessVariable*pConfigExt->GenQueryInterval
  1674. + pConfigExt->GenQueryMaxResponseTime;
  1675. Trace0(ERR, "Warning: GroupMembershipTimeout's value should be "
  1676. "RobustnessVariable*GenQueryInterval + GenQueryMaxResponseTime");
  1677. }
  1678. return Error;
  1679. } // _ValidateIfConfig
  1680. //------------------------------------------------------------------------------
  1681. // InitializeIfTable
  1682. // Creates the Interface table. The interface table size is dynamic
  1683. //------------------------------------------------------------------------------
  1684. DWORD
  1685. InitializeIfTable(
  1686. )
  1687. {
  1688. DWORD Error = NO_ERROR;
  1689. PIGMP_IF_TABLE pTable;
  1690. DWORD NumBuckets, i;
  1691. BEGIN_BREAKOUT_BLOCK1 {
  1692. // set the initial size of the interface table to IF_HASHTABLE_SZ1
  1693. NumBuckets = IF_HASHTABLE_SZ1;
  1694. //
  1695. // allocate memory for the interface table
  1696. //
  1697. g_pIfTable = IGMP_ALLOC(sizeof(IGMP_IF_TABLE), 0x400000,0);
  1698. PROCESS_ALLOC_FAILURE2(g_pIfTable,
  1699. "error %d allocating %d bytes for interface table",
  1700. Error, sizeof(IGMP_IF_TABLE),
  1701. GOTO_END_BLOCK1);
  1702. pTable = g_pIfTable;
  1703. // initialize NumBuckets and NumInterfaces
  1704. pTable->NumBuckets = NumBuckets;
  1705. pTable->NumInterfaces = 0;
  1706. //
  1707. // Initialize the IfTable lists
  1708. //
  1709. InitializeListHead(&pTable->ListByIndex);
  1710. InitializeListHead(&pTable->ListByAddr);
  1711. //
  1712. // Initialize the list CS and proxyAlertCS
  1713. //
  1714. try {
  1715. InitializeCriticalSection(&pTable->IfLists_CS);
  1716. InitializeCriticalSection(&g_ProxyAlertCS);
  1717. }
  1718. except (EXCEPTION_EXECUTE_HANDLER) {
  1719. Error = GetExceptionCode();
  1720. Trace1(ANY,
  1721. "exception %d initializing critical section in InitIfTable",
  1722. Error);
  1723. Logerr0(INIT_CRITSEC_FAILED, Error);
  1724. GOTO_END_BLOCK1;
  1725. }
  1726. //
  1727. // allocate memory for the different buckets
  1728. //
  1729. pTable->HashTableByIndex = IGMP_ALLOC(sizeof(LIST_ENTRY)*NumBuckets,
  1730. 0x800000,0);
  1731. PROCESS_ALLOC_FAILURE2(pTable->HashTableByIndex,
  1732. "error %d allocating %d bytes for interface table",
  1733. Error, sizeof(LIST_ENTRY)*NumBuckets,
  1734. GOTO_END_BLOCK1);
  1735. //
  1736. // allocate memory for the array of pointers to dynamic RWLs
  1737. //
  1738. pTable->aIfBucketDRWL
  1739. = IGMP_ALLOC(sizeof(PDYNAMIC_RW_LOCK)*NumBuckets, 0x800001,0);
  1740. PROCESS_ALLOC_FAILURE2(pTable->aIfBucketDRWL,
  1741. "error %d allocating %d bytes for interface table",
  1742. Error, sizeof(PDYNAMIC_RW_LOCK)*NumBuckets,
  1743. GOTO_END_BLOCK1);
  1744. //
  1745. // allocate memory for the array of pointers to dynamic CSs
  1746. //
  1747. pTable->aIfBucketDCS
  1748. = IGMP_ALLOC(sizeof(PDYNAMIC_CS_LOCK)*NumBuckets, 0x800002,0);
  1749. PROCESS_ALLOC_FAILURE2(pTable->aIfBucketDCS,
  1750. "error %d allocating %d bytes for interface table",
  1751. Error, sizeof(PDYNAMIC_CS_LOCK)*NumBuckets,
  1752. GOTO_END_BLOCK1);
  1753. //
  1754. // init locks to NULL, implying that the dynamic locks have not been
  1755. // allocated. and initialize the list heads.
  1756. //
  1757. for (i=0; i<NumBuckets; i++) {
  1758. InitializeListHead(&pTable->HashTableByIndex[i]);
  1759. pTable->aIfBucketDRWL[i] = NULL;
  1760. pTable->aIfBucketDCS[i] = NULL;
  1761. }
  1762. pTable->Status = 0;
  1763. } END_BREAKOUT_BLOCK1;
  1764. return Error;
  1765. } //end _InitializeIfTable
  1766. //------------------------------------------------------------------------------
  1767. // _DeInitializeIfTable
  1768. //------------------------------------------------------------------------------
  1769. VOID
  1770. DeInitializeIfTable(
  1771. )
  1772. {
  1773. PIGMP_IF_TABLE pTable = g_pIfTable;
  1774. PLIST_ENTRY pHead, ple;
  1775. PIF_TABLE_ENTRY pite;
  1776. DWORD i, dwRetval;
  1777. if (pTable==NULL)
  1778. return;
  1779. //
  1780. // for each active interface call deregister MGM.
  1781. //
  1782. // go through the list of active interfaces ordered by IpAddr
  1783. pHead = &g_pIfTable->ListByAddr;
  1784. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1785. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, LinkByAddr);
  1786. // if not activated then continue
  1787. if (!IS_IF_ACTIVATED(pite))
  1788. continue;
  1789. // deregister all interfaces, ras clients and proxy protocol from mgm
  1790. DeActivationDeregisterFromMgm(pite);
  1791. }
  1792. // delete the IfLists CS
  1793. DeleteCriticalSection(&pTable->IfLists_CS);
  1794. IGMP_FREE_NOT_NULL(pTable->aIfBucketDCS);
  1795. IGMP_FREE_NOT_NULL(pTable->aIfBucketDRWL);
  1796. IGMP_FREE_NOT_NULL(pTable->HashTableByIndex);
  1797. IGMP_FREE_NOT_NULL(g_pIfTable);
  1798. // I dont delete the different dynamic locks. They should have been deleted
  1799. // by now
  1800. return;
  1801. }
  1802. //------------------------------------------------------------------------------
  1803. // _InitializeGroupTable //
  1804. //------------------------------------------------------------------------------
  1805. DWORD
  1806. InitializeGroupTable (
  1807. )
  1808. {
  1809. BOOL bErr = TRUE;
  1810. DWORD Error = NO_ERROR;
  1811. PGROUP_TABLE pGroupTable;
  1812. DWORD i;
  1813. BEGIN_BREAKOUT_BLOCK1 {
  1814. //
  1815. // allocate space for the group table
  1816. //
  1817. g_pGroupTable = IGMP_ALLOC(sizeof(GROUP_TABLE), 0x800004,0);
  1818. PROCESS_ALLOC_FAILURE2(g_pGroupTable,
  1819. "error %d allocating %d bytes for Group table",
  1820. Error, sizeof(GROUP_TABLE),
  1821. GOTO_END_BLOCK1);
  1822. pGroupTable = g_pGroupTable;
  1823. //
  1824. // initialize group tables' dynamically locked lists
  1825. //
  1826. for (i=0; i<GROUP_HASH_TABLE_SZ; i++) {
  1827. InitDynamicCSLockedList(&pGroupTable->HashTableByGroup[i]);
  1828. }
  1829. //
  1830. // initialize list of all groups
  1831. //
  1832. try {
  1833. CREATE_LOCKED_LIST(&pGroupTable->ListByGroup);
  1834. }
  1835. except (EXCEPTION_EXECUTE_HANDLER) {
  1836. Error = GetExceptionCode();
  1837. Trace1(ERR, "Exception %d creating locked list for Group Table",
  1838. Error);
  1839. Logerr0(INIT_CRITSEC_FAILED, Error);
  1840. GOTO_END_BLOCK1;
  1841. }
  1842. //
  1843. // initialize the list of new groups
  1844. //
  1845. InitializeListHead(&pGroupTable->ListByGroupNew);
  1846. pGroupTable->NumGroupsInNewList = 0;
  1847. pGroupTable->Status = 0;
  1848. bErr = FALSE;
  1849. } END_BREAKOUT_BLOCK1;
  1850. if (!bErr) {
  1851. return Error==NO_ERROR ? ERROR_CAN_NOT_COMPLETE: Error;
  1852. }
  1853. else {
  1854. return Error;
  1855. }
  1856. } //end _InitializeGroupTable
  1857. //------------------------------------------------------------------------------
  1858. // DeInitializeGroupTable //
  1859. // Just delete the critical sections //
  1860. //------------------------------------------------------------------------------
  1861. VOID
  1862. DeInitializeGroupTable (
  1863. )
  1864. {
  1865. PGROUP_TABLE pGroupTable = g_pGroupTable;
  1866. DWORD i;
  1867. if (pGroupTable==NULL)
  1868. return;
  1869. //
  1870. // I dont try to delete the dynamically allocated locks as they should
  1871. // have all been deleted by the last thread executing in that lock
  1872. //
  1873. DeleteCriticalSection(&pGroupTable->ListByGroup.Lock);
  1874. IGMP_FREE_NOT_NULL(pGroupTable);
  1875. }
  1876. //------------------------------------------------------------------------------
  1877. // _InitializeRasTable
  1878. // creates ras table and initializes the fields.
  1879. // called by _DeActivateInterfaceInitial() _AddIfEntry()
  1880. // The interface table is created during _AddIfEntry, as _ConnectRasClients can
  1881. // be called even when the ras server interface is not activated
  1882. //------------------------------------------------------------------------------
  1883. DWORD
  1884. InitializeRasTable(
  1885. DWORD IfIndex,
  1886. PIF_TABLE_ENTRY pite
  1887. )
  1888. {
  1889. DWORD Error = NO_ERROR, i;
  1890. PRAS_TABLE prt;
  1891. //
  1892. // allocate Ras table
  1893. //
  1894. prt = IGMP_ALLOC(sizeof(RAS_TABLE), 0x800008,IfIndex);
  1895. PROCESS_ALLOC_FAILURE2(prt, "error %d allocating %d bytes for Ras Table",
  1896. Error, sizeof(RAS_TABLE),
  1897. return Error);
  1898. //set the ras table entry in pite
  1899. pite->pRasTable = prt;
  1900. // initialize list pointing to Ras Clients ordered by IpAddr
  1901. InitializeListHead(&prt->ListByAddr);
  1902. // initialize hash table containing lists pointing to Ras Clients
  1903. // hashed on IpAddr
  1904. for (i=0; i<RAS_HASH_TABLE_SZ; i++)
  1905. InitializeListHead(&prt->HashTableByAddr[i]);
  1906. // set backpointer to the interface table entry
  1907. prt->pIfTable = pite;
  1908. // set RefCount and Status
  1909. prt->RefCount = 1;
  1910. prt->Status = IF_CREATED_FLAG;
  1911. return NO_ERROR;
  1912. } //end _InitializeRasTable
  1913. //todo:remove
  1914. //------------------------------------------------------------------------------
  1915. // DeInitializeRasTable
  1916. //------------------------------------------------------------------------------
  1917. VOID
  1918. DeInitializeRasTable (
  1919. PIF_TABLE_ENTRY pite,
  1920. BOOL bFullCleanup
  1921. )
  1922. {
  1923. PRAS_TABLE prt = pite->pRasTable;
  1924. PRAS_TABLE_ENTRY prte;
  1925. PLIST_ENTRY pHeadRas, pleRas;
  1926. pHeadRas = &prt->ListByAddr;
  1927. for (pleRas=pHeadRas->Flink; pleRas!=pHeadRas; pleRas=pleRas->Flink) {
  1928. prte = CONTAINING_RECORD(pleRas, RAS_TABLE_ENTRY, LinkByAddr);
  1929. MgmReleaseInterfaceOwnership(g_MgmIgmprtrHandle, pite->IfIndex,
  1930. prte->NHAddr);
  1931. }
  1932. return;
  1933. }
  1934. //------------------------------------------------------------------------------
  1935. // _MergeIfGroupsLists
  1936. //
  1937. // Merges the new GI list with the main GI list.
  1938. // Locks: Assumes the IF-GI list to be locked.
  1939. //------------------------------------------------------------------------------
  1940. VOID
  1941. MergeIfGroupsLists(
  1942. PIF_TABLE_ENTRY pite
  1943. )
  1944. {
  1945. // sentinel is set at the end of the Main list so that all entries is inserted
  1946. // before it. its group value is set to all 1's.
  1947. GROUP_TABLE_ENTRY pgeSentinel;
  1948. GI_ENTRY giSentinel;
  1949. PGI_ENTRY giNew, giMain;
  1950. PLIST_ENTRY pHeadNew, pHeadMain, pleMain, pleNew;
  1951. Trace1(ENTER1, "Entering _MergeIfGroupLists(): IfIndex:%0x", pite->IfIndex);
  1952. pHeadNew = &pite->ListOfSameIfGroupsNew;
  1953. pHeadMain = &pite->ListOfSameIfGroups;
  1954. //
  1955. // if main list is empty, then just move the new list to main list
  1956. // and I am done
  1957. //
  1958. if (IsListEmpty(pHeadMain)) {
  1959. // insert pHeadMain into new list
  1960. InsertHeadList(pHeadNew, pHeadMain);
  1961. // remove new list header
  1962. RemoveEntryList(pHeadNew);
  1963. InitializeListHead(pHeadNew);
  1964. return;
  1965. }
  1966. //
  1967. // insert the sentinel at the end of the main list
  1968. //
  1969. pgeSentinel.GroupLittleEndian = ~0;
  1970. giSentinel.pGroupTableEntry = &pgeSentinel;
  1971. InsertTailList(pHeadMain, &giSentinel.LinkBySameIfGroups);
  1972. pleMain = pHeadMain->Flink;
  1973. giMain = CONTAINING_RECORD(pleMain, GI_ENTRY, LinkBySameIfGroups);
  1974. // merge the lists by inserting the entries from new list into main list.
  1975. for (pleNew=pHeadNew->Flink; pleNew!=pHeadNew; ) {
  1976. giNew = CONTAINING_RECORD(pleNew, GI_ENTRY, LinkBySameIfGroups);
  1977. pleNew=pleNew->Flink;
  1978. while (giNew->pGroupTableEntry->GroupLittleEndian >
  1979. giMain->pGroupTableEntry->GroupLittleEndian)
  1980. {
  1981. pleMain = pleMain->Flink;
  1982. giMain = CONTAINING_RECORD(pleMain, GI_ENTRY, LinkBySameIfGroups);
  1983. }
  1984. InsertTailList(pleMain, &giNew->LinkBySameIfGroups);
  1985. }
  1986. //
  1987. // reinitialize the New list
  1988. //
  1989. pite->NumGIEntriesInNewList = 0;
  1990. InitializeListHead(&pite->ListOfSameIfGroupsNew);
  1991. // remove the sentinel entry from the main list
  1992. RemoveEntryList(&giSentinel.LinkBySameIfGroups);
  1993. //DebugPrintIfGroups(pite, 0); //deldel
  1994. Trace0(LEAVE1, "Leaving _MergeIfGroupsLists");
  1995. return;
  1996. } //end _MergeIfGroupsLists
  1997. //------------------------------------------------------------------------------
  1998. // _MergeProxyLists
  1999. //
  2000. // Merges the new GI list with the main GI list.
  2001. // Locks: Assumes the IF-GI list to be locked.
  2002. //------------------------------------------------------------------------------
  2003. VOID
  2004. MergeProxyLists(
  2005. PIF_TABLE_ENTRY pite
  2006. )
  2007. {
  2008. // sentinel is set at the end of the Main list so that all entries is inserted
  2009. // before it. its group value is set to all 1's.
  2010. PROXY_GROUP_ENTRY ProxySentinel, *pProxyNew, *pProxyMain;
  2011. PLIST_ENTRY pHeadNew, pHeadMain, pleMain, pleNew;
  2012. Trace1(ENTER1, "Entering MergeProxyLists(): IfIndex:%0x", pite->IfIndex);
  2013. pHeadNew = &pite->ListOfSameIfGroupsNew;
  2014. pHeadMain = &pite->ListOfSameIfGroups;
  2015. //
  2016. // if main list is empty, then just move the new list to main list
  2017. // and I am done
  2018. //
  2019. if (IsListEmpty(pHeadMain)) {
  2020. CONCATENATE_LISTS(pite->ListOfSameIfGroups, pite->ListOfSameIfGroupsNew);
  2021. pite->NumGIEntriesInNewList = 0;
  2022. return;
  2023. }
  2024. //
  2025. // insert the sentinel at the end of the main list
  2026. //
  2027. ProxySentinel.GroupLittleEndian = ~0;
  2028. InsertTailList(pHeadMain, &ProxySentinel.LinkBySameIfGroups);
  2029. pleMain = pHeadMain->Flink;
  2030. pProxyMain = CONTAINING_RECORD(pleMain, PROXY_GROUP_ENTRY,
  2031. LinkBySameIfGroups);
  2032. // merge the lists by inserting the entries from new list into main list.
  2033. for (pleNew=pHeadNew->Flink; pleNew!=pHeadNew; ) {
  2034. pProxyNew = CONTAINING_RECORD(pleNew, PROXY_GROUP_ENTRY,
  2035. LinkBySameIfGroups);
  2036. pleNew=pleNew->Flink;
  2037. while (pProxyNew->GroupLittleEndian > pProxyMain->GroupLittleEndian)
  2038. {
  2039. pleMain = pleMain->Flink;
  2040. pProxyMain = CONTAINING_RECORD(pleMain, PROXY_GROUP_ENTRY,
  2041. LinkBySameIfGroups);
  2042. }
  2043. InsertTailList(pleMain, &pProxyNew->LinkBySameIfGroups);
  2044. }
  2045. //
  2046. // reinitialize the New list
  2047. //
  2048. pite->NumGIEntriesInNewList = 0;
  2049. InitializeListHead(&pite->ListOfSameIfGroupsNew);
  2050. // remove the sentinel entry from the main list
  2051. RemoveEntryList(&ProxySentinel.LinkBySameIfGroups);
  2052. Trace0(LEAVE1, "Leaving _MergeProxyLists");
  2053. return;
  2054. } //end _MergeProxyLists
  2055. //------------------------------------------------------------------------------
  2056. // _MergeGroupLists
  2057. //
  2058. // Merges the new group list with the main group list.
  2059. //
  2060. // Locks: Assumes the group list to be locked.
  2061. // Called by: MibGetInternalGroupIfsInfo() or InsertInGroupsList()
  2062. //------------------------------------------------------------------------------
  2063. VOID
  2064. MergeGroupLists(
  2065. )
  2066. {
  2067. // sentinel is set at the end of the Main list so that all entries is inserted
  2068. // before it. its group value is set to all 1's.
  2069. GROUP_TABLE_ENTRY pgeSentinel;
  2070. PGROUP_TABLE_ENTRY pgeNew, pgeMain;
  2071. PLIST_ENTRY pHeadNew, pHeadMain, pleMain, pleNew;
  2072. Trace0(ENTER1, "Entering _MergeGroupLists()");
  2073. #if DBG
  2074. DebugPrintGroupsList(1);
  2075. #endif
  2076. pHeadNew = &g_pGroupTable->ListByGroupNew;
  2077. pHeadMain = &g_pGroupTable->ListByGroup.Link;
  2078. //
  2079. // if main list is empty, then just move the new list to main list
  2080. // and I am done
  2081. //
  2082. if (IsListEmpty(pHeadMain)) {
  2083. // insert pHeadMain into new list
  2084. InsertHeadList(pHeadNew, pHeadMain);
  2085. // remove new list header
  2086. RemoveEntryList(pHeadNew);
  2087. InitializeListHead(pHeadNew);
  2088. return;
  2089. }
  2090. //
  2091. // insert the sentinel at the end of the main list
  2092. //
  2093. pgeSentinel.GroupLittleEndian = ~0;
  2094. InsertTailList(pHeadMain, &pgeSentinel.LinkByGroup);
  2095. pleMain = pHeadMain->Flink;
  2096. pgeMain = CONTAINING_RECORD(pleMain, GROUP_TABLE_ENTRY, LinkByGroup);
  2097. // merge the lists by inserting the entries from new list into main list.
  2098. for (pleNew=pHeadNew->Flink; pleNew!=pHeadNew; ) {
  2099. pgeNew = CONTAINING_RECORD(pleNew, GROUP_TABLE_ENTRY, LinkByGroup);
  2100. pleNew=pleNew->Flink;
  2101. while (pgeNew->GroupLittleEndian > pgeMain->GroupLittleEndian) {
  2102. pleMain = pleMain->Flink;
  2103. pgeMain = CONTAINING_RECORD(pleMain, GROUP_TABLE_ENTRY,
  2104. LinkByGroup);
  2105. }
  2106. InsertTailList(pleMain, &pgeNew->LinkByGroup);
  2107. }
  2108. //
  2109. // reinitialize the New list
  2110. //
  2111. g_pGroupTable->NumGroupsInNewList = 0;
  2112. InitializeListHead(&g_pGroupTable->ListByGroupNew);
  2113. // remove the sentinel entry from the main list
  2114. RemoveEntryList(&pgeSentinel.LinkByGroup);
  2115. return;
  2116. } //end _MergeGroupLists