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.

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