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.

1610 lines
42 KiB

  1. //=============================================================================
  2. // Copyright (c) 1997 Microsoft Corporation
  3. // Module Name: Api.c
  4. // Abstract:
  5. // This module implements some of the Igmp APIs
  6. // RegisterProtocol, StartProtocol, StopProtocol,
  7. // GetGlobalInfo, SetGlobalInfo, and GetEventMessage
  8. //
  9. // Author: K.S.Lokesh (lokeshs@) 11-1-97
  10. //=============================================================================
  11. #include "pchigmp.h"
  12. #pragma hdrstop
  13. //------------------------------------------------------------------------------
  14. // Global variables (see global.h for description)
  15. //------------------------------------------------------------------------------
  16. DWORD g_Initialized;
  17. // interface table, group table, global config, global stats
  18. PIGMP_IF_TABLE g_pIfTable;
  19. PGROUP_TABLE g_pGroupTable;
  20. GLOBAL_CONFIG g_Config;
  21. IGMP_GLOBAL_STATS g_Info;
  22. // socket wait-event bindings
  23. LIST_ENTRY g_ListOfSocketEvents;
  24. READ_WRITE_LOCK g_SocketsRWLock;
  25. // igmp global timer struct
  26. IGMP_TIMER_GLOBAL g_TimerStruct;
  27. // protocol handles returned by mgm
  28. HANDLE g_MgmIgmprtrHandle;
  29. HANDLE g_MgmProxyHandle;
  30. // proxy table
  31. DWORD g_ProxyIfIndex;
  32. PIF_TABLE_ENTRY g_pProxyIfEntry;
  33. CRITICAL_SECTION g_ProxyAlertCS;
  34. LIST_ENTRY g_ProxyAlertsList;
  35. // ras table
  36. DWORD g_RasIfIndex;
  37. PIF_TABLE_ENTRY g_pRasIfEntry;
  38. // global lock, and dynamic locks
  39. CRITICAL_SECTION g_CS;
  40. DYNAMIC_LOCKS_STORE g_DynamicCSStore;
  41. DYNAMIC_LOCKS_STORE g_DynamicRWLStore;
  42. // enum lock
  43. READ_WRITE_LOCK g_EnumRWLock;
  44. // others
  45. HANDLE g_ActivitySemaphore;
  46. LONG g_ActivityCount;
  47. DWORD g_RunningStatus;
  48. HINSTANCE g_DllHandle;
  49. HANDLE g_RtmNotifyEvent;
  50. LOCKED_LIST g_RtmQueue;
  51. HANDLE g_Heap;
  52. DWORD g_TraceId=INVALID_TRACEID;
  53. HANDLE g_LogHandle;
  54. // signature for each enumeration
  55. USHORT g_GlobalIfGroupEnumSignature;
  56. #ifdef MIB_DEBUG
  57. DWORD g_MibTraceId;
  58. IGMP_TIMER_ENTRY g_MibTimer;
  59. #endif
  60. #if DEBUG_FLAGS_MEM_ALLOC
  61. extern CRITICAL_SECTION g_MemCS;
  62. #endif
  63. //------------------------------------------------------------------------------
  64. // #defines for g_Initialized
  65. //------------------------------------------------------------------------------
  66. //
  67. // the below flags are used to mark if the data has been initialized.
  68. // If a flag is not set, the corresponding structure wont be deinitialized
  69. //
  70. #define TIMER_GLOBAL_INIT 0x00000002
  71. #define WINSOCK_INIT 0x00000010
  72. #define DYNAMIC_CS_LOCKS_INIT 0x00000020
  73. #define DYNAMIC_RW_LOCKS_INIT 0x00000040
  74. #define GROUP_TABLE_INIT 0x00000080
  75. #define IF_TABLE_INIT 0x00000100
  76. //
  77. // flags associated with dll and calls made before start protocol.
  78. // these flags should not be reset by start protocol
  79. //
  80. #define DLL_STARTUP_FLAGS 0xFF000000
  81. //
  82. // Is StartProtocol being called immediately after DLL startup.
  83. // Used to see if heap has to be destroyed and recreated.
  84. // Set in DllStartup() and cleared in ProcolCleanup() as part of StopProtocol()
  85. //
  86. #define CLEAN_DLL_STARTUP 0x01000000
  87. // flag set to prevent register_protocol from being called multiple times.
  88. #define REGISTER_PROTOCOL 0x02000000
  89. //------------------------------------------------------------------------------
  90. // _DLLMAIN
  91. //
  92. // Called immediately after igmpv2.dll is loaded for the first time by the
  93. // process, and when the igmpv2.dll is unloaded by the process.
  94. // It does some initialization/final cleanup.
  95. //
  96. // Calls: _DllStartup() or _DllCleanup()
  97. //------------------------------------------------------------------------------
  98. BOOL
  99. WINAPI
  100. DLLMAIN (
  101. HINSTANCE hModule,
  102. DWORD dwReason,
  103. LPVOID lpvReserved
  104. )
  105. {
  106. BOOL bNoErr;
  107. DWORD Error=NO_ERROR;
  108. switch (dwReason) {
  109. //
  110. // Startup Initialization of Dll
  111. //
  112. case DLL_PROCESS_ATTACH:
  113. {
  114. // disable per-thread initialization
  115. DisableThreadLibraryCalls(hModule);
  116. // create and initialize global data
  117. bNoErr = DllStartup();
  118. break;
  119. }
  120. //
  121. // Cleanup of Dll
  122. //
  123. case DLL_PROCESS_DETACH:
  124. {
  125. // free global data
  126. bNoErr = DllCleanup();
  127. break;
  128. }
  129. default:
  130. bNoErr = TRUE;
  131. break;
  132. }
  133. return bNoErr;
  134. } //end _DLLMAIN
  135. //------------------------------------------------------------------------------
  136. // _DllStartup
  137. //
  138. // Sets the initial igmp status to IGMP_STATUS_STOPPED, creates a private heap,
  139. // Does the initialization of the rtm queue and tracing/logging,
  140. // and creates the global critical section.
  141. //
  142. // Note: no structures must be allocated from heap here, as StartProtocol()
  143. // if called after StopProtocol() destroys the heap.
  144. // Return Values: TRUE (if no error), else FALSE.
  145. //------------------------------------------------------------------------------
  146. BOOL
  147. DllStartup(
  148. )
  149. {
  150. BOOL bNoErr;
  151. DWORD Error=NO_ERROR;
  152. //not required to ZeroMemory igmp global struct as it is a global variable
  153. //
  154. // set the initial igmp status to stopped.
  155. // The status is set to running, after the protocol specific initialization
  156. // is completed as part of Start Protocol
  157. //
  158. g_RunningStatus = IGMP_STATUS_STOPPED;
  159. bNoErr = FALSE;
  160. BEGIN_BREAKOUT_BLOCK1 {
  161. // set the default logging level. It will be reset during
  162. // StartProtocol(), when logging level is set as part of global config
  163. g_Config.LoggingLevel = IGMP_LOGGING_WARN;
  164. //
  165. // create a private heap for Igmp
  166. //
  167. g_Heap = HeapCreate(0, 0, 0);
  168. if (g_Heap == NULL) {
  169. Error = GetLastError();
  170. GOTO_END_BLOCK1;
  171. }
  172. try {
  173. // initialize the Router Manager event queue
  174. CREATE_LOCKED_LIST(&g_RtmQueue);
  175. // create global critical section
  176. InitializeCriticalSection(&g_CS);
  177. }
  178. except (EXCEPTION_EXECUTE_HANDLER) {
  179. Error = GetExceptionCode();
  180. GOTO_END_BLOCK1;
  181. }
  182. // igmp has a clean initialization from DLL startup. If StartProtocol
  183. // is now called, it does not have to cleanup the heap.
  184. g_Initialized |= CLEAN_DLL_STARTUP;
  185. bNoErr = TRUE;
  186. } END_BREAKOUT_BLOCK1;
  187. return bNoErr;
  188. } //end _DllStartup
  189. //------------------------------------------------------------------------------
  190. // _DllCleanup
  191. //
  192. // Called when the igmpv2 dll is being unloaded. StopProtocol() would have
  193. // been called before, and that would have cleaned all the igmpv2 structures.
  194. // This call frees the rtm queue, the global CS, destroys the local heap,
  195. // and deregisters tracing/logging.
  196. //
  197. // Return Value: TRUE
  198. //------------------------------------------------------------------------------
  199. BOOL
  200. DllCleanup(
  201. )
  202. {
  203. // destroy the router manager event queue
  204. if (LOCKED_LIST_CREATED(&g_RtmQueue)) {
  205. DELETE_LOCKED_LIST(&g_RtmQueue, EVENT_QUEUE_ENTRY, Link);
  206. }
  207. //DebugCheck
  208. //DebugScanMemory();
  209. // delete global critical section
  210. DeleteCriticalSection(&g_CS);
  211. #if DEBUG_FLAGS_MEM_ALLOC
  212. DeleteCriticalSection(&g_MemCS);
  213. #endif
  214. // destroy private heap
  215. if (g_Heap != NULL) {
  216. HeapDestroy(g_Heap);
  217. }
  218. // deregister tracing/error logging
  219. if (g_LogHandle)
  220. RouterLogDeregister(g_LogHandle);
  221. if (g_TraceId!=INVALID_TRACEID)
  222. TraceDeregister(g_TraceId);
  223. return TRUE;
  224. }
  225. VOID
  226. InitTracingAndLogging(
  227. )
  228. {
  229. BEGIN_BREAKOUT_BLOCK1 {
  230. #define REGKEY_TRACING TEXT("Software\\Microsoft\\Tracing\\IGMPv2")
  231. #define REGVAL_CONSOLETRACINGMASK TEXT("ConsoleTracingMask")
  232. TCHAR szTracing[MAX_PATH];
  233. HKEY pTracingKey;
  234. DWORD Value, Error;
  235. lstrcpy(szTracing, REGKEY_TRACING);
  236. Error = RegOpenKeyEx(
  237. HKEY_LOCAL_MACHINE, szTracing, 0, KEY_SET_VALUE, &pTracingKey
  238. );
  239. if (Error != ERROR_SUCCESS)
  240. GOTO_END_BLOCK1;
  241. Value = 0x00ff0000;
  242. RegSetValueEx(
  243. pTracingKey, REGVAL_CONSOLETRACINGMASK, 0,
  244. REG_DWORD, (LPBYTE)&Value, sizeof(DWORD)
  245. );
  246. RegCloseKey(pTracingKey);
  247. } END_BREAKOUT_BLOCK1;
  248. // initialize tracing and error logging
  249. if (g_TraceId==INVALID_TRACEID) {
  250. g_TraceId = TraceRegister("IGMPv2");
  251. }
  252. if (!g_LogHandle) {
  253. g_LogHandle = RouterLogRegister("IGMPv2");
  254. }
  255. }
  256. //------------------------------------------------------------------------------
  257. // _RegisterProtocol
  258. //
  259. // This is the first function called by the IP Router Manager.
  260. // The Router Manager tells the routing protocol its version and capabilities
  261. // It also tells the DLL, the ID of the protocol it expects us to
  262. // register. This allows one DLL to support multiple routing protocols.
  263. // We return the functionality we support and a pointer to our functions.
  264. // Return Value:
  265. // Error: The error code returned by MGM if registering with it failed
  266. // else NO_ERROR
  267. //------------------------------------------------------------------------------
  268. DWORD
  269. WINAPI
  270. RegisterProtocol(
  271. IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
  272. IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
  273. )
  274. {
  275. DWORD Error = NO_ERROR;
  276. // Note: There should not be any trace/logs before here
  277. InitTracingAndLogging() ;
  278. Trace0(ENTER, "RegisterProtocol()");
  279. // cannot call RegisterProtocol multiple times
  280. if (g_Initialized&REGISTER_PROTOCOL) {
  281. Trace0(ERR, "Error: _RegisterProtocol() called multiple times for igmp");
  282. IgmpAssertOnError(FALSE);
  283. return ERROR_CAN_NOT_COMPLETE;
  284. }
  285. else {
  286. g_Initialized |= REGISTER_PROTOCOL;
  287. }
  288. //
  289. // The Router Manager should be calling us to register our protocol.
  290. // The Router Manager must be atleast the version we are compiled with
  291. // The Router Manager must support routing and multicast.
  292. //
  293. if(pRoutingChar->dwProtocolId != MS_IP_IGMP)
  294. return ERROR_NOT_SUPPORTED;
  295. if(pRoutingChar->dwVersion < MS_ROUTER_VERSION)
  296. return ERROR_NOT_SUPPORTED;
  297. if(!(pRoutingChar->fSupportedFunctionality & RF_ROUTING)
  298. || !(pRoutingChar->fSupportedFunctionality & RF_MULTICAST) )
  299. return ERROR_NOT_SUPPORTED;
  300. //
  301. // We setup our characteristics and function pointers
  302. // All pointers should be set to NULL by the caller.
  303. //
  304. pServiceChar->fSupportedFunctionality = 0;
  305. pRoutingChar->fSupportedFunctionality = RF_MULTICAST | RF_ROUTING;
  306. pRoutingChar->pfnStartProtocol = StartProtocol;
  307. pRoutingChar->pfnStartComplete = StartComplete;
  308. pRoutingChar->pfnStopProtocol = StopProtocol;
  309. pRoutingChar->pfnAddInterface = AddInterface;
  310. pRoutingChar->pfnDeleteInterface = DeleteInterface;
  311. pRoutingChar->pfnInterfaceStatus = InterfaceStatus;
  312. pRoutingChar->pfnGetEventMessage = GetEventMessage;
  313. pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
  314. pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
  315. pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo;
  316. pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo;
  317. pRoutingChar->pfnMibCreateEntry = MibCreate;
  318. pRoutingChar->pfnMibDeleteEntry = MibDelete;
  319. pRoutingChar->pfnMibGetEntry = MibGet;
  320. pRoutingChar->pfnMibSetEntry = MibSet;
  321. pRoutingChar->pfnMibGetFirstEntry = MibGetFirst;
  322. pRoutingChar->pfnMibGetNextEntry = MibGetNext;
  323. pRoutingChar->pfnUpdateRoutes = NULL;
  324. pRoutingChar->pfnConnectClient = ConnectRasClient;
  325. pRoutingChar->pfnDisconnectClient = DisconnectRasClient;
  326. pRoutingChar->pfnGetNeighbors = GetNeighbors;
  327. pRoutingChar->pfnGetMfeStatus = GetMfeStatus;
  328. pRoutingChar->pfnQueryPower = NULL;
  329. pRoutingChar->pfnSetPower = NULL;
  330. Trace0(LEAVE, "Leaving RegisterProtocol():\n");
  331. return NO_ERROR;
  332. } //end _RegisterProtocol
  333. //------------------------------------------------------------------------------
  334. // _StartProtocol
  335. //
  336. // Called after the _RegisterProtocol() API.
  337. // Initializes the data structures used by the protocol. However, the
  338. // protocol actually starts to run when it gets interface ownerships.
  339. // Locks:
  340. // runs completely in g_CS.
  341. // Return Value:
  342. // Error: if there is an error else NO_ERROR
  343. //------------------------------------------------------------------------------
  344. DWORD
  345. WINAPI
  346. StartProtocol(
  347. IN HANDLE hRtmNotifyEvent, //notify Rtm when protocol stopped
  348. IN PSUPPORT_FUNCTIONS pSupportFunctions, //NULL
  349. IN PVOID pGlobalConfig,
  350. IN ULONG ulStructureVersion,
  351. IN ULONG ulStructureSize,
  352. IN ULONG ulStructureCount
  353. )
  354. {
  355. WSADATA WsaData;
  356. DWORD Error = NO_ERROR;
  357. BOOL bErr;
  358. Trace0(ENTER, "Entering StartProtocol()");
  359. // make sure it is not an unsupported igmp version structure
  360. if (ulStructureVersion>=IGMP_CONFIG_VERSION_600) {
  361. Trace1(ERR, "Unsupported IGMP version structure: %0x",
  362. ulStructureVersion);
  363. IgmpAssertOnError(FALSE);
  364. return ERROR_CAN_NOT_COMPLETE;
  365. }
  366. // lock retained for entire initialization. so api_entry not required
  367. ACQUIRE_GLOBAL_LOCK("_StartProtocol");
  368. //
  369. // make certain igmp is not already running
  370. //
  371. if (g_RunningStatus != IGMP_STATUS_STOPPED) {
  372. Trace0(START,
  373. "Error: _StartProtocol called when Igmp is already running");
  374. Logwarn0(IGMP_ALREADY_STARTED, NO_ERROR);
  375. RELEASE_GLOBAL_LOCK("_StartProtocol");
  376. return ERROR_CAN_NOT_COMPLETE;
  377. }
  378. bErr = TRUE;
  379. BEGIN_BREAKOUT_BLOCK1 {
  380. // clear initialization flags set during and after _startProtocol
  381. g_Initialized &= DLL_STARTUP_FLAGS;
  382. // g_RunningStatus, g_CS, g_TraceId, g_LogHandle, g_RtmQueue,
  383. // g_Initialized & 0xFF000000 initialized in DllStartup/RegisterProtocol
  384. //
  385. // If start protocol has been called after a stop protocol.
  386. //
  387. if (!(g_Initialized & CLEAN_DLL_STARTUP)) {
  388. // destroy private heap, so that there is no memory leak.
  389. if (g_Heap != NULL) {
  390. HeapDestroy(g_Heap);
  391. }
  392. //
  393. // Reset the igmp global structure.
  394. // bugchk:make sure that all appropriate fields are being reset.
  395. //
  396. g_pIfTable = NULL;
  397. g_pGroupTable = NULL;
  398. ZeroMemory(&g_Config, sizeof(GLOBAL_CONFIG));
  399. g_Config.LoggingLevel = IGMP_LOGGING_WARN;
  400. ZeroMemory(&g_Info, sizeof(IGMP_GLOBAL_STATS));
  401. InitializeListHead(&g_ListOfSocketEvents);
  402. ZeroMemory(&g_SocketsRWLock, sizeof(READ_WRITE_LOCK));
  403. ZeroMemory(&g_EnumRWLock, sizeof(READ_WRITE_LOCK));
  404. ZeroMemory(&g_TimerStruct, sizeof(IGMP_TIMER_GLOBAL));
  405. g_MgmIgmprtrHandle = g_MgmProxyHandle = NULL;
  406. g_ProxyIfIndex = 0;
  407. g_pProxyIfEntry = NULL;
  408. ZeroMemory(&g_ProxyAlertCS, sizeof(CRITICAL_SECTION));
  409. InitializeListHead(&g_ProxyAlertsList);
  410. g_RasIfIndex = 0;
  411. g_pRasIfEntry = NULL;
  412. ZeroMemory(&g_DynamicCSStore, sizeof(DYNAMIC_LOCKS_STORE));
  413. ZeroMemory(&g_DynamicRWLStore, sizeof(DYNAMIC_LOCKS_STORE));
  414. g_ActivitySemaphore = NULL;
  415. g_ActivityCount = 0;
  416. g_RtmNotifyEvent = NULL;
  417. g_Heap = NULL;
  418. #ifdef MIB_DEBUG
  419. g_MibTraceId = 0;
  420. ZeroMemory(&g_MibTimer, sizeof(IGMP_TIMER_ENTRY));
  421. #endif
  422. // create private heap again.
  423. g_Heap = HeapCreate(0, 0, 0);
  424. if (g_Heap == NULL) {
  425. Error = GetLastError();
  426. Trace1(ANY, "error %d creating Igmp private heap", Error);
  427. GOTO_END_BLOCK1;
  428. }
  429. }
  430. // save the Router Manager notification event
  431. g_RtmNotifyEvent = hRtmNotifyEvent;
  432. //
  433. // set the Global Config (after making validation changes)
  434. //
  435. if(pGlobalConfig == NULL) {
  436. Trace0(ERR, "_StartProtocol: Called with NULL global config");
  437. IgmpAssertOnError(FALSE);
  438. Error = ERROR_INVALID_PARAMETER;
  439. GOTO_END_BLOCK1;
  440. }
  441. {
  442. PIGMP_MIB_GLOBAL_CONFIG pGlobalConfigTmp;
  443. pGlobalConfigTmp = (PIGMP_MIB_GLOBAL_CONFIG) pGlobalConfig;
  444. // Check the global config, and correct if values are not correct.
  445. // Not a fatal error.
  446. if (! ValidateGlobalConfig(pGlobalConfigTmp)) {
  447. Error = ERROR_INVALID_PARAMETER;
  448. GOTO_END_BLOCK1;
  449. }
  450. g_Config.Version = pGlobalConfigTmp->Version;
  451. g_Config.LoggingLevel = pGlobalConfigTmp->LoggingLevel;
  452. g_Config.RasClientStats = 1;
  453. }
  454. //
  455. // The Global Stats are set to all 0 as it is a global variable.
  456. //
  457. //
  458. // Initialize Winsock version 2.0
  459. //
  460. Error = (DWORD)WSAStartup(MAKEWORD(2,0), &WsaData);
  461. if ( (Error!=0) || (LOBYTE(WsaData.wVersion)<2) ) {
  462. Trace1(ERR,
  463. "StartProtocol: Error %d :could not initialize winsock v-2.0",
  464. Error);
  465. IgmpAssertOnError(FALSE);
  466. Logerr0(WSASTARTUP_FAILED, Error);
  467. if (LOBYTE(WsaData.wVersion)<2)
  468. WSACleanup();
  469. GOTO_END_BLOCK1;
  470. }
  471. g_Initialized |= WINSOCK_INIT;
  472. //
  473. // initialize list of SocketEvents
  474. //
  475. InitializeListHead(&g_ListOfSocketEvents);
  476. Error = CreateReadWriteLock(&g_SocketsRWLock);
  477. if (Error!=NO_ERROR)
  478. GOTO_END_BLOCK1;
  479. Error = CreateReadWriteLock(&g_EnumRWLock);
  480. if (Error!=NO_ERROR)
  481. GOTO_END_BLOCK1;
  482. //
  483. // initialize the timer queues and other timer structures
  484. //
  485. Error = InitializeTimerGlobal();
  486. if (Error!=NO_ERROR)
  487. GOTO_END_BLOCK1;
  488. g_Initialized |= TIMER_GLOBAL_INIT;
  489. // Create Interface Table
  490. InitializeIfTable();
  491. g_Initialized |= IF_TABLE_INIT;
  492. // Create Group Table
  493. InitializeGroupTable();
  494. g_Initialized |= GROUP_TABLE_INIT;
  495. // proxy, ras interface already set to 0/NULL in global structure.
  496. InitializeListHead(&g_ProxyAlertsList);
  497. //
  498. // Initialise the Dynamic CS and ReadWrite locks main struct
  499. //
  500. Error = InitializeDynamicLocksStore(&g_DynamicCSStore);
  501. if (Error!=NO_ERROR)
  502. GOTO_END_BLOCK1;
  503. g_Initialized |= DYNAMIC_CS_LOCKS_INIT;
  504. Error = InitializeDynamicLocksStore(&g_DynamicRWLStore);
  505. if (Error!=NO_ERROR)
  506. GOTO_END_BLOCK1;
  507. g_Initialized |= DYNAMIC_RW_LOCKS_INIT;
  508. //
  509. // create the semaphore released by each thread when it is done
  510. // g_ActivityCount already set to 0.
  511. //
  512. g_ActivityCount = 0;
  513. g_ActivitySemaphore = CreateSemaphore(NULL, 0, 0xfffffff, NULL);
  514. if (g_ActivitySemaphore == NULL) {
  515. Error = GetLastError();
  516. Trace1(ERR, "error %d creating semaphore for Igmp threads", Error);
  517. IgmpAssertOnError(FALSE);
  518. Logerr0(CREATE_SEMAPHORE_FAILED, Error);
  519. GOTO_END_BLOCK1;
  520. }
  521. //
  522. // set the starting time for igmp. Should be done after global
  523. // timer and global Info struct are initialized
  524. //
  525. g_Info.TimeWhenRtrStarted.QuadPart = GetCurrentIgmpTime();
  526. // set igmp status to running
  527. g_RunningStatus = IGMP_STATUS_RUNNING;
  528. #ifdef MIB_DEBUG
  529. //
  530. // set delayed timer to display igmp's MIB tables periodically
  531. //
  532. g_MibTraceId = TraceRegisterEx("IGMPMIB", TRACE_USE_CONSOLE);
  533. if (g_MibTraceId != INVALID_TRACEID) {
  534. g_MibTimer.Context = NULL;
  535. g_MibTimer.Status = TIMER_STATUS_CREATED;
  536. g_MibTimer.Function = WT_MibDisplay;
  537. #if DEBUG_TIMER_TIMERID
  538. SET_TIMER_ID(&g_MibTimer, 910, 0, 0, 0);
  539. #endif
  540. ACQUIRE_TIMER_LOCK("_StartProtocol");
  541. InsertTimer(&g_MibTimer, 5000, TRUE, DBG_Y);
  542. RELEASE_TIMER_LOCK("_StartProtocol");
  543. }
  544. #endif //MIB_DEBUG
  545. //
  546. // register Igmp router with MGM. Proxy will be registered if there
  547. // is an active proxy interface.
  548. //
  549. Error = RegisterProtocolWithMgm(PROTO_IP_IGMP);
  550. // no error if I have reached here
  551. bErr = FALSE;
  552. } END_BREAKOUT_BLOCK1;
  553. if (bErr) {
  554. Trace1(START, "Igmp could not be started: %d", Error);
  555. ProtocolCleanup();
  556. }
  557. else {
  558. Trace0(START, "Igmp started successfully");
  559. Loginfo0(IGMP_STARTED, NO_ERROR);
  560. }
  561. g_DllHandle = LoadLibrary(TEXT("igmpv2.dll"));
  562. RELEASE_GLOBAL_LOCK("_StartProtocol()");
  563. Trace1(LEAVE, "Leaving StartProtocol():%d\n", Error);
  564. return (Error);
  565. } //end StartProtocol
  566. //------------------------------------------------------------------------------
  567. // _StartComplete
  568. //
  569. //------------------------------------------------------------------------------
  570. DWORD
  571. APIENTRY
  572. StartComplete(
  573. VOID
  574. )
  575. {
  576. return NO_ERROR;
  577. }
  578. //------------------------------------------------------------------------------
  579. // _StopProtocol
  580. //
  581. // sets the igmp status to stopping, marks the current number of active igmp
  582. // work items, and queues a worker that will wait till all those work items
  583. // have completed and then clean up igmp structures. This function returns
  584. // a pending status to the caller, while the queued work item will notify
  585. // the rtm after the cleanup has been done.
  586. // Locking:
  587. // Runs completely in g_CS.
  588. // Return Values:
  589. // ERROR_CAN_NOT_COMPLETE, PENDING.
  590. // Queues:
  591. // _WF_FinishStopProtocol()
  592. //------------------------------------------------------------------------------
  593. DWORD
  594. APIENTRY
  595. StopProtocol(
  596. VOID
  597. )
  598. {
  599. DWORD dwThreadCount, Error=NO_ERROR;
  600. Trace0(ENTER, "entering _StopProtocol()");
  601. //debugCheck
  602. #if DEBUG_FLAGS_MEM_ALLOC
  603. // make sure that no interface timers exist
  604. #ifdef MIB_DEBUG
  605. if (g_TimerStruct.NumTimers>1)
  606. #else
  607. if (g_TimerStruct.NumTimers>0)
  608. #endif
  609. {
  610. IgmpAssert(FALSE);
  611. DbgPrint("Cleanup: some igmp timers still exist\n");
  612. DebugPrintTimerQueue();
  613. }
  614. // make sure that no groups exist
  615. DebugForcePrintGroupsList(ENSURE_EMPTY);
  616. #endif
  617. ACQUIRE_GLOBAL_LOCK("_StopProtocol");
  618. //
  619. // cannot stop if already stopped
  620. //
  621. if (g_RunningStatus != IGMP_STATUS_RUNNING) {
  622. Trace0(ERR, "Trying to stop Igmp when it is already being stopped");
  623. IgmpAssertOnError(FALSE);
  624. Logerr0(PROTO_ALREADY_STOPPING, NO_ERROR);
  625. Trace0(LEAVE, "Leaving _StopProtocol()\n");
  626. RELEASE_GLOBAL_LOCK("_StopProtocol");
  627. return ERROR_CAN_NOT_COMPLETE;
  628. }
  629. //
  630. // set Igmp's status to STOPPING;
  631. // this prevents any more work-items from being queued,
  632. // and it prevents the one's already queued from executing
  633. //
  634. InterlockedExchange(&g_RunningStatus, IGMP_STATUS_STOPPING);
  635. //
  636. // find out how many threads are active in Igmp;
  637. // we will have to wait for this many threads to exit
  638. // before we clean up Igmp's resources
  639. //
  640. dwThreadCount = g_ActivityCount;
  641. RELEASE_GLOBAL_LOCK("_StopProtocol");
  642. Trace0(LEAVE, "leaving _StopProtocol");
  643. //
  644. // QueueUserWorkItem that waits for all active Igmp threads and then
  645. // releases resources taken by this DLL.
  646. // Note: I dont use QueueIgmpWorker as that would increment the
  647. // ActivityCount.
  648. //
  649. QueueUserWorkItem(WF_FinishStopProtocol, (PVOID)(DWORD_PTR)dwThreadCount, 0);
  650. // Note: to be safe, there should be no code after QueueUserWorkItem
  651. return ERROR_PROTOCOL_STOP_PENDING;
  652. } //end StopProtocol
  653. DWORD
  654. FreeLibraryThread(
  655. PVOID pvContext
  656. )
  657. {
  658. FreeLibraryAndExitThread(g_DllHandle, 0);
  659. return 0;
  660. }
  661. //------------------------------------------------------------------------------
  662. // WF_FinishStopProtocol
  663. //------------------------------------------------------------------------------
  664. DWORD
  665. WF_FinishStopProtocol(
  666. PVOID pContext //dwThreadCount
  667. )
  668. /*++
  669. Routing Description:
  670. Waits for all the current active igmp work items to complete. Follows that
  671. by a call to ProtocolCleanup() to deregister and cleanup all igmp structures.
  672. In the end, notifies RtrManager that the protocol has stopped.
  673. Queued by: _StopProtocol()
  674. Calls: _ProtocolCleanup()
  675. Locks: no locks required as all igmp threads have stopped.
  676. --*/
  677. {
  678. MESSAGE msg = {0, 0, 0};
  679. DWORD dwThreadCount;
  680. DWORD Error = NO_ERROR;
  681. Trace0(ENTER1, "entering _WF_FinishStopProtocol()");
  682. //
  683. // NOTE: since this is called while the router is stopping,
  684. // do not use EnterIgmpWorker()/LeaveIgmpWorker()
  685. //
  686. dwThreadCount = PtrToUlong(pContext);
  687. //
  688. // waits for API callers and worker functions to finish
  689. //
  690. while (dwThreadCount-- > 0) {
  691. Trace1(STOP, "%d threads active in Igmp", dwThreadCount+1);
  692. WaitForSingleObject(g_ActivitySemaphore, INFINITE);
  693. }
  694. // enter the critical section and leave, just to be sure that
  695. // all threads have quit their calls to LeaveIgmpWorker()
  696. ACQUIRE_GLOBAL_LOCK("_WF_FinishStopProtocol");
  697. RELEASE_GLOBAL_LOCK("_WF_FinishStopProtocol");
  698. Trace0(STOP, "all threads stopped. Cleaning up resources");
  699. //
  700. // This call deregisters with Wait-Server/MGM, and cleans up
  701. // all structures
  702. //
  703. ProtocolCleanup();
  704. Loginfo0(IGMP_STOPPED, NO_ERROR);
  705. //
  706. // notify Router Manager that protocol has been stopped
  707. //
  708. ACQUIRE_LIST_LOCK(&g_RtmQueue, "g_RtmQueue", "_WF_FinishStopProtocol");
  709. EnqueueEvent(&g_RtmQueue, ROUTER_STOPPED, msg);
  710. SetEvent(g_RtmNotifyEvent);
  711. RELEASE_LIST_LOCK(&g_RtmQueue, "g_RtmQueue", "_WF_FinishStopProtocol");
  712. Trace0(LEAVE1, "Leaving _WF_FinishStopProtocol()");
  713. if (g_DllHandle) {
  714. HANDLE h_Thread;
  715. h_Thread = CreateThread(0,0,FreeLibraryThread, NULL, 0, NULL);
  716. if (h_Thread != NULL)
  717. CloseHandle(h_Thread);
  718. }
  719. return 0;
  720. } //end _WF_FinishStopProtocol
  721. //------------------------------------------------------------------------------
  722. // _ProtocolCleanup
  723. //
  724. // All active igmp work items have completed before this procedure is called.
  725. // So it is safe to deregister with Wait-Server, and deregister all interfaces/
  726. // RAS clients and Igmp router/proxy protocol with MGM. Then, all the structures
  727. // are cleaned up.
  728. //
  729. // Called by:
  730. // _WF_FinishStopProtocol() and _StartProtocol()
  731. // Locks:
  732. // No locks required as no api can enter when g_RunningStatus set to stopping.
  733. //------------------------------------------------------------------------------
  734. VOID
  735. ProtocolCleanup(
  736. )
  737. {
  738. DWORD Error = NO_ERROR;
  739. Trace0(ENTER1, "entering _ProtocolCleanup()");
  740. //
  741. // Deregister Igmp Router from MGM. Proxy is deregistered if required in
  742. // _DeinitializeIfTable
  743. //
  744. if (g_MgmIgmprtrHandle!=NULL) {
  745. Error = MgmDeRegisterMProtocol(g_MgmIgmprtrHandle);
  746. Trace1(MGM, "_MgmDeRegisterMProtocol(Igmp): returned %d", Error);
  747. }
  748. // deregister Mib display
  749. #ifdef MIB_DEBUG
  750. if (g_MibTraceId != INVALID_TRACEID)
  751. TraceDeregister(g_MibTraceId);
  752. #endif
  753. // close activity semaphore
  754. if (g_ActivitySemaphore != NULL) {
  755. CloseHandle(g_ActivitySemaphore);
  756. g_ActivitySemaphore = NULL;
  757. }
  758. // DeInitialise the Dynamic CS and ReadWrite locks main struct
  759. if (g_Initialized&DYNAMIC_RW_LOCKS_INIT)
  760. DeInitializeDynamicLocksStore(&g_DynamicRWLStore, LOCK_TYPE_RW);
  761. if (g_Initialized&DYNAMIC_CS_LOCKS_INIT)
  762. DeInitializeDynamicLocksStore(&g_DynamicCSStore, LOCK_TYPE_CS);
  763. // DeInitialize the group table. Delete the group bucket locks.
  764. if (g_Initialized & GROUP_TABLE_INIT)
  765. DeInitializeGroupTable();
  766. // DeInitialize InterfaceTable. This call also deregister all interfaces &
  767. // ras clients from MGM
  768. if (g_Initialized & IF_TABLE_INIT)
  769. DeInitializeIfTable();
  770. // DeInitialize the global timer. Deletes the timer critical-section.
  771. if (g_Initialized&TIMER_GLOBAL_INIT)
  772. DeInitializeTimerGlobal();
  773. //
  774. // delete sockets events and deregister them from wait thread.
  775. // delete sockets read-write lock
  776. //
  777. {
  778. PLIST_ENTRY pHead, ple;
  779. PSOCKET_EVENT_ENTRY psee;
  780. HANDLE WaitHandle;
  781. pHead = &g_ListOfSocketEvents;
  782. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  783. psee = CONTAINING_RECORD(ple,SOCKET_EVENT_ENTRY,LinkBySocketEvents);
  784. if (psee->InputWaitEvent) {
  785. WaitHandle = InterlockedExchangePointer(&psee->InputWaitEvent, NULL);
  786. if (WaitHandle)
  787. UnregisterWaitEx( WaitHandle, NULL ) ;
  788. }
  789. CloseHandle(psee->InputEvent);
  790. }
  791. DeleteReadWriteLock(&g_SocketsRWLock);
  792. DeleteCriticalSection(&g_ProxyAlertCS);
  793. DeleteReadWriteLock(&g_EnumRWLock);
  794. }
  795. // deinitialize winsock
  796. if (g_Initialized & WINSOCK_INIT) {
  797. WSACleanup();
  798. }
  799. // Mark that _StopProtocol has been called once.
  800. // If _StartProtocol is called again, igmp will have to Destroy/Create
  801. // private heap and ZeroMemory parts of igmp global struct.
  802. g_Initialized &= ~CLEAN_DLL_STARTUP;
  803. Trace0(LEAVE1, "leaving _ProtocolCleanup()");
  804. return;
  805. } //end _ProtocolCleanup
  806. //------------------------------------------------------------------------------
  807. // DebugPrintGlobalConfig
  808. //------------------------------------------------------------------------------
  809. VOID
  810. DebugPrintGlobalConfig (
  811. PIGMP_MIB_GLOBAL_CONFIG pConfigExt
  812. )
  813. {
  814. Trace0(CONFIG, "Printing Global Config");
  815. Trace1(CONFIG, "Version: 0x%x", pConfigExt->Version);
  816. Trace1(CONFIG, "LoggingLevel: %x\n", pConfigExt->LoggingLevel);
  817. }
  818. //------------------------------------------------------------------------------
  819. // GetGlobalInfo
  820. //
  821. // Return Values: ERROR_CAN_NOT_COMPLETE, ERROR_INVALID_DATA, NO_ERROR
  822. //------------------------------------------------------------------------------
  823. DWORD
  824. WINAPI
  825. GetGlobalInfo(
  826. IN OUT PVOID pvConfig,
  827. IN OUT PDWORD pdwSize,
  828. IN OUT PULONG pulStructureVersion,
  829. IN OUT PULONG pulStructureSize,
  830. IN OUT PULONG pulStructureCount
  831. )
  832. {
  833. DWORD Error=NO_ERROR, dwSize;
  834. PIGMP_MIB_GLOBAL_CONFIG pGlobalConfig;
  835. Trace2(ENTER1, "entering GetGlobalInfo(): pvConfig(%08x) pdwSize(%08x)",
  836. pvConfig, pdwSize);
  837. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  838. BEGIN_BREAKOUT_BLOCK1 {
  839. //
  840. // check the buffer size and set to global config
  841. //
  842. if (pdwSize == NULL) {
  843. Error = ERROR_INVALID_PARAMETER;
  844. GOTO_END_BLOCK1;
  845. }
  846. if ( (*pdwSize < sizeof(IGMP_MIB_GLOBAL_CONFIG)) || (pvConfig==NULL) ) {
  847. Error = ERROR_INSUFFICIENT_BUFFER;
  848. }
  849. else {
  850. pGlobalConfig = (PIGMP_MIB_GLOBAL_CONFIG) pvConfig;
  851. pGlobalConfig->Version = g_Config.Version;
  852. pGlobalConfig->LoggingLevel = g_Config.LoggingLevel;
  853. pGlobalConfig->RasClientStats = g_Config.RasClientStats;
  854. }
  855. *pdwSize = sizeof(IGMP_MIB_GLOBAL_CONFIG);
  856. } END_BREAKOUT_BLOCK1;
  857. if (pulStructureCount)
  858. *pulStructureCount = 1;
  859. if (pulStructureSize && pdwSize)
  860. *pulStructureSize = *pdwSize;
  861. if (pulStructureVersion)
  862. *pulStructureVersion = IGMP_CONFIG_VERSION_500;
  863. Trace1(LEAVE1, "Leaving GetGlobalInfo(): %d\n", Error);
  864. LeaveIgmpApi();
  865. return Error;
  866. }
  867. //------------------------------------------------------------------------------
  868. // SetGlobalInfo
  869. // Return Values: ERROR_CAN_NOT_COMPLETE, ERROR_INVALID_PARAMETER,
  870. // ERROR_INVALID_DATA, NO_ERROR
  871. //------------------------------------------------------------------------------
  872. DWORD
  873. WINAPI
  874. SetGlobalInfo(
  875. IN PVOID pvConfig,
  876. IN ULONG ulStructureVersion,
  877. IN ULONG ulStructureSize,
  878. IN ULONG ulStructureCount
  879. )
  880. {
  881. DWORD Error=NO_ERROR, dwSize;
  882. PIGMP_MIB_GLOBAL_CONFIG pConfigSrc;
  883. BOOL bValid;
  884. if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
  885. // make sure it is not an unsupported igmp version structure
  886. if (ulStructureVersion>=IGMP_CONFIG_VERSION_600) {
  887. Trace1(ERR, "Unsupported IGMP version structure: %0x",
  888. ulStructureVersion);
  889. IgmpAssertOnError(FALSE);
  890. LeaveIgmpApi();
  891. return ERROR_CAN_NOT_COMPLETE;
  892. }
  893. Trace1(ENTER, "entering SetGlobalInfo: pvConfig(%08x)", pvConfig);
  894. ASSERT(ulStructureSize == sizeof(IGMP_MIB_GLOBAL_CONFIG));
  895. BEGIN_BREAKOUT_BLOCK1 {
  896. if (pvConfig == NULL) {
  897. Error = ERROR_INVALID_PARAMETER;
  898. GOTO_END_BLOCK1;
  899. }
  900. pConfigSrc = (PIGMP_MIB_GLOBAL_CONFIG) pvConfig;
  901. // validate global config.
  902. bValid = ValidateGlobalConfig(pConfigSrc);
  903. if (!bValid) {
  904. Error = ERROR_INVALID_DATA;
  905. GOTO_END_BLOCK1;
  906. }
  907. // copy from the buffer
  908. InterlockedExchange(&g_Config.RasClientStats,
  909. pConfigSrc->RasClientStats);
  910. InterlockedExchange(&g_Config.LoggingLevel,
  911. pConfigSrc->LoggingLevel);
  912. } END_BREAKOUT_BLOCK1;
  913. Trace1(LEAVE, "leaving SetGlobalInfo(): %d\n", Error);
  914. LeaveIgmpApi();
  915. return Error;
  916. }
  917. //------------------------------------------------------------------------------
  918. // ValidateGlobalConfig
  919. //
  920. // validates the global config info. If values are not valid, then sets them to
  921. // some default values.
  922. //
  923. // Return Values:
  924. // TRUE: if the global config values are valid.
  925. // FALSE: if the global config values are not valid. sets default values.
  926. //------------------------------------------------------------------------------
  927. BOOL
  928. ValidateGlobalConfig(
  929. PIGMP_MIB_GLOBAL_CONFIG pGlobalConfig
  930. )
  931. {
  932. DebugPrintGlobalConfig(pGlobalConfig);
  933. // check version
  934. if (pGlobalConfig->Version>=IGMP_VERSION_3_5) {
  935. Trace1(ERR, "Invalid version in global config.\n"
  936. "Create the Igmp configuration again", pGlobalConfig->Version);
  937. IgmpAssertOnError(FALSE);
  938. Logerr0(INVALID_VERSION, ERROR_INVALID_DATA);
  939. return FALSE;
  940. }
  941. // check loggingLevel
  942. switch (pGlobalConfig->LoggingLevel) {
  943. case IGMP_LOGGING_NONE :
  944. case IGMP_LOGGING_ERROR :
  945. case IGMP_LOGGING_WARN :
  946. case IGMP_LOGGING_INFO :
  947. break;
  948. default :
  949. pGlobalConfig->LoggingLevel = IGMP_LOGGING_WARN;
  950. return FALSE;
  951. }
  952. // check RasClientStats value
  953. if ((pGlobalConfig->RasClientStats!=0)&&(pGlobalConfig->RasClientStats!=1)){
  954. pGlobalConfig->RasClientStats = 0;
  955. return FALSE;
  956. }
  957. return TRUE;
  958. }
  959. //----------------------------------------------------------------------------
  960. // GetEventMessage
  961. //
  962. // This is called by the IP Router Manager if we indicate that we have
  963. // a message in our queue to be delivered to it (by setting the
  964. // g_RtmNotifyEvent)
  965. // Return Value
  966. // NO_ERROR
  967. //----------------------------------------------------------------------------
  968. DWORD
  969. APIENTRY
  970. GetEventMessage(
  971. OUT ROUTING_PROTOCOL_EVENTS *pEvent,
  972. OUT PMESSAGE pResult
  973. )
  974. {
  975. DWORD Error;
  976. //
  977. // Note: _GetEventMessage() does not use the
  978. // EnterIgmpApi()/LeaveIgmpApi() mechanism,
  979. // since it may be called after Igmp has stopped, when the
  980. // Router Manager is retrieving the ROUTER_STOPPED message
  981. //
  982. Trace2(ENTER, "entering _GetEventMessage: pEvent(%08x) pResult(%08x)",
  983. pEvent, pResult);
  984. ACQUIRE_LIST_LOCK(&g_RtmQueue, "RtmQueue", "_GetEventMessage");
  985. Error = DequeueEvent(&g_RtmQueue, pEvent, pResult);
  986. RELEASE_LIST_LOCK(&g_RtmQueue, "RtmQueue", "_GetEventMessage");
  987. Trace1(LEAVE, "leaving _GetEventMessage: %d\n", Error);
  988. return Error;
  989. }
  990. //----------------------------------------------------------------------------
  991. // Function: EnqueueEvent
  992. //
  993. // This function adds an entry to the end of the queue of
  994. // Router Manager events. It assumes the queue is locked.
  995. //----------------------------------------------------------------------------
  996. DWORD
  997. EnqueueEvent(
  998. PLOCKED_LIST pQueue,
  999. ROUTING_PROTOCOL_EVENTS EventType,
  1000. MESSAGE Msg
  1001. ) {
  1002. DWORD Error;
  1003. PLIST_ENTRY phead;
  1004. PEVENT_QUEUE_ENTRY peqe;
  1005. phead = &pQueue->Link;
  1006. peqe = IGMP_ALLOC(sizeof(EVENT_QUEUE_ENTRY), 0x1, 0);
  1007. PROCESS_ALLOC_FAILURE2(peqe,
  1008. "error %d allocating %d bytes for event queue entry",
  1009. Error, sizeof(EVENT_QUEUE_ENTRY),
  1010. return Error);
  1011. peqe->EventType = EventType;
  1012. peqe->Msg = Msg;
  1013. InsertTailList(phead, &peqe->Link);
  1014. return NO_ERROR;
  1015. }
  1016. //------------------------------------------------------------------------------
  1017. // Function: DequeueEvent
  1018. //
  1019. // This function removes an entry from the head of the queue
  1020. // of Router Manager events. It assumes the queue is locked
  1021. //------------------------------------------------------------------------------
  1022. DWORD
  1023. DequeueEvent(
  1024. PLOCKED_LIST pQueue,
  1025. ROUTING_PROTOCOL_EVENTS *pEventType,
  1026. PMESSAGE pMsg
  1027. ) {
  1028. PLIST_ENTRY phead, ple;
  1029. PEVENT_QUEUE_ENTRY peqe;
  1030. phead = &pQueue->Link;
  1031. if (IsListEmpty(phead)) {
  1032. return ERROR_NO_MORE_ITEMS;
  1033. }
  1034. ple = RemoveHeadList(phead);
  1035. peqe = CONTAINING_RECORD(ple, EVENT_QUEUE_ENTRY, Link);
  1036. *pEventType = peqe->EventType;
  1037. *pMsg = peqe->Msg;
  1038. IGMP_FREE(peqe);
  1039. return NO_ERROR;
  1040. }
  1041. //------------------------------------------------------------------------------
  1042. // GetNeighbors
  1043. // Return Values: ERROR_INSUFFICIENT_BUFFER, NO_ERROR
  1044. //------------------------------------------------------------------------------
  1045. DWORD
  1046. APIENTRY
  1047. GetNeighbors(
  1048. IN DWORD dwInterfaceIndex,
  1049. IN PDWORD pdwNeighborList,
  1050. IN OUT PDWORD pdwNeighborListSize,
  1051. OUT PBYTE pbInterfaceFlags
  1052. )
  1053. {
  1054. PIF_TABLE_ENTRY pite = GetIfByIndex(dwInterfaceIndex);
  1055. if (IS_QUERIER(pite)) {
  1056. *pbInterfaceFlags |= MRINFO_QUERIER_FLAG;
  1057. *pdwNeighborListSize = 0;
  1058. }
  1059. else {
  1060. if (*pdwNeighborListSize < 4)
  1061. return ERROR_INSUFFICIENT_BUFFER;
  1062. *pdwNeighborListSize = 4;
  1063. *pdwNeighborList = pite->Info.QuerierIpAddr;
  1064. }
  1065. return NO_ERROR; // no neighbors
  1066. }
  1067. //-------------------------------------------------------------------------
  1068. // GetMfeStatus
  1069. //
  1070. // set statusCode to MFE_OIF_PRUNED if the GroupAddr Mcast group is not
  1071. // joined on the interface, else set it to MFE_NO_ERROR
  1072. //-------------------------------------------------------------------------
  1073. DWORD
  1074. APIENTRY
  1075. GetMfeStatus(
  1076. IN DWORD IfIndex,
  1077. IN DWORD GroupAddr,
  1078. IN DWORD SourceAddr,
  1079. OUT PBYTE StatusCode
  1080. )
  1081. {
  1082. PIF_TABLE_ENTRY pite;
  1083. PGROUP_TABLE_ENTRY pge;
  1084. PGI_ENTRY pgie;
  1085. // by default, set code to group not found on the interface.
  1086. // if found, set it to MFE_NO_ERROR later on.
  1087. *StatusCode = MFE_OIF_PRUNED;
  1088. ACQUIRE_IF_LOCK_SHARED(IfIndex, "_GetMfeStatus");
  1089. pite = GetIfByIndex(IfIndex);
  1090. if (pite!=NULL) {
  1091. ACQUIRE_GROUP_LOCK(GroupAddr, "_GetMfeStatus");
  1092. pge = GetGroupFromGroupTable(GroupAddr, NULL, 0);
  1093. if (pge!=NULL) {
  1094. pgie = GetGIFromGIList(pge, pite, 0, ANY_GROUP_TYPE, NULL, 0);
  1095. if (pgie!=NULL)
  1096. *StatusCode = MFE_NO_ERROR;
  1097. }
  1098. RELEASE_GROUP_LOCK(GroupAddr, "_GetMfeStatus");
  1099. }
  1100. RELEASE_IF_LOCK_SHARED(IfIndex, "_GetMfeStatus");
  1101. return NO_ERROR;
  1102. }