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.

674 lines
20 KiB

  1. /*++
  2. Copyright(c) 2001 Microsoft Corporation
  3. Module Name:
  4. nlbwmi.c
  5. Abstract:
  6. Network Load Balancing (NLB)
  7. Driver - WMI event generation
  8. Author:
  9. karthicn
  10. --*/
  11. #include "wlbsparm.h"
  12. #include <wmistr.h>
  13. #include <wmiguid.h>
  14. #include <wmilib.h>
  15. #include "main.h"
  16. #include "univ.h"
  17. #include "nlbwmimof.h"
  18. #include "nlbwmi.h"
  19. #include "nlbwmi.tmh"
  20. //
  21. // MOF Resource Name
  22. //
  23. WCHAR NLBMofResourceName[] = L"NLBMofResource";
  24. //
  25. // Base Instance Name
  26. //
  27. WCHAR NLBBaseInstanceName[] = L"NLB_Block";
  28. // NLB Event Guids - the MicrosoftNLB* variables are autogenerated (in nlbwmimof.h)
  29. GUID NodeControlEventGuid = MicrosoftNLB_NodeControlEventGuid;
  30. GUID PortRuleControlEventGuid = MicrosoftNLB_PortControlEventGuid;
  31. GUID ConvergingEventGuid = MicrosoftNLB_ConvergingEventGuid;
  32. GUID ConvergedEventGuid = MicrosoftNLB_ConvergedEventGuid;
  33. GUID StartupEventGuid = MicrosoftNLB_StartupEventGuid;
  34. GUID ShutdownEventGuid = MicrosoftNLB_ShutdownEventGuid;
  35. // NLB Event Guid Registration Information
  36. WMIGUIDREGINFO NlbWmiGuidList[] =
  37. {
  38. {
  39. &NodeControlEventGuid,
  40. 1,
  41. WMIREG_FLAG_EVENT_ONLY_GUID
  42. },
  43. {
  44. &PortRuleControlEventGuid,
  45. 1,
  46. WMIREG_FLAG_EVENT_ONLY_GUID
  47. },
  48. {
  49. &ConvergingEventGuid,
  50. 1,
  51. WMIREG_FLAG_EVENT_ONLY_GUID
  52. },
  53. {
  54. &ConvergedEventGuid,
  55. 1,
  56. WMIREG_FLAG_EVENT_ONLY_GUID
  57. },
  58. {
  59. &StartupEventGuid,
  60. 1,
  61. WMIREG_FLAG_EVENT_ONLY_GUID
  62. },
  63. {
  64. &ShutdownEventGuid,
  65. 1,
  66. WMIREG_FLAG_EVENT_ONLY_GUID
  67. },
  68. // Add new event info here
  69. };
  70. #define NlbWmiGuidCount (ULONG)(sizeof(NlbWmiGuidList)/sizeof(WMIGUIDREGINFO))
  71. // NLB Event Information
  72. NLB_WMI_EVENT NlbWmiEvents[] =
  73. {
  74. {
  75. &NodeControlEventGuid,
  76. FALSE
  77. },
  78. {
  79. &PortRuleControlEventGuid,
  80. FALSE
  81. },
  82. {
  83. &ConvergingEventGuid,
  84. FALSE
  85. },
  86. {
  87. &ConvergedEventGuid,
  88. FALSE
  89. },
  90. {
  91. &StartupEventGuid,
  92. FALSE
  93. },
  94. {
  95. &ShutdownEventGuid,
  96. FALSE
  97. },
  98. // Add new event info here as well
  99. };
  100. //
  101. // Prototype declarations
  102. //
  103. NTSTATUS
  104. NlbWmi_Query_RegInfo(
  105. IN PDEVICE_OBJECT DeviceObject,
  106. OUT ULONG *RegFlags,
  107. OUT PUNICODE_STRING InstanceName,
  108. OUT PUNICODE_STRING *RegistryPath,
  109. OUT PUNICODE_STRING MofResourceName,
  110. OUT PDEVICE_OBJECT *Pdo
  111. );
  112. NTSTATUS
  113. NlbWmi_Query_DataBlock(
  114. IN PDEVICE_OBJECT DeviceObject,
  115. IN PIRP Irp,
  116. IN ULONG GuidIndex,
  117. IN ULONG InstanceIndex,
  118. IN ULONG InstanceCount,
  119. IN OUT PULONG InstanceLengthArray,
  120. IN ULONG BufferAvail,
  121. OUT PUCHAR Buffer
  122. );
  123. NTSTATUS
  124. NlbWmi_Function_Control(
  125. IN PDEVICE_OBJECT DeviceObject,
  126. IN PIRP Irp,
  127. IN ULONG GuidIndex,
  128. IN WMIENABLEDISABLECONTROL Function,
  129. IN BOOLEAN Enable
  130. );
  131. //
  132. // WMI Helper Library context
  133. //
  134. WMILIB_CONTEXT NlbWmiLibContext =
  135. {
  136. NlbWmiGuidCount,
  137. NlbWmiGuidList,
  138. NlbWmi_Query_RegInfo,
  139. NlbWmi_Query_DataBlock,
  140. NULL,
  141. NULL,
  142. NULL,
  143. NlbWmi_Function_Control
  144. };
  145. /*
  146. Name : NlbWmi_Initialize
  147. Description : This function initializes the data structures and registers the supported guids with the wmi system
  148. Arguments : None
  149. Return Value: status
  150. */
  151. NTSTATUS NlbWmi_Initialize()
  152. {
  153. ULONG idx;
  154. NTSTATUS status;
  155. TRACE_VERB("->%!FUNC!");
  156. /* Disable event generation for all events */
  157. for (idx = 0 ; idx < NlbWmiGuidCount ; idx++)
  158. {
  159. NlbWmiEvents[idx].Enable = FALSE;
  160. }
  161. if (univ_device_object != NULL)
  162. {
  163. /* Register with WMI */
  164. status = IoWMIRegistrationControl(univ_device_object, WMIREG_ACTION_REGISTER);
  165. if (status != STATUS_SUCCESS)
  166. {
  167. TRACE_CRIT("%!FUNC! IoWMIRegistrationControl(DeviceObject : %p, REGISTER) returned Error : 0x%x",univ_device_object, status);
  168. }
  169. }
  170. else // Device Object is NULL
  171. {
  172. status = STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
  173. TRACE_CRIT("%!FUNC! Device Object is NULL, Could not call IoWMIRegistrationControl() to register with WMI");
  174. }
  175. TRACE_VERB("<-%!FUNC! return : 0x%x", status);
  176. return status;
  177. }
  178. /*
  179. Name : NlbWmi_Shutdown
  180. Description : This function de-registers with the wmi system
  181. Arguments : None
  182. Return Value: void
  183. */
  184. VOID NlbWmi_Shutdown()
  185. {
  186. NTSTATUS ntStatus;
  187. TRACE_VERB("->%!FUNC!");
  188. if (univ_device_object != NULL)
  189. {
  190. /* DeRegister with WMI */
  191. ntStatus = IoWMIRegistrationControl(univ_device_object, WMIREG_ACTION_DEREGISTER);
  192. if (ntStatus != STATUS_SUCCESS)
  193. {
  194. TRACE_CRIT("%!FUNC! IoWMIRegistrationControl(DeviceObject : %p, DEREGISTER) returned Error : 0x%x",univ_device_object, ntStatus);
  195. }
  196. }
  197. else
  198. {
  199. TRACE_CRIT("%!FUNC! Device Object is NULL, Could not call IoWMIRegistrationControl() to deregister with WMI");
  200. }
  201. TRACE_VERB("<-%!FUNC!");
  202. return;
  203. }
  204. /*
  205. Name : NlbWmi_System_Control
  206. Description : This function is responsible for handling the IRP_MJ_SYSTEM_CONTROL irps. It uses the wmi helper
  207. library function to crack the irp to have the appropriate call back functions called
  208. Arguments : Device Object, Irp
  209. Return Value: status
  210. */
  211. NTSTATUS NlbWmi_System_Control (PVOID DeviceObject, PIRP pIrp)
  212. {
  213. NTSTATUS status;
  214. SYSCTL_IRP_DISPOSITION disposition;
  215. TRACE_VERB("->%!FUNC!");
  216. //
  217. // Call Wmilib helper function to crack the irp. If this is a wmi irp
  218. // that is targetted for the supported guids, then WmiSystemControl will callback
  219. // at the appropriate callback routine.
  220. //
  221. status = WmiSystemControl(
  222. &NlbWmiLibContext,
  223. DeviceObject,
  224. pIrp,
  225. &disposition
  226. );
  227. switch(disposition)
  228. {
  229. case IrpProcessed:
  230. //
  231. // This irp has been processed and may be completed or pending.
  232. //
  233. break;
  234. case IrpNotCompleted:
  235. //
  236. // This irp has not been completed, but has been fully processed.
  237. // so we need to complete it
  238. // (Must be a IRP_MN_REG_INFO)
  239. //
  240. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  241. break;
  242. default:
  243. case IrpNotWmi:
  244. case IrpForward:
  245. {
  246. TRACE_CRIT("%!FUNC! WmiSystemControl returned disposition : 0x%x, Unexpected", disposition);
  247. pIrp->IoStatus.Status = status;
  248. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  249. break;
  250. }
  251. }
  252. if( !NT_SUCCESS( status ))
  253. {
  254. TRACE_CRIT("%!FUNC! WmiSystemControl returned error : 0x%x", status);
  255. }
  256. TRACE_VERB("<-%!FUNC! return : 0x%x", status);
  257. return status;
  258. } // NlbWmi_System_Control
  259. /*
  260. Name : NlbWmi_Query_RegInfo
  261. Description : This function is called back by the Wmi helper library to process a IRP_MN_REG_INFO irp. It
  262. registers the Instance name, registry path & Mof resource name with wmi. For more information
  263. about this function, please look in the DDK under "WMI library Callback Routines"->"DpWmiQueryReginfo"
  264. Return Value: status
  265. */
  266. NTSTATUS
  267. NlbWmi_Query_RegInfo(
  268. IN PDEVICE_OBJECT DeviceObject,
  269. OUT ULONG *RegFlags,
  270. OUT PUNICODE_STRING InstanceName,
  271. OUT PUNICODE_STRING *RegistryPath,
  272. OUT PUNICODE_STRING MofResourceName,
  273. OUT PDEVICE_OBJECT *Pdo
  274. )
  275. {
  276. PAGED_CODE();
  277. TRACE_VERB("->%!FUNC!");
  278. //
  279. // Tell WMI to generate instance names off of a static base name
  280. //
  281. *RegFlags = WMIREG_FLAG_INSTANCE_BASENAME;
  282. //
  283. // Set our base instance name. WmiLib will call ExFreePool on the buffer
  284. // of the string, so we need to allocate it from paged pool.
  285. //
  286. InstanceName->Length = wcslen( NLBBaseInstanceName ) * sizeof( WCHAR );
  287. InstanceName->MaximumLength = InstanceName->Length + sizeof( UNICODE_NULL );
  288. InstanceName->Buffer = ExAllocatePoolWithTag(
  289. PagedPool,
  290. InstanceName->MaximumLength,
  291. UNIV_POOL_TAG
  292. );
  293. if( NULL != InstanceName->Buffer )
  294. {
  295. RtlCopyMemory(
  296. InstanceName->Buffer,
  297. NLBBaseInstanceName,
  298. InstanceName->Length
  299. );
  300. InstanceName->Buffer[InstanceName->Length / sizeof(WCHAR)] = UNICODE_NULL;
  301. }
  302. else
  303. {
  304. TRACE_CRIT("%!FUNC! Error allocating memory");
  305. TRACE_VERB("<-%!FUNC! return status = STATUS_INSUFFICIENT_RESOURCES");
  306. return STATUS_INSUFFICIENT_RESOURCES;
  307. }
  308. //
  309. // Return the registry path for this driver. This is required so WMI
  310. // can find your driver image and can attribute any eventlog messages to
  311. // your driver.
  312. //
  313. *RegistryPath = &DriverEntryRegistryPath;
  314. //
  315. // Return the name specified in the .rc file of the resource which
  316. // contains the binary mof data.
  317. //
  318. RtlInitUnicodeString(MofResourceName, NLBMofResourceName);
  319. TRACE_VERB("<-%!FUNC! return=0x%x", STATUS_SUCCESS);
  320. return STATUS_SUCCESS;
  321. } // NlbWmi_Query_RegInfo
  322. /*
  323. Name : NlbWmi_Query_DataBlock
  324. Description : This function is called back by the Wmi helper library to process IRP_MN_QUERY_ALL_DATA
  325. & IRP_MN_QUERY_SINGLE_INSTANCE irps. We DO NOT SUPPORT these irps. However, this is a
  326. required callback and hence we implement it. We DO NOT EXPECT THIS FUNCTION TO BE CALLED.
  327. For more information about this function, please look in the DDK under
  328. "WMI library Callback Routines"->"DpWmiQueryDataBlock"
  329. Return Value: status
  330. */
  331. NTSTATUS
  332. NlbWmi_Query_DataBlock(
  333. IN PDEVICE_OBJECT DeviceObject,
  334. IN PIRP Irp,
  335. IN ULONG GuidIndex,
  336. IN ULONG InstanceIndex,
  337. IN ULONG InstanceCount,
  338. IN OUT PULONG InstanceLengthArray,
  339. IN ULONG BufferAvail,
  340. OUT PUCHAR Buffer
  341. )
  342. {
  343. NTSTATUS status;
  344. PAGED_CODE();
  345. TRACE_VERB("->%!FUNC!");
  346. status = WmiCompleteRequest(
  347. DeviceObject,
  348. Irp,
  349. STATUS_WMI_GUID_NOT_FOUND,
  350. 0,
  351. IO_NO_INCREMENT
  352. );
  353. TRACE_VERB("<-%!FUNC! return=0x%x", status);
  354. return status;
  355. } // NlbWmi_Query_DataBlock
  356. /*
  357. Name : NlbWmi_Function_Control
  358. Description : This function is called back by the Wmi helper library to process IRP_MN_ENABLE_EVENTS,
  359. IRP_MN_DISABLE_EVENTS, IRP_MN_ENABLE_COLLECTION & IRP_MN_DISABLE_COLLECTION irps. We only
  360. support IRP_MN_ENABLE_EVENTS & IRP_MN_DISABLE_EVENTS irps. The function enables/disables
  361. events generation. For more information about this function, please look in the DDK under
  362. "WMI library Callback Routines"->"DpWmiQueryReginfo"
  363. Return Value: status
  364. */
  365. NTSTATUS
  366. NlbWmi_Function_Control(
  367. IN PDEVICE_OBJECT DeviceObject,
  368. IN PIRP Irp,
  369. IN ULONG GuidIndex,
  370. IN WMIENABLEDISABLECONTROL Function,
  371. IN BOOLEAN Enable
  372. )
  373. {
  374. NTSTATUS status = STATUS_SUCCESS;
  375. PAGED_CODE();
  376. TRACE_VERB("->%!FUNC! %ls Event Index : %d", Enable ? L"ENABLE" : L"DISABLE", GuidIndex);
  377. if( WmiEventControl == Function )
  378. {
  379. // Verify that the guid index is in the range 0 - (NlbWmiGuidCount - 1)
  380. // Also, verify that the guid has not been flagged as removed. Although
  381. // we never flag a guid as being removed, do this check as part of
  382. // following "best practices".
  383. if( (GuidIndex < NlbWmiGuidCount)
  384. && !(NlbWmiGuidList[GuidIndex].Flags & WMIREG_FLAG_REMOVE_GUID))
  385. {
  386. NlbWmiEvents[GuidIndex].Enable = Enable;
  387. }
  388. else
  389. {
  390. //
  391. // Invalid guid index.
  392. //
  393. status = STATUS_WMI_GUID_NOT_FOUND;
  394. TRACE_CRIT("%!FUNC! Invalid WMI guid or guid flagged as removed, guid index: %d", GuidIndex);
  395. }
  396. }
  397. else
  398. {
  399. //
  400. // We currently don't have any (expensive) data blocks
  401. //
  402. status = STATUS_INVALID_DEVICE_REQUEST;
  403. TRACE_CRIT("%!FUNC! Invalid Device Request");
  404. }
  405. status = WmiCompleteRequest(
  406. DeviceObject,
  407. Irp,
  408. status,
  409. 0,
  410. IO_NO_INCREMENT
  411. );
  412. TRACE_VERB("<-%!FUNC! return status = 0x%x", status);
  413. return status;
  414. } // NlbWmi_Function_Control
  415. /*
  416. Name : NlbWmi_Fire_Event
  417. Description : This function fires wmi events. It allocates memory, fills it in with the
  418. incoming event data and calls WmiFireEvent to fire the event.
  419. Arguments : Event Id, Event Data (statically allocated)
  420. Return Value: status
  421. */
  422. NTSTATUS NlbWmi_Fire_Event(NlbWmiEventId EventId, PVOID pvInEventData, ULONG ulInEventDataSize)
  423. {
  424. NTSTATUS status;
  425. PVOID pvOutEventData;
  426. TRACE_VERB("->%!FUNC! Event : %d", EventId);
  427. if (ulInEventDataSize > 0)
  428. {
  429. pvOutEventData = ExAllocatePoolWithTag(NonPagedPool, ulInEventDataSize, UNIV_POOL_TAG);
  430. if (pvOutEventData == NULL)
  431. {
  432. TRACE_CRIT("%!FUNC! Error allocating memory");
  433. TRACE_VERB("<-%!FUNC! return status = STATUS_INSUFFICIENT_RESOURCES");
  434. return STATUS_INSUFFICIENT_RESOURCES;
  435. }
  436. RtlCopyMemory(pvOutEventData, pvInEventData, ulInEventDataSize);
  437. }
  438. else
  439. {
  440. pvOutEventData = NULL;
  441. }
  442. status = WmiFireEvent(univ_device_object, NlbWmiEvents[EventId].pGuid, 0, ulInEventDataSize, pvOutEventData);
  443. if( !NT_SUCCESS( status ))
  444. {
  445. TRACE_CRIT("%!FUNC! WmiFireEvent returned error : 0x%x", status);
  446. }
  447. TRACE_VERB("<-%!FUNC! return status = 0x%x", status);
  448. return status;
  449. } // NlbWmi_Fire_Event
  450. // This macro fills in the common properties(Adapter Guid, IP Address, Host priority) of all events
  451. #define FillCommonProperties() \
  452. { \
  453. Event.AdapterGuid[0] = sizeof(Event.AdapterGuid) - sizeof(Event.AdapterGuid[0]); \
  454. wcsncpy(&(Event.AdapterGuid[1]), univ_adapters[ctxtp->adapter_id].device_name + 8, Event.AdapterGuid[0]/sizeof(WCHAR)); \
  455. Event.ClusterIPAddress[0] = sizeof(Event.ClusterIPAddress) - sizeof(Event.ClusterIPAddress[0]); \
  456. wcsncpy(&(Event.ClusterIPAddress[1]), ctxtp->params.cl_ip_addr, Event.ClusterIPAddress[0]/sizeof(WCHAR)); \
  457. Event.HostPriority = ctxtp->params.host_priority; \
  458. }
  459. /*
  460. Name : NlbWmi_Fire_NodeControlEvent
  461. Description : This function fires Node Control events. It extracts the common event properties
  462. (out of the given pointer to the MAIN_CTXT structure) and fills in a local
  463. structure. It also fills in Node Control Event specific fields from the arguments
  464. passed to it. It then fires the actual event by calling NlbWmi_Fire_Event.
  465. Arguments : Pointer to MAIN_CTXT, NodeControlEventId
  466. Return Value: void
  467. */
  468. void NlbWmi_Fire_NodeControlEvent(PMAIN_CTXT ctxtp, NodeControlEventId Id)
  469. {
  470. MicrosoftNLB_NodeControlEvent Event;
  471. TRACE_VERB("->%!FUNC! Event : %d", Id);
  472. NdisZeroMemory(&Event, MicrosoftNLB_NodeControlEvent_SIZE);
  473. // Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
  474. FillCommonProperties()
  475. // Fill event specific properties
  476. Event.Id = Id;
  477. // Fire the event
  478. NlbWmi_Fire_Event(NodeControlEvent, &Event, MicrosoftNLB_NodeControlEvent_SIZE);
  479. TRACE_VERB("<-%!FUNC!");
  480. return;
  481. }
  482. /*
  483. Name : NlbWmi_Fire_PortControlEvent
  484. Description : This function fires Port Control events. It extracts the common event properties
  485. (out of the given pointer to the MAIN_CTXT structure) and fills in a local
  486. structure. It also fills in Port Control Event specific fields (id, vip, port) from the arguments
  487. passed to it. It then fires the actual event by calling NlbWmi_Fire_Event.
  488. Arguments : Pointer to MAIN_CTXT, PortControlEventId, Vip, Port
  489. Return Value: void
  490. */
  491. void NlbWmi_Fire_PortControlEvent(PMAIN_CTXT ctxtp, PortControlEventId Id, WCHAR *pwcVip, ULONG ulPort)
  492. {
  493. MicrosoftNLB_PortControlEvent Event;
  494. TRACE_VERB("->%!FUNC! Event : %d, Vip : %ls, Start Port : %d", Id, pwcVip, ulPort);
  495. NdisZeroMemory(&Event, MicrosoftNLB_PortControlEvent_SIZE);
  496. // Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
  497. FillCommonProperties()
  498. // Fill event specific properties
  499. Event.Id = Id;
  500. Event.VirtualIPAddress[0] = sizeof(Event.VirtualIPAddress) - sizeof(Event.VirtualIPAddress[0]);
  501. wcsncpy(&(Event.VirtualIPAddress[1]), pwcVip, Event.VirtualIPAddress[0]/sizeof(WCHAR));
  502. Event.Port = ulPort;
  503. // Fire the event
  504. NlbWmi_Fire_Event(PortRuleControlEvent, &Event, MicrosoftNLB_PortControlEvent_SIZE);
  505. TRACE_VERB("<-%!FUNC!");
  506. return;
  507. }
  508. /*
  509. Name : NlbWmi_Fire_ConvergingEvent
  510. Description : This function fires Converging events. It extracts the common event properties
  511. (out of the given pointer to the MAIN_CTXT structure) and fills in a local
  512. structure. It also fills in Converging Event specific fields from the arguments
  513. passed to it. It then fires the actual event by calling NlbWmi_Fire_Event.
  514. Arguments : Pointer to MAIN_CTXT, NodeControlEventId, Initiator DIP, Initiator Host Priority
  515. Return Value: void
  516. */
  517. void NlbWmi_Fire_ConvergingEvent(
  518. PMAIN_CTXT ctxtp,
  519. ConvergingEventId Cause,
  520. WCHAR *pwcInitiatorDip,
  521. ULONG ulInitiatorHostPriority)
  522. {
  523. MicrosoftNLB_ConvergingEvent Event;
  524. TRACE_VERB("->%!FUNC! Cause : %d, Initiator DIP : %ls, Initiator Host Priority : %d", Cause, pwcInitiatorDip, ulInitiatorHostPriority);
  525. NdisZeroMemory(&Event, MicrosoftNLB_ConvergingEvent_SIZE);
  526. // Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
  527. FillCommonProperties()
  528. // Fill event specific properties
  529. Event.Cause = Cause;
  530. Event.InitiatorDedicatedIP[0] = sizeof(Event.InitiatorDedicatedIP) - sizeof(Event.InitiatorDedicatedIP[0]);
  531. wcsncpy(&(Event.InitiatorDedicatedIP[1]), pwcInitiatorDip, Event.InitiatorDedicatedIP[0]/sizeof(WCHAR));
  532. Event.InitiatorHostPriority = ulInitiatorHostPriority;
  533. // Fire the event
  534. NlbWmi_Fire_Event(ConvergingEvent, &Event, MicrosoftNLB_ConvergingEvent_SIZE);
  535. TRACE_VERB("<-%!FUNC!");
  536. return;
  537. }
  538. /*
  539. Name : NlbWmi_Fire_ConvergedEvent
  540. Description : This function fires Converged events. It extracts the common event properties
  541. (out of the given pointer to the MAIN_CTXT structure) and fills in a local
  542. structure. It also fills in Converged Event specific fields from the arguments
  543. passed to it. It then fires the actual event by calling NlbWmi_Fire_Event.
  544. Arguments : Pointer to MAIN_CTXT, HostMap
  545. Return Value: void
  546. */
  547. void NlbWmi_Fire_ConvergedEvent(PMAIN_CTXT ctxtp, ULONG ulHostMap)
  548. {
  549. MicrosoftNLB_ConvergedEvent Event;
  550. TRACE_VERB("->%!FUNC! Host Map : %d", ulHostMap);
  551. NdisZeroMemory(&Event, MicrosoftNLB_ConvergedEvent_SIZE);
  552. // Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
  553. FillCommonProperties()
  554. // Fill event specific properties
  555. Event.HostMap = ulHostMap;
  556. // Fire the event
  557. NlbWmi_Fire_Event(ConvergedEvent, &Event, MicrosoftNLB_ConvergedEvent_SIZE);
  558. TRACE_VERB("<-%!FUNC!");
  559. return;
  560. }