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.

1142 lines
41 KiB

  1. #include <precomp.h>
  2. #include "rpcsrv.h"
  3. #include "utils.h"
  4. #include "intflist.h"
  5. #include "deviceio.h"
  6. #include "wzcsvc.h"
  7. #include "notify.h"
  8. #include "storage.h"
  9. #include "zcdblog.h"
  10. #include "tracing.h"
  11. //taroonm
  12. #include <wifipol.h>
  13. #define WZEROCONF_SERVICE TEXT("wzcsvc")
  14. #define EAPOL_LINKED
  15. SERVICE_STATUS g_WZCSvcStatus;
  16. SERVICE_STATUS_HANDLE g_WZCSvcStatusHandle = NULL;
  17. HDEVNOTIFY g_WZCSvcDeviceNotif = NULL;
  18. UINT g_nThreads = 0;
  19. HINSTANCE g_hInstance = NULL;
  20. //context of users preferences
  21. WZC_INTERNAL_CONTEXT g_wzcInternalCtxt = {0};
  22. BOOL WINAPI DllMain(
  23. HINSTANCE hinstDLL, // handle to the DLL module
  24. DWORD fdwReason, // reason for calling function
  25. LPVOID lpvReserved // reserved
  26. )
  27. {
  28. if (g_hInstance == NULL)
  29. g_hInstance = hinstDLL;
  30. return TRUE;
  31. }
  32. //-----------------------------------------------------------
  33. VOID WINAPI
  34. WZCSvcMain(
  35. IN DWORD dwArgc,
  36. IN LPWSTR *lpwszArgv)
  37. {
  38. DWORD dwError = ERROR_SUCCESS;
  39. DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
  40. BOOL bLogEnabled = FALSE;
  41. // Initialize the workstation to receive service requests
  42. // by registering the service control handler.
  43. g_WZCSvcStatusHandle = RegisterServiceCtrlHandlerEx(
  44. WZEROCONF_SERVICE,
  45. WZCSvcControlHandler,
  46. NULL);
  47. if (g_WZCSvcStatusHandle == (SERVICE_STATUS_HANDLE)NULL)
  48. return;
  49. // this is the first thread to run
  50. InterlockedIncrement(&g_nThreads);
  51. // Initialize Tracing
  52. TrcInitialize();
  53. // Initialize the Event logging
  54. EvtInitialize();
  55. DbgPrint((TRC_TRACK,"**** [WZCSvcMain - Service Start Pending"));
  56. // Initialize all the status fields so that the subsequent calls
  57. // to SetServiceStatus need to only update fields that changed.
  58. g_WZCSvcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  59. g_WZCSvcStatus.dwCurrentState = SERVICE_START_PENDING;
  60. g_WZCSvcStatus.dwControlsAccepted = 0;
  61. g_WZCSvcStatus.dwCheckPoint = 1;
  62. g_WZCSvcStatus.dwWaitHint = 4000;
  63. g_WZCSvcStatus.dwWin32ExitCode = ERROR_SUCCESS;
  64. g_WZCSvcStatus.dwServiceSpecificExitCode = 0;
  65. // update status to START_PENDING
  66. WZCSvcUpdateStatus();
  67. // Initialize global hashes. If this fails it means the most important
  68. // critical section failed to initialize - no point in going further.
  69. dwError = HshInitialize(&g_hshHandles);
  70. if (dwError != ERROR_SUCCESS)
  71. goto exit;
  72. dwError = LstInitIntfHashes();
  73. if (dwError != ERROR_SUCCESS)
  74. goto exit;
  75. //Initialize the service's context
  76. dwError = WZCContextInit(&g_wzcInternalCtxt);
  77. if (dwError != ERROR_SUCCESS)
  78. goto exit;
  79. // TODO: the block below should be moved to a function responsible for
  80. // loading the whole g_wzcInternalCtxt from the persistent storage
  81. {
  82. // load the service's context from the registry
  83. dwError = StoLoadWZCContext(NULL, &(g_wzcInternalCtxt.wzcContext));
  84. if (ERROR_SUCCESS != dwError)
  85. goto exit;
  86. // load the global interface template from the registry.
  87. dwError = StoLoadIntfConfig(NULL, g_wzcInternalCtxt.pIntfTemplate);
  88. DbgAssert((dwError == ERROR_SUCCESS,"Err %d loading the template interface from the registry"));
  89. }
  90. // Open log database if logging enabled
  91. EnterCriticalSection(&g_wzcInternalCtxt.csContext);
  92. bLogEnabled = ((g_wzcInternalCtxt.wzcContext.dwFlags & WZC_CTXT_LOGGING_ON) != 0);
  93. LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
  94. dwError = InitWZCDbGlobals(bLogEnabled);
  95. if ((INT)dwError < 0) {
  96. EvtLogWzcError(WZCSVC_SERVICE_FAILED, dwError);
  97. dwError = ERROR_DATABASE_FAILURE;
  98. }
  99. if (ERROR_SUCCESS != dwError)
  100. goto exit;
  101. dwError = LstInitTimerQueue();
  102. if (dwError != ERROR_SUCCESS)
  103. goto exit;
  104. #ifdef EAPOL_LINKED
  105. // Start EAPOL/802.1X
  106. EAPOLServiceMain (dwArgc, NULL);
  107. #endif
  108. // load the interfaces list
  109. dwError = LstLoadInterfaces();
  110. DbgAssert((dwError == ERROR_SUCCESS,"LstLoadInterfaces failed with error %d", dwError));
  111. // register for service control notifications
  112. ZeroMemory (&PnPFilter, sizeof(PnPFilter));
  113. PnPFilter.dbcc_size = sizeof(PnPFilter);
  114. PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  115. PnPFilter.dbcc_classguid = GUID_NDIS_LAN_CLASS;
  116. // NOTE: EAPOL service is only working with ANSI strings, hence the ANSI calls
  117. g_WZCSvcDeviceNotif = RegisterDeviceNotificationA(
  118. (HANDLE)g_WZCSvcStatusHandle,
  119. &PnPFilter,
  120. DEVICE_NOTIFY_SERVICE_HANDLE );
  121. DbgAssert((g_WZCSvcDeviceNotif != (HDEVNOTIFY) NULL,
  122. "Registering for device notifications failed with error %d", GetLastError));
  123. // register with WMI for device notifications
  124. dwError = WZCSvcWMINotification(TRUE);
  125. DbgAssert((dwError == ERROR_SUCCESS,"WZCSvcRegisterWMINotif failed with error %d", dwError));
  126. // Start the RPC Server.
  127. dwError = WZCSvcStartRPCServer();
  128. DbgAssert((dwError == ERROR_SUCCESS,"WZCStartRPCServer failed with error %d", dwError));
  129. //taroonM: Policy Engine Init
  130. dwError = InitPolicyEngine(dwPolicyEngineParam, &hPolicyEngineThread);
  131. DbgAssert((dwError == ERROR_SUCCESS,"InitPolicyEngine failed with error %d", dwError));
  132. exit:
  133. if (dwError == ERROR_SUCCESS)
  134. {
  135. g_WZCSvcStatus.dwCurrentState = SERVICE_RUNNING;
  136. g_WZCSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_SESSIONCHANGE;
  137. g_WZCSvcStatus.dwCheckPoint = 0;
  138. g_WZCSvcStatus.dwWaitHint = 0;
  139. // update status to RUNNING
  140. WZCSvcUpdateStatus();
  141. DbgPrint((TRC_TRACK,"**** WZCSvcMain - Service Running"));
  142. DbLogWzcInfo(WZCSVC_SERVICE_STARTED, NULL);
  143. }
  144. else
  145. {
  146. DbgPrint((TRC_TRACK,"**** WZCSvcMain - Service Failed to start"));
  147. // stop the WZC engine
  148. WZCSvcShutdown(dwError);
  149. // stop the EAP engine
  150. EAPOLCleanUp (dwError);
  151. // destroy the handles hash
  152. HshDestroy(&g_hshHandles);
  153. // if database has been opened, close it here since there is no one else using it
  154. DeInitWZCDbGlobals();
  155. // finaly destroy the WZC context
  156. WZCContextDestroy(&g_wzcInternalCtxt);
  157. // if we did successfully register with SCM, then indicate the service has stopped
  158. if (g_WZCSvcStatusHandle != (SERVICE_STATUS_HANDLE)NULL)
  159. {
  160. g_WZCSvcStatus.dwCurrentState = SERVICE_STOPPED;
  161. g_WZCSvcStatus.dwControlsAccepted = 0;
  162. g_WZCSvcStatus.dwCheckPoint = 0;
  163. g_WZCSvcStatus.dwWaitHint = 0;
  164. g_WZCSvcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  165. g_WZCSvcStatus.dwServiceSpecificExitCode = dwError;
  166. WZCSvcUpdateStatus();
  167. }
  168. EvtTerminate();
  169. TrcTerminate();
  170. }
  171. InterlockedDecrement(&g_nThreads);
  172. return;
  173. }
  174. // global array for the GUIDs for the WMI notifications
  175. LPGUID g_lpGuidWmiNotif[] = {
  176. (LPGUID)&GUID_NDIS_NOTIFY_BIND,
  177. (LPGUID)&GUID_NDIS_NOTIFY_UNBIND,
  178. (LPGUID)&GUID_NDIS_STATUS_MEDIA_CONNECT,
  179. (LPGUID)&GUID_NDIS_STATUS_MEDIA_DISCONNECT
  180. };
  181. //-----------------------------------------------------------
  182. // Handles all WMI registration and de-registration
  183. DWORD
  184. WZCSvcWMINotification(BOOL bRegister)
  185. {
  186. DWORD dwErr = ERROR_SUCCESS;
  187. INT nIdx;
  188. DbgPrint((TRC_TRACK,"[WZCSvcWMINotification(%d)", bRegister));
  189. // do the requested action - registration / deregistration
  190. // if registering for notifications, break the loop first time a registration failed
  191. // if de-registering, ignore the errors and go on deregistering the remaining notifications
  192. for (nIdx = 0;
  193. nIdx < sizeof(g_lpGuidWmiNotif)/sizeof(LPGUID) && (!bRegister || dwErr == ERROR_SUCCESS);
  194. nIdx++)
  195. {
  196. dwErr = WmiNotificationRegistrationW(
  197. g_lpGuidWmiNotif[nIdx],
  198. (BOOLEAN)bRegister,
  199. (PVOID)WZCSvcWMINotificationHandler,
  200. (ULONG_PTR)NULL,
  201. NOTIFICATION_CALLBACK_DIRECT);
  202. DbgAssert((dwErr == 0, "Failed to %s notif index %d",
  203. bRegister ? "register" : "de-register",
  204. nIdx));
  205. }
  206. // in case a registration was requested and one of the Wmi calls above failed,
  207. // rollback the action by deregistering for whatever was registered successfully
  208. if (bRegister && dwErr != ERROR_SUCCESS)
  209. {
  210. DbgPrint((TRC_GENERIC,"Rollback WmiNotif for %d Guids", nIdx));
  211. for(nIdx--; nIdx>=0; nIdx--)
  212. {
  213. WmiNotificationRegistrationW(
  214. g_lpGuidWmiNotif[nIdx],
  215. (BOOLEAN)FALSE,
  216. (PVOID)WZCSvcWMINotificationHandler,
  217. (ULONG_PTR)NULL,
  218. NOTIFICATION_CALLBACK_DIRECT);
  219. }
  220. }
  221. DbgPrint((TRC_TRACK, "WZCSvcWMINotification]=%d", dwErr));
  222. return dwErr;
  223. }
  224. //-----------------------------------------------------------
  225. DWORD
  226. WZCSvcUpdateStatus()
  227. {
  228. DbgPrint((TRC_TRACK,"[WZCSvcUpdateStatus(%d)]", g_WZCSvcStatus.dwCurrentState));
  229. return SetServiceStatus(g_WZCSvcStatusHandle, &g_WZCSvcStatus) ?
  230. ERROR_SUCCESS : GetLastError();
  231. }
  232. //-----------------------------------------------------------
  233. DWORD
  234. WZCSvcControlHandler(
  235. IN DWORD dwControl,
  236. IN DWORD dwEventType,
  237. IN PVOID pEventData,
  238. IN PVOID pContext)
  239. {
  240. DWORD dwRetCode = NO_ERROR;
  241. BOOL bDecrement = TRUE;
  242. InterlockedIncrement(&g_nThreads);
  243. DbgPrint((TRC_TRACK|TRC_NOTIF,"[WZCSvcControlHandler(%d,%d,..)", dwControl, dwEventType));
  244. DbgPrint((TRC_NOTIF,"SCM Notification: Control=0x%x; EventType=0x%04x", dwControl, dwEventType));
  245. switch (dwControl)
  246. {
  247. case SERVICE_CONTROL_DEVICEEVENT:
  248. if (g_WZCSvcStatus.dwCurrentState == SERVICE_RUNNING &&
  249. pEventData != NULL)
  250. {
  251. PDEV_BROADCAST_DEVICEINTERFACE pInfo = (DEV_BROADCAST_DEVICEINTERFACE *)pEventData;
  252. if (pInfo->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
  253. {
  254. PWZC_DEVICE_NOTIF pDevNotif;
  255. pDevNotif = MemCAlloc(FIELD_OFFSET(WZC_DEVICE_NOTIF, dbDeviceIntf) + pInfo->dbcc_size);
  256. DbgAssert((pDevNotif != NULL, "Not enough memory?"));
  257. if (pDevNotif != NULL)
  258. {
  259. // build up the notification information
  260. switch(dwEventType)
  261. {
  262. case DBT_DEVICEARRIVAL:
  263. pDevNotif->dwEventType = WZCNOTIF_DEVICE_ARRIVAL;
  264. break;
  265. case DBT_DEVICEREMOVECOMPLETE:
  266. pDevNotif->dwEventType = WZCNOTIF_DEVICE_REMOVAL;
  267. break;
  268. default:
  269. pDevNotif->dwEventType = WZCNOTIF_UNKNOWN;
  270. DbgPrint((TRC_ERR,"SCM Notification %d is not recognized", dwEventType));
  271. break;
  272. }
  273. // pass down notification only if it is recognized at this level
  274. if (pDevNotif->dwEventType != WZCNOTIF_UNKNOWN)
  275. {
  276. memcpy(&(pDevNotif->dbDeviceIntf), pInfo, pInfo->dbcc_size);
  277. // pDevNotif will be MemFree-ed by the worker thread
  278. if (QueueUserWorkItem(
  279. (LPTHREAD_START_ROUTINE)WZCWrkDeviceNotifHandler,
  280. (LPVOID)pDevNotif,
  281. WT_EXECUTELONGFUNCTION))
  282. {
  283. bDecrement = FALSE;
  284. }
  285. }
  286. else
  287. {
  288. MemFree(pDevNotif);
  289. }
  290. }
  291. }
  292. }
  293. break;
  294. case SERVICE_CONTROL_STOP:
  295. case SERVICE_CONTROL_SHUTDOWN:
  296. // make sure the control is not sent twice forcing the service to lock
  297. // a critical section already destroyed! (see WZCSvcShutdown->StoSaveConfig)
  298. if (g_WZCSvcStatus.dwCurrentState != SERVICE_STOPPED)
  299. {
  300. g_WZCSvcStatus.dwCurrentState = SERVICE_STOP_PENDING;
  301. g_WZCSvcStatus.dwCheckPoint = 1;
  302. g_WZCSvcStatus.dwWaitHint = 60000;
  303. WZCSvcUpdateStatus();
  304. // Shutdown Zero Conf
  305. WZCSvcShutdown(ERROR_SUCCESS);
  306. // Shutdown EAPOL/802.1X
  307. EAPOLCleanUp (NO_ERROR);
  308. DbgPrint((TRC_TRACK,"EAPOLCleanUp done!"));
  309. // destroy the handles hash
  310. HshDestroy(&g_hshHandles);
  311. DbgPrint((TRC_TRACK,"Hashes Destroyed!"));
  312. DeInitWZCDbGlobals();
  313. // clean up the service's context
  314. WZCContextDestroy(&g_wzcInternalCtxt);
  315. //WZCSvcUpdateStatus();
  316. g_WZCSvcStatus.dwCurrentState = SERVICE_STOPPED;
  317. g_WZCSvcStatus.dwControlsAccepted = 0;
  318. g_WZCSvcStatus.dwCheckPoint = 0;
  319. g_WZCSvcStatus.dwWaitHint = 0;
  320. g_WZCSvcStatus.dwWin32ExitCode = ERROR_SUCCESS;
  321. g_WZCSvcStatus.dwServiceSpecificExitCode = 0;
  322. WZCSvcUpdateStatus();
  323. // this is the last thread of the service (guaranteed by WZCSvcShutdown)
  324. // all datastructures have been closed, tracing has been disabled. No need
  325. // to decrement the thread counter since no one uses it anymore.
  326. // just set it to 0 to play safe
  327. bDecrement = FALSE;
  328. g_nThreads = 0;
  329. EvtTerminate();
  330. TrcTerminate();
  331. }
  332. break;
  333. case SERVICE_CONTROL_SESSIONCHANGE:
  334. // 802.1X session change handler
  335. ElSessionChangeHandler (
  336. pEventData,
  337. dwEventType
  338. );
  339. break;
  340. }
  341. if (bDecrement)
  342. {
  343. DbgPrint((TRC_TRACK|TRC_NOTIF,"WZCSvcControlHandler]"));
  344. InterlockedDecrement(&g_nThreads);
  345. }
  346. return ERROR_SUCCESS;
  347. }
  348. //-----------------------------------------------------------
  349. // WZCSvcWMINotificationHandler: Callback function called by WMI on any registered
  350. // notification (as of 01/19/01: bind/unbind/connect/disconnect)
  351. VOID CALLBACK
  352. WZCSvcWMINotificationHandler(
  353. IN PWNODE_HEADER pWnodeHdr,
  354. IN UINT_PTR uiNotificationContext)
  355. {
  356. DWORD dwErr = ERROR_SUCCESS;
  357. PWZC_DEVICE_NOTIF pDevNotif = NULL;
  358. PWNODE_SINGLE_INSTANCE pWnode = (PWNODE_SINGLE_INSTANCE)pWnodeHdr;
  359. LPWSTR wszTransport;
  360. BOOL bDecrement = TRUE;
  361. // increment the thread counter
  362. InterlockedIncrement(&g_nThreads);
  363. DbgPrint((TRC_TRACK|TRC_NOTIF, "[WZCSvcWMIHandler(0x%p)", pWnodeHdr));
  364. // check if the service is still running, otherwise ignore
  365. // the notification
  366. if (g_WZCSvcStatus.dwCurrentState != SERVICE_RUNNING)
  367. goto exit;
  368. // check if we have valid notification data from WMI
  369. if (pWnodeHdr == NULL)
  370. {
  371. dwErr = ERROR_INVALID_PARAMETER;
  372. goto exit;
  373. }
  374. // allocate memory for the WZC Notification Structure.
  375. pDevNotif = MemCAlloc(FIELD_OFFSET(WZC_DEVICE_NOTIF, wmiNodeHdr) + pWnodeHdr->BufferSize);
  376. if (pDevNotif == NULL)
  377. {
  378. dwErr = GetLastError();
  379. goto exit;
  380. }
  381. // translate the specific WMI notification code to WZC notification
  382. else if (!memcmp( &(pWnodeHdr->Guid), &GUID_NDIS_STATUS_MEDIA_CONNECT, sizeof(GUID)))
  383. pDevNotif->dwEventType = WZCNOTIF_MEDIA_CONNECT;
  384. else if (!memcmp( &(pWnodeHdr->Guid), &GUID_NDIS_STATUS_MEDIA_DISCONNECT, sizeof(GUID)))
  385. pDevNotif->dwEventType = WZCNOTIF_MEDIA_DISCONNECT;
  386. else if (!memcmp( &(pWnodeHdr->Guid), &GUID_NDIS_NOTIFY_BIND, sizeof(GUID)))
  387. pDevNotif->dwEventType = WZCNOTIF_ADAPTER_BIND;
  388. else if (!memcmp( &(pWnodeHdr->Guid), &GUID_NDIS_NOTIFY_UNBIND, sizeof(GUID)))
  389. pDevNotif->dwEventType = WZCNOTIF_ADAPTER_UNBIND;
  390. else
  391. {
  392. pDevNotif->dwEventType = WZCNOTIF_UNKNOWN;
  393. DbgPrint((TRC_ERR,"WMI Notification GUID is not recognized"));
  394. goto exit;
  395. }
  396. // copy the WMI notification data into the local buffer
  397. memcpy(&(pDevNotif->wmiNodeHdr), pWnodeHdr, pWnodeHdr->BufferSize);
  398. // pDevNotif will be MemFree-ed by the worker thread
  399. if (!QueueUserWorkItem(
  400. (LPTHREAD_START_ROUTINE)WZCWrkDeviceNotifHandler,
  401. (LPVOID)pDevNotif,
  402. WT_EXECUTELONGFUNCTION))
  403. {
  404. dwErr = GetLastError();
  405. goto exit;
  406. }
  407. bDecrement = FALSE;
  408. // since the working thread has been created successfully, the notification
  409. // structure allocated above will be free-ed by the thread. Set the local
  410. // pointer to NULL to prevent the memory from being free-ed prematurely
  411. // (MemFree does nothing when pointer is NULL)
  412. pDevNotif = NULL;
  413. exit:
  414. MemFree(pDevNotif);
  415. DbgPrint((TRC_TRACK|TRC_NOTIF, "WZCSvcWMIHandler=%d]", dwErr));
  416. if (bDecrement)
  417. InterlockedDecrement(&g_nThreads);
  418. }
  419. //-----------------------------------------------------------
  420. VOID
  421. WZCSvcShutdown(IN DWORD dwErrorCode)
  422. {
  423. DbgPrint((TRC_TRACK,"[WZCSvcShutdown(%d)", dwErrorCode));
  424. //taroonm:
  425. TerminatePolicyEngine(hPolicyEngineThread);
  426. if (g_WZCSvcDeviceNotif != NULL && !UnregisterDeviceNotification(g_WZCSvcDeviceNotif))
  427. {
  428. DbgPrint((TRC_ERR,"Err: UnregisterDeviceNotification->%d", GetLastError()));
  429. }
  430. // reset the notification handler since it has already been unregistered
  431. g_WZCSvcDeviceNotif = NULL;
  432. // unregister from WMI
  433. WZCSvcWMINotification(FALSE);
  434. // stop first the RPC server
  435. WZCSvcStopRPCServer();
  436. // all the notification registrations have been removed.
  437. // Block here until all worker/rpc threads terminate.
  438. DbgPrint((TRC_SYNC,"Waiting for %d thread(s) to terminate", g_nThreads));
  439. while(g_nThreads != 1)
  440. {
  441. Sleep(1000);
  442. DbgPrint((TRC_SYNC,"Waiting for %d more thread(s).", g_nThreads));
  443. }
  444. // save the configuration to the registry
  445. StoSaveConfig();
  446. // destroy all the hashes related to the list of interfaces
  447. // (included the list itself)
  448. LstDestroyIntfHashes();
  449. // destroy the timer queue. At this point there should be no timer queued so
  450. // there is no point in waiting for any completion
  451. LstDestroyTimerQueue();
  452. DbgPrint((TRC_TRACK,"WZCSvcShutdown]"));
  453. }
  454. //-----------------------------------------------------------
  455. VOID
  456. WZCWrkDeviceNotifHandler(
  457. IN LPVOID pvData)
  458. {
  459. DWORD dwErr = ERROR_SUCCESS;
  460. PWZC_DEVICE_NOTIF pDevNotif = (PWZC_DEVICE_NOTIF)pvData;
  461. PWNODE_SINGLE_INSTANCE pWnode = (PWNODE_SINGLE_INSTANCE)&(pDevNotif->wmiNodeHdr);
  462. LPBYTE pbDeviceKey = NULL; // pointer in the notification data where the dev key is
  463. UINT nDeviceKeyLen; // number of bytes for the dev key
  464. LPWSTR pwszDeviceKey = NULL;
  465. PINTF_CONTEXT pIntfContext = NULL;
  466. PHASH_NODE *ppHash = NULL; // reference to the hash to use for getting the INTF_CONTEXT
  467. PHASH_NODE pHashNode = NULL; // interface's node in the hash
  468. BOOL bForwardUp = FALSE; // specifies whether the notification needs to passed to the upper layers
  469. DbgPrint((TRC_TRACK,"[WZCWrkDeviceNotifHandler(wzcnotif %d)", pDevNotif->dwEventType));
  470. DbgAssert((pDevNotif != NULL, "(null) device notification info!"));
  471. // don't do one single bit of work if the service is not in the running state
  472. if (g_WZCSvcStatus.dwCurrentState != SERVICE_RUNNING)
  473. goto exit;
  474. // get the Device Key information for the event (either the GUID or the Description)
  475. switch(pDevNotif->dwEventType)
  476. {
  477. case WZCNOTIF_DEVICE_REMOVAL:
  478. case WZCNOTIF_ADAPTER_UNBIND:
  479. // do forward up device removal or unbind no matter what
  480. bForwardUp = TRUE;
  481. // no break.
  482. case WZCNOTIF_DEVICE_ARRIVAL:
  483. case WZCNOTIF_ADAPTER_BIND:
  484. {
  485. LPBYTE pbDeviceKeyEnd = NULL;
  486. if (pDevNotif->dwEventType == WZCNOTIF_DEVICE_ARRIVAL ||
  487. pDevNotif->dwEventType == WZCNOTIF_DEVICE_REMOVAL)
  488. {
  489. // if the notification comes from SCM, get the pointer to the "\device\{guid}"
  490. // string from the dbcc_name field
  491. pbDeviceKey = (LPBYTE)(pDevNotif->dbDeviceIntf.dbcc_name);
  492. }
  493. else
  494. {
  495. // check if the notification refers to the NDISUIO transport
  496. pbDeviceKey = RtlOffsetToPointer(pWnode, pWnode->DataBlockOffset);
  497. // if this is not a notification for the NDISUIO transport, ignore it.
  498. if (wcsncmp ((LPWSTR)pbDeviceKey, L"NDISUIO", 7))
  499. {
  500. DbgPrint((TRC_NOTIF,"Ignore WMI Notif %d for Transport %S",
  501. pDevNotif->dwEventType,
  502. pbDeviceKey));
  503. goto exit;
  504. }
  505. // get first the pointer to the Transport Name
  506. pbDeviceKey = RtlOffsetToPointer(pWnode, pWnode->DataBlockOffset);
  507. // skip to the "\device\{guid}" string
  508. pbDeviceKey += (wcslen((LPWSTR)pbDeviceKey) + 1) * sizeof(WCHAR);
  509. }
  510. // build now the actual "{guid}" string from the L"\DEVICE\{guid}" string
  511. // pointed by wszGuid
  512. pbDeviceKey = (LPBYTE)wcsrchr( (LPWSTR)pbDeviceKey, L'{' );
  513. if (pbDeviceKey != NULL)
  514. pbDeviceKeyEnd = (LPBYTE)wcsrchr( (LPWSTR)pbDeviceKey, L'}' );
  515. if (pbDeviceKey == NULL || pbDeviceKeyEnd == NULL)
  516. {
  517. DbgPrint((TRC_ERR,"Err: Mal-formed dbcc_name"));
  518. goto exit;
  519. }
  520. // include the closing curved bracket in the GUID string
  521. pbDeviceKeyEnd += sizeof(WCHAR);
  522. nDeviceKeyLen = (UINT)(pbDeviceKeyEnd - pbDeviceKey);
  523. // get the reference to the GUID hash. This will be used in order to locate
  524. // the interface context. This reference is guaranteed to exist since it is a static
  525. // global variable.
  526. ppHash = &g_lstIntfHashes.pHnGUID;
  527. break;
  528. }
  529. case WZCNOTIF_MEDIA_DISCONNECT:
  530. case WZCNOTIF_MEDIA_CONNECT:
  531. {
  532. LPBYTE pbDeviceKeyEnd = NULL;
  533. // disconnect should be forwarded up no matter what
  534. // for connects, we assume we'll forward it up. After dispatching the event
  535. // to the state machine, if this resulted in a WZC notification we'll block
  536. // the forwarding.
  537. bForwardUp = TRUE;
  538. // for MEDIA_CONNECT / DISCONNECT events, we also get the adapter's GUID
  539. pbDeviceKey = RtlOffsetToPointer(pWnode, pWnode->DataBlockOffset);
  540. // build now the actual "{guid}" string from the L"\DEVICE\{guid}" string
  541. // pointed by wszGuid
  542. pbDeviceKey = (LPBYTE)wcsrchr( (LPWSTR)pbDeviceKey, L'{' );
  543. if (pbDeviceKey != NULL)
  544. pbDeviceKeyEnd = (LPBYTE)wcsrchr( (LPWSTR)pbDeviceKey,L'}' );
  545. if (pbDeviceKey == NULL || pbDeviceKeyEnd == NULL)
  546. {
  547. DbgPrint((TRC_ERR,"Err: Mal-formed device name"));
  548. goto exit;
  549. }
  550. pbDeviceKeyEnd += sizeof(WCHAR);
  551. nDeviceKeyLen = (UINT)(pbDeviceKeyEnd - pbDeviceKey);
  552. // get the reference to the GUID hash. This will be used in order to locate
  553. // the interface context. This reference is guaranteed to exist since it is a static
  554. // global variable.
  555. ppHash = &g_lstIntfHashes.pHnGUID;
  556. break;
  557. }
  558. // no need to specify "default:" as the event type has been already filtered
  559. // out to one of the valid events
  560. }
  561. // get memory for GUID (add space for the null terminator)
  562. pwszDeviceKey = (LPWSTR)MemCAlloc(nDeviceKeyLen + sizeof(WCHAR));
  563. if (pwszDeviceKey == NULL)
  564. {
  565. dwErr = GetLastError();
  566. goto exit;
  567. }
  568. // copy the GUID string in the key (because of the CAlloc, the '\0' is already there)
  569. memcpy(pwszDeviceKey, pbDeviceKey, nDeviceKeyLen);
  570. // locate now the INTF_CONTEXT structure related to this notification
  571. // and keep the lock on the hashes all the time (since the PnP event mostly sure
  572. // results in removing / adding an interface context which means altering the
  573. // hash)
  574. EnterCriticalSection(&(g_lstIntfHashes.csMutex));
  575. dwErr = HshQueryObjectRef(
  576. *ppHash,
  577. pwszDeviceKey,
  578. &pHashNode);
  579. if (dwErr == ERROR_SUCCESS)
  580. {
  581. pIntfContext = (PINTF_CONTEXT)pHashNode->pObject;
  582. // at this point we know the notification type, the key info and
  583. // the INTERFACE_CONTEXT object (if any) for the device.
  584. DbgPrint((TRC_NOTIF,"WZCNotif %d for Device Key \"%S\". Context=0x%p",
  585. pDevNotif->dwEventType,
  586. pwszDeviceKey,
  587. pIntfContext));
  588. }
  589. // forward now the notification for processing
  590. dwErr = LstNotificationHandler(&pIntfContext, pDevNotif->dwEventType, pwszDeviceKey);
  591. // At this point, bForwardUp is FALSE only for ADAPTER_BIND or DEVICE_ARRIVAL
  592. // If this is a new adapter, but not a wireless one, pass up the notification.
  593. if (pDevNotif->dwEventType == WZCNOTIF_ADAPTER_BIND || pDevNotif->dwEventType == WZCNOTIF_DEVICE_ARRIVAL)
  594. bForwardUp = bForwardUp || (dwErr == ERROR_MEDIA_INCOMPATIBLE);
  595. // At this point, bForwardUp is FALSE only for ADAPTER_BIND or DEVICE_ARRIVAL for a wireless adapter
  596. // If WZC doesn't seem to be enabled for this adapter, pass up the notification
  597. if (dwErr == ERROR_SUCCESS && pIntfContext != NULL)
  598. bForwardUp = bForwardUp || ((pIntfContext->dwCtlFlags & INTFCTL_ENABLED) == 0);
  599. // At this point, bForwardUp is FALSE only for ADAPTER_BIND or DEVICE_ARRIVAL for a wireless adapter
  600. // on which WZC is enabled. For all the other cases, notification is passed through.
  601. // All that remains is to block the pass-through of the notification if we deal with a valid context
  602. // for which INTFCTL_INTERNAL_BLK_MEDIACONN bit is set. This bit is being set in StateNotifyFn
  603. // and it is reset after processing each event / command so it is only a narrow case where we really
  604. // need to block. We do block it because one WZC notification must have already been sent up so
  605. // there is totally redundant to pass another one up.
  606. if (pIntfContext != NULL)
  607. {
  608. bForwardUp = bForwardUp && !(pIntfContext->dwCtlFlags & INTFCTL_INTERNAL_BLK_MEDIACONN);
  609. // now, since we determined whether we need or not to pass up the PnP notification
  610. // we can (and must) clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit.
  611. pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
  612. }
  613. // for all the remaining cases, the notification is going to be substituted
  614. // later (in {SN} state) with a "WZCNOTIF_WZC_CONNECT" notification. Assume something goes wrong
  615. // and the interface never gets to {SN}, it means there is no reason for the upper layer to act
  616. // on an interface for which the underlying layer (Zero Conf) failed.
  617. // unlock the hashes at the end
  618. LeaveCriticalSection(&(g_lstIntfHashes.csMutex));
  619. if (bForwardUp)
  620. {
  621. // Notify upper level app (802.1x) that the selected
  622. // 802.11 configuration is successful.
  623. DbgPrint((TRC_NOTIF, "Passing through notification %d",pDevNotif->dwEventType));
  624. dwErr = ElMediaEventsHandler(pDevNotif);
  625. DbgAssert((dwErr == ERROR_SUCCESS, "Error or Exception 0x%x when passing through notification", dwErr));
  626. }
  627. exit:
  628. MemFree(pwszDeviceKey);
  629. MemFree(pDevNotif);
  630. DbgPrint((TRC_TRACK,"WZCWrkDeviceNotifHandler=%d]", dwErr));
  631. // decrement the thread counter
  632. InterlockedDecrement(&g_nThreads);
  633. }
  634. //-----------------------------------------------------------
  635. // WZCTimeoutCallback: timer callback routine. It should not lock any cs, but just spawn
  636. // the timer handler routine after referencing the context (to avoid premature deletion)
  637. VOID WINAPI
  638. WZCTimeoutCallback(
  639. IN PVOID pvData,
  640. IN BOOL fTimerOrWaitFired)
  641. {
  642. DWORD dwErr = ERROR_SUCCESS;
  643. PINTF_CONTEXT pIntfContext = (PINTF_CONTEXT)pvData;
  644. BOOL bDecrement = TRUE;
  645. // increment the thread counter the first thing!
  646. InterlockedIncrement(&g_nThreads);
  647. DbgPrint((TRC_TRACK|TRC_NOTIF, "[WZCTimeoutCallback(0x%p)", pIntfContext));
  648. DbgAssert((pIntfContext != NULL, "Invalid (null) context in timer callback!"));
  649. // reference the context to make sure no one will delete it unexpectedly.
  650. LstRccsReference(pIntfContext);
  651. if (!QueueUserWorkItem(
  652. (LPTHREAD_START_ROUTINE)WZCSvcTimeoutHandler,
  653. (LPVOID)pIntfContext,
  654. WT_EXECUTELONGFUNCTION))
  655. {
  656. dwErr = GetLastError();
  657. goto exit;
  658. }
  659. bDecrement = FALSE;
  660. exit:
  661. DbgPrint((TRC_TRACK|TRC_NOTIF, "WZCTimeoutCallback=%d]", dwErr));
  662. if (bDecrement)
  663. {
  664. // getting here would be really bad - it would mean we failed to spawn the
  665. // timer handler. We need to make sure we not unbalance the reference counter
  666. // on the context. The counter can't get to 0 since the device notification thread
  667. // is waiting for all the timer routines to complete.
  668. InterlockedDecrement(&(pIntfContext->rccs.nRefCount));
  669. InterlockedDecrement(&g_nThreads);
  670. }
  671. }
  672. //-----------------------------------------------------------
  673. VOID
  674. WZCSvcTimeoutHandler(
  675. IN PVOID pvData)
  676. {
  677. DWORD dwErr = ERROR_SUCCESS;
  678. PINTF_CONTEXT pIntfContext = (PINTF_CONTEXT)pvData;
  679. DbgPrint((TRC_TRACK,"[WZCSvcTimeoutHandler(0x%p)", pIntfContext));
  680. // lock the context here (it has been referenced in the timer callback!)
  681. LstRccsLock(pIntfContext);
  682. // the timer handler should be a noop in all the following cases:
  683. // - the service doesn't look to be either starting or running
  684. // - the timer handler is invalid. This is an indication the context is being destroyed
  685. // - the timer flag is not set! Same indication the context is being destroyed.
  686. if ((g_WZCSvcStatus.dwCurrentState == SERVICE_RUNNING || g_WZCSvcStatus.dwCurrentState == SERVICE_START_PENDING) &&
  687. (pIntfContext->hTimer != INVALID_HANDLE_VALUE) &&
  688. (pIntfContext->dwCtlFlags & INTFCTL_INTERNAL_TM_ON))
  689. {
  690. // since the timer fired already for this event and we only deal with
  691. // one time timers, reset the TIMER_ON flag for this context:
  692. pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_TM_ON;
  693. // dispatch the timeout event
  694. dwErr = StateDispatchEvent(
  695. eEventTimeout,
  696. pIntfContext,
  697. NULL);
  698. // clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit since this is not a media sense handler
  699. pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
  700. DbgAssert((dwErr == ERROR_SUCCESS,
  701. "Dispatching timeout event failed for context 0x%p\n",
  702. pIntfContext));
  703. }
  704. // unlock unref the context!
  705. LstRccsUnlockUnref(pIntfContext);
  706. DbgPrint((TRC_TRACK,"WZCSvcTimeoutHandler=%d]", dwErr));
  707. InterlockedDecrement(&g_nThreads);
  708. }
  709. //-----------------------------------------------------------
  710. VOID
  711. WZCWrkWzcSendNotif(
  712. IN LPVOID pvData)
  713. {
  714. DWORD dwErr = ERROR_SUCCESS;
  715. DbgPrint((TRC_TRACK,"[WZCWrkWzcSendNotif(0x%p)", pvData));
  716. DbgPrint((TRC_NOTIF, "Sending WZC_CONFIG_NOTIF to upper level apps"));
  717. dwErr = ElMediaEventsHandler(pvData);
  718. DbgPrint((TRC_TRACK,"WZCWrkWzcSendNotif]=%d", dwErr));
  719. InterlockedDecrement(&g_nThreads);
  720. }
  721. //-----------------------------------------------------------
  722. // EAPOLQueryGUIDNCSState
  723. // Called by Netman module query the ncs state of the GUID under 802.1X control
  724. // Arguments:
  725. // pGuidConn - Interface GUID
  726. // pncs - NCS status of the interface
  727. // Returns:
  728. // S_OK - network connection status is reported by WZC
  729. // S_FALSE - status is not controlled by WZC
  730. HRESULT
  731. WZCQueryGUIDNCSState (
  732. IN GUID *pGuidConn,
  733. OUT NETCON_STATUS *pncs)
  734. {
  735. HRESULT hr = S_FALSE;
  736. InterlockedIncrement(&g_nThreads);
  737. // check if the service is still running, return the call instantly
  738. if (g_WZCSvcStatus.dwCurrentState == SERVICE_RUNNING ||
  739. g_WZCSvcStatus.dwCurrentState == SERVICE_START_PENDING)
  740. {
  741. // check what Zero Config says about the adapter's status
  742. if (hr == S_FALSE)
  743. {
  744. WCHAR wszGuid[64]; // enough for "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
  745. // convert the GUID to "{xxx...}" and get the ncStatus from the interface context (if any)
  746. if (StringFromGUID2(pGuidConn, wszGuid, 64) != 0)
  747. hr = LstQueryGUIDNCStatus(wszGuid, pncs);
  748. }
  749. // check what 802.1x says about the adapter's status
  750. if (hr == S_FALSE)
  751. {
  752. hr = EAPOLQueryGUIDNCSState (
  753. pGuidConn,
  754. pncs);
  755. }
  756. }
  757. InterlockedDecrement(&g_nThreads);
  758. return hr;
  759. }
  760. //-----------------------------------------------------------
  761. // EAPOLQueryGUIDNCSState
  762. // WZCTrayIconReady
  763. //
  764. // Purpose: Called by Netman module to inform about Tray being
  765. // ready for notifications from WZCSVC
  766. // Arguments:
  767. // pszUserName - Username of the user logged in on the desktop
  768. // Returns:
  769. // None
  770. VOID
  771. WZCTrayIconReady (
  772. IN const WCHAR * pszUserName)
  773. {
  774. EAPOLTrayIconReady(pszUserName);
  775. }
  776. //-----------------------------------------------------------
  777. // WZCContextInit
  778. // Description:Initialises an internal context with default values
  779. // Parameters: pointer to an internal context with storage pre allocated
  780. // Returns: win32 error code
  781. DWORD WZCContextInit(PWZC_INTERNAL_CONTEXT pwzcICtxt)
  782. {
  783. DWORD dwErr = ERROR_SUCCESS;
  784. DbgPrint((TRC_TRACK,"[WZCContextInit(%p=%d)", pwzcICtxt, pwzcICtxt->bValid));
  785. if (pwzcICtxt->bValid)
  786. {
  787. dwErr = ERROR_ALREADY_INITIALIZED;
  788. }
  789. else
  790. {
  791. PWZC_CONTEXT pwzcCtxt = &(pwzcICtxt->wzcContext);
  792. DbgPrint((TRC_TRACK,"Initializing wzc context"));
  793. // null out the service's context
  794. ZeroMemory(pwzcCtxt, sizeof(WZC_CONTEXT));
  795. __try
  796. {
  797. //set defaults
  798. pwzcCtxt->tmTr = TMMS_DEFAULT_TR;
  799. pwzcCtxt->tmTc = TMMS_DEFAULT_TC;
  800. pwzcCtxt->tmTp = TMMS_DEFAULT_TP;
  801. pwzcCtxt->tmTf = TMMS_DEFAULT_TF;
  802. pwzcCtxt->tmTd = TMMS_DEFAULT_TD;
  803. //Init CriticalSection
  804. InitializeCriticalSection(&(pwzcICtxt->csContext));
  805. DbgPrint((TRC_TRACK,"Critical section initialized successfully"));
  806. // mark the context is valid
  807. pwzcICtxt->bValid = TRUE;
  808. }
  809. __except(EXCEPTION_EXECUTE_HANDLER)
  810. {
  811. dwErr = GetExceptionCode();
  812. }
  813. if (dwErr == ERROR_SUCCESS)
  814. {
  815. dwErr = LstConstructIntfContext(
  816. NULL,
  817. &(pwzcICtxt->pIntfTemplate));
  818. }
  819. }
  820. DbgPrint((TRC_TRACK,"WZCContextInit]=%d", dwErr));
  821. return dwErr;
  822. }
  823. //-----------------------------------------------------------
  824. // WZCContextDestroy
  825. // Description:Destroys an internal context with default values
  826. // Parameters: pointer to an internal context initialised using WZCContextInit
  827. // Returns: win32 error code
  828. DWORD WZCContextDestroy(PWZC_INTERNAL_CONTEXT pwzcICtxt)
  829. {
  830. DWORD dwErr = ERROR_SUCCESS;
  831. PWZC_CONTEXT pwzcCtxt = NULL;
  832. DbgPrint((TRC_TRACK,"[WZCContextDestroy"));
  833. if (pwzcICtxt->bValid)
  834. {
  835. // destroy the global context here
  836. LstDestroyIntfContext(pwzcICtxt->pIntfTemplate);
  837. pwzcICtxt->pIntfTemplate = NULL;
  838. pwzcICtxt->bValid = FALSE;
  839. //Destroy critical section
  840. DeleteCriticalSection(&(pwzcICtxt->csContext));
  841. }
  842. DbgPrint((TRC_TRACK,"WZCContextDestroy]=%d", dwErr));
  843. return dwErr;
  844. }
  845. //-----------------------------------------------------------
  846. // WzcContextQuery
  847. // Description: Queries specified params in the global context and sends the
  848. // values back to the client.
  849. // Parameters:
  850. // [in] dwInFlags - Bitmask of the WZC_CTL_* flags, indicates the
  851. // appropriate parameter.
  852. // [out] pContext - Holds current values requested by user
  853. // [out] pdwOutFlags - Indicates the values that were successfully returned
  854. // Returns: win32 error code
  855. DWORD WzcContextQuery(
  856. DWORD dwInFlags,
  857. PWZC_CONTEXT pContext,
  858. LPDWORD pdwOutFlags)
  859. {
  860. DWORD dwErr = ERROR_SUCCESS;
  861. DWORD dwOutFlags = 0;
  862. PWZC_CONTEXT pwzcCtxt = &g_wzcInternalCtxt.wzcContext;
  863. DbgPrint((TRC_TRACK, "[WzcContextQuery(%d)", dwInFlags));
  864. if (FALSE == g_wzcInternalCtxt.bValid)
  865. {
  866. dwErr = ERROR_ARENA_TRASHED;
  867. goto exit;
  868. }
  869. EnterCriticalSection(&g_wzcInternalCtxt.csContext);
  870. if (dwInFlags & WZC_CONTEXT_CTL_LOG)
  871. {
  872. pContext->dwFlags |= (DWORD)(pwzcCtxt->dwFlags & WZC_CTXT_LOGGING_ON);
  873. dwOutFlags |= WZC_CONTEXT_CTL_LOG;
  874. }
  875. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TR)
  876. {
  877. pContext->tmTr = pwzcCtxt->tmTr;
  878. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TR;
  879. }
  880. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TC)
  881. {
  882. pContext->tmTc = pwzcCtxt->tmTc;
  883. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TC;
  884. }
  885. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TP)
  886. {
  887. pContext->tmTp = pwzcCtxt->tmTp;
  888. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TP;
  889. }
  890. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TF)
  891. {
  892. pContext->tmTf = pwzcCtxt->tmTf;
  893. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TF;
  894. }
  895. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TD)
  896. {
  897. pContext->tmTd = pwzcCtxt->tmTd;
  898. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TD;
  899. }
  900. LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
  901. exit:
  902. if (pdwOutFlags != NULL)
  903. *pdwOutFlags = dwOutFlags;
  904. DbgPrint((TRC_TRACK, "WzcContextQuery(out: 0x%08x)]=%d", dwOutFlags, dwErr));
  905. return dwErr;
  906. }
  907. //-----------------------------------------------------------
  908. // WzcContextSet
  909. // Description: Sets specified params in the global context to the values
  910. // passed in by the client.
  911. // Parameters:
  912. // [in] dwInFlags - Bitmask of the WZC_CTL_* flags, indicates the
  913. // appropriate parameter.
  914. // [in] pContext - Should point to the user specified values
  915. // [out] pdwOutFlags - Indicates the values that were successfully set
  916. // Returns: win32 error code
  917. DWORD WzcContextSet(
  918. DWORD dwInFlags,
  919. PWZC_CONTEXT pContext,
  920. LPDWORD pdwOutFlags)
  921. {
  922. DWORD dwErr = ERROR_SUCCESS;
  923. DWORD dwOutFlags = 0;
  924. PWZC_CONTEXT pwzcCtxt = &g_wzcInternalCtxt.wzcContext;
  925. DbgPrint((TRC_TRACK, "[WzcContextSet(%d)", dwInFlags));
  926. if (FALSE == g_wzcInternalCtxt.bValid)
  927. {
  928. dwErr = ERROR_ARENA_TRASHED;
  929. goto exit;
  930. }
  931. EnterCriticalSection(&g_wzcInternalCtxt.csContext);
  932. //Set appropriate entries
  933. if (dwInFlags & WZC_CONTEXT_CTL_LOG)
  934. {
  935. if (pContext->dwFlags & WZC_CTXT_LOGGING_ON)
  936. pwzcCtxt->dwFlags |= WZC_CONTEXT_CTL_LOG;
  937. else
  938. pwzcCtxt->dwFlags &= ~WZC_CONTEXT_CTL_LOG;
  939. dwOutFlags |= WZC_CONTEXT_CTL_LOG;
  940. }
  941. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TR)
  942. {
  943. pwzcCtxt->tmTr = pContext->tmTr;
  944. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TR;
  945. }
  946. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TC)
  947. {
  948. pwzcCtxt->tmTc = pContext->tmTc;
  949. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TC;
  950. }
  951. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TP)
  952. {
  953. pwzcCtxt->tmTp = pContext->tmTp;
  954. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TP;
  955. }
  956. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TF)
  957. {
  958. pwzcCtxt->tmTf = pContext->tmTf;
  959. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TF;
  960. }
  961. if (dwInFlags & WZC_CONTEXT_CTL_TIMER_TD)
  962. {
  963. pwzcCtxt->tmTd = pContext->tmTd;
  964. dwOutFlags |= WZC_CONTEXT_CTL_TIMER_TD;
  965. }
  966. //Save into the registry
  967. dwErr = StoSaveWZCContext(NULL, &g_wzcInternalCtxt.wzcContext);
  968. DbgAssert((ERROR_SUCCESS == dwErr, "Error saving context to registry %d",dwErr));
  969. LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
  970. exit:
  971. if (pdwOutFlags != NULL)
  972. *pdwOutFlags = dwOutFlags;
  973. DbgPrint((TRC_TRACK, "WzcContextSet(out: 0x%08x)]=%d", dwOutFlags, dwErr));
  974. return dwErr;
  975. }