Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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