Add syscall.9 adapted from OpenBSD.
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / ndis_events.c
blobace041a463b537aebbdf2dfcce63b62fff430608
1 /*
2 * ndis_events - Receive NdisMIndicateStatus() events using WMI
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #define _WIN32_WINNT 0x0400
17 #include "includes.h"
19 #ifndef COBJMACROS
20 #define COBJMACROS
21 #endif /* COBJMACROS */
22 #include <wbemidl.h>
24 #include "common.h"
27 static int wmi_refcnt = 0;
28 static int wmi_first = 1;
30 struct ndis_events_data {
31 IWbemObjectSink sink;
32 IWbemObjectSinkVtbl sink_vtbl;
34 IWbemServices *pSvc;
35 IWbemLocator *pLoc;
37 HANDLE read_pipe, write_pipe, event_avail;
38 UINT ref;
39 int terminating;
40 char *ifname; /* {GUID..} */
41 WCHAR *adapter_desc;
44 enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
45 EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
47 static int ndis_events_get_adapter(struct ndis_events_data *events,
48 const char *ifname, const char *desc);
51 static int ndis_events_constructor(struct ndis_events_data *events)
53 events->ref = 1;
55 if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
56 wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
57 (int) GetLastError());
58 return -1;
60 events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
61 if (events->event_avail == NULL) {
62 wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
63 (int) GetLastError());
64 CloseHandle(events->read_pipe);
65 CloseHandle(events->write_pipe);
66 return -1;
69 return 0;
73 static void ndis_events_destructor(struct ndis_events_data *events)
75 CloseHandle(events->read_pipe);
76 CloseHandle(events->write_pipe);
77 CloseHandle(events->event_avail);
78 IWbemServices_Release(events->pSvc);
79 IWbemLocator_Release(events->pLoc);
80 if (--wmi_refcnt == 0)
81 CoUninitialize();
85 static HRESULT STDMETHODCALLTYPE
86 ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
88 *obj = NULL;
90 if (IsEqualIID(riid, &IID_IUnknown) ||
91 IsEqualIID(riid, &IID_IWbemObjectSink)) {
92 *obj = this;
93 IWbemObjectSink_AddRef(this);
94 return NOERROR;
97 return E_NOINTERFACE;
101 static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
103 struct ndis_events_data *events = (struct ndis_events_data *) this;
104 return ++events->ref;
108 static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
110 struct ndis_events_data *events = (struct ndis_events_data *) this;
112 if (--events->ref != 0)
113 return events->ref;
115 ndis_events_destructor(events);
116 wpa_printf(MSG_DEBUG, "ndis_events: terminated");
117 os_free(events->adapter_desc);
118 os_free(events->ifname);
119 os_free(events);
120 return 0;
124 static int ndis_events_send_event(struct ndis_events_data *events,
125 enum event_types type,
126 char *data, size_t data_len)
128 char buf[512], *pos, *end;
129 int _type;
130 DWORD written;
132 end = buf + sizeof(buf);
133 _type = (int) type;
134 os_memcpy(buf, &_type, sizeof(_type));
135 pos = buf + sizeof(_type);
137 if (data) {
138 if (2 + data_len > (size_t) (end - pos)) {
139 wpa_printf(MSG_DEBUG, "Not enough room for send_event "
140 "data (%d)", data_len);
141 return -1;
143 *pos++ = data_len >> 8;
144 *pos++ = data_len & 0xff;
145 os_memcpy(pos, data, data_len);
146 pos += data_len;
149 if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
150 SetEvent(events->event_avail);
151 return 0;
153 wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
154 return -1;
158 static void ndis_events_media_connect(struct ndis_events_data *events)
160 wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
161 ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
165 static void ndis_events_media_disconnect(struct ndis_events_data *events)
167 wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
168 ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
172 static void ndis_events_media_specific(struct ndis_events_data *events,
173 IWbemClassObject *pObj)
175 VARIANT vt;
176 HRESULT hr;
177 LONG lower, upper, k;
178 UCHAR ch;
179 char *data, *pos;
180 size_t data_len;
182 wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
184 /* This is the StatusBuffer from NdisMIndicateStatus() call */
185 hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
186 0, &vt, NULL, NULL);
187 if (FAILED(hr)) {
188 wpa_printf(MSG_DEBUG, "Could not get "
189 "NdisStatusMediaSpecificIndication from "
190 "the object?!");
191 return;
194 SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
195 SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
196 data_len = upper - lower + 1;
197 data = os_malloc(data_len);
198 if (data == NULL) {
199 wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
200 "data");
201 VariantClear(&vt);
202 return;
205 pos = data;
206 for (k = lower; k <= upper; k++) {
207 SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
208 *pos++ = ch;
210 wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", data, data_len);
212 VariantClear(&vt);
214 ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
216 os_free(data);
220 static void ndis_events_adapter_arrival(struct ndis_events_data *events)
222 wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
223 ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
227 static void ndis_events_adapter_removal(struct ndis_events_data *events)
229 wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
230 ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
234 static HRESULT STDMETHODCALLTYPE
235 ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
236 IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
238 struct ndis_events_data *events = (struct ndis_events_data *) this;
239 long i;
241 if (events->terminating) {
242 wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
243 "indication - terminating");
244 return WBEM_NO_ERROR;
246 /* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
247 lObjectCount); */
249 for (i = 0; i < lObjectCount; i++) {
250 IWbemClassObject *pObj = ppObjArray[i];
251 HRESULT hr;
252 VARIANT vtClass, vt;
254 hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
255 NULL);
256 if (FAILED(hr)) {
257 wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
258 "event.");
259 break;
261 /* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
263 hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
264 NULL);
265 if (FAILED(hr)) {
266 wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
267 "from event.");
268 VariantClear(&vtClass);
269 break;
272 if (wcscmp(vtClass.bstrVal,
273 L"MSNdis_NotifyAdapterArrival") == 0) {
274 wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
275 "update adapter description since it may "
276 "have changed with new adapter instance");
277 ndis_events_get_adapter(events, events->ifname, NULL);
280 if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
281 wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
282 "indication for foreign adapter: "
283 "InstanceName: '%S' __CLASS: '%S'",
284 vt.bstrVal, vtClass.bstrVal);
285 VariantClear(&vtClass);
286 VariantClear(&vt);
287 continue;
289 VariantClear(&vt);
291 if (wcscmp(vtClass.bstrVal,
292 L"MSNdis_StatusMediaSpecificIndication") == 0) {
293 ndis_events_media_specific(events, pObj);
294 } else if (wcscmp(vtClass.bstrVal,
295 L"MSNdis_StatusMediaConnect") == 0) {
296 ndis_events_media_connect(events);
297 } else if (wcscmp(vtClass.bstrVal,
298 L"MSNdis_StatusMediaDisconnect") == 0) {
299 ndis_events_media_disconnect(events);
300 } else if (wcscmp(vtClass.bstrVal,
301 L"MSNdis_NotifyAdapterArrival") == 0) {
302 ndis_events_adapter_arrival(events);
303 } else if (wcscmp(vtClass.bstrVal,
304 L"MSNdis_NotifyAdapterRemoval") == 0) {
305 ndis_events_adapter_removal(events);
306 } else {
307 wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
308 "'%S'", vtClass.bstrVal);
311 VariantClear(&vtClass);
314 return WBEM_NO_ERROR;
318 static HRESULT STDMETHODCALLTYPE
319 ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
320 BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
322 return WBEM_NO_ERROR;
326 static int notification_query(IWbemObjectSink *pDestSink,
327 IWbemServices *pSvc, const char *class_name)
329 HRESULT hr;
330 WCHAR query[256];
332 _snwprintf(query, 256,
333 L"SELECT * FROM %S", class_name);
334 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
335 hr = IWbemServices_ExecNotificationQueryAsync(pSvc, L"WQL", query, 0,
336 0, pDestSink);
337 if (FAILED(hr)) {
338 wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
339 "failed with hresult of 0x%x",
340 class_name, (int) hr);
341 return -1;
344 return 0;
348 static int register_async_notification(IWbemObjectSink *pDestSink,
349 IWbemServices *pSvc)
351 int i;
352 const char *class_list[] = {
353 "MSNdis_StatusMediaConnect",
354 "MSNdis_StatusMediaDisconnect",
355 "MSNdis_StatusMediaSpecificIndication",
356 "MSNdis_NotifyAdapterArrival",
357 "MSNdis_NotifyAdapterRemoval",
358 NULL
361 for (i = 0; class_list[i]; i++) {
362 if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
363 return -1;
366 return 0;
370 void ndis_events_deinit(struct ndis_events_data *events)
372 events->terminating = 1;
373 IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
374 IWbemObjectSink_Release(&events->sink);
376 * Rest of deinitialization is done in ndis_events_destructor() once
377 * all reference count drops to zero.
382 static int ndis_events_use_desc(struct ndis_events_data *events,
383 const char *desc)
385 char *tmp, *pos;
386 size_t len;
388 if (desc == NULL) {
389 if (events->adapter_desc == NULL)
390 return -1;
391 /* Continue using old description */
392 return 0;
395 tmp = os_strdup(desc);
396 if (tmp == NULL)
397 return -1;
399 pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
400 if (pos)
401 *pos = '\0';
403 len = os_strlen(tmp);
404 events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
405 if (events->adapter_desc == NULL) {
406 os_free(tmp);
407 return -1;
409 _snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
410 os_free(tmp);
411 return 0;
415 static int ndis_events_get_adapter(struct ndis_events_data *events,
416 const char *ifname, const char *desc)
418 HRESULT hr;
419 IWbemServices *pSvc;
420 #define MAX_QUERY_LEN 256
421 WCHAR query[MAX_QUERY_LEN];
422 IEnumWbemClassObject *pEnumerator;
423 IWbemClassObject *pObj;
424 ULONG uReturned;
425 VARIANT vt;
426 int len, pos;
429 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
430 * to have better probability of matching with InstanceName from
431 * MSNdis events. If this fails, use the provided description.
434 os_free(events->adapter_desc);
435 events->adapter_desc = NULL;
437 hr = IWbemLocator_ConnectServer(events->pLoc, L"ROOT\\CIMV2", NULL,
438 NULL, 0, 0, 0, 0, &pSvc);
439 if (FAILED(hr)) {
440 wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
441 "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
442 return ndis_events_use_desc(events, desc);
444 wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
446 _snwprintf(query, MAX_QUERY_LEN,
447 L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
448 L"WHERE SettingID='%S'", ifname);
449 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
451 hr = IWbemServices_ExecQuery(pSvc, L"WQL", query,
452 WBEM_FLAG_FORWARD_ONLY |
453 WBEM_FLAG_RETURN_IMMEDIATELY,
454 NULL, &pEnumerator);
455 if (!SUCCEEDED(hr)) {
456 wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
457 "GUID from Win32_NetworkAdapterConfiguration: "
458 "0x%x", (int) hr);
459 IWbemServices_Release(pSvc);
460 return ndis_events_use_desc(events, desc);
463 uReturned = 0;
464 hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
465 &pObj, &uReturned);
466 if (!SUCCEEDED(hr) || uReturned == 0) {
467 wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
468 "GUID from Win32_NetworkAdapterConfiguration: "
469 "0x%x", (int) hr);
470 IEnumWbemClassObject_Release(pEnumerator);
471 IWbemServices_Release(pSvc);
472 return ndis_events_use_desc(events, desc);
474 IEnumWbemClassObject_Release(pEnumerator);
476 VariantInit(&vt);
477 hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
478 if (!SUCCEEDED(hr)) {
479 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
480 "Win32_NetworkAdapterConfiguration: 0x%x",
481 (int) hr);
482 IWbemServices_Release(pSvc);
483 return ndis_events_use_desc(events, desc);
486 _snwprintf(query, MAX_QUERY_LEN,
487 L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
488 L"Index=%d",
489 vt.uintVal);
490 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
491 VariantClear(&vt);
492 IWbemClassObject_Release(pObj);
494 hr = IWbemServices_ExecQuery(pSvc, L"WQL", query,
495 WBEM_FLAG_FORWARD_ONLY |
496 WBEM_FLAG_RETURN_IMMEDIATELY,
497 NULL, &pEnumerator);
498 if (!SUCCEEDED(hr)) {
499 wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
500 "from Win32_NetworkAdapter: 0x%x", (int) hr);
501 IWbemServices_Release(pSvc);
502 return ndis_events_use_desc(events, desc);
505 uReturned = 0;
506 hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
507 &pObj, &uReturned);
508 if (!SUCCEEDED(hr) || uReturned == 0) {
509 wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
510 "from Win32_NetworkAdapter: 0x%x", (int) hr);
511 IEnumWbemClassObject_Release(pEnumerator);
512 IWbemServices_Release(pSvc);
513 return ndis_events_use_desc(events, desc);
515 IEnumWbemClassObject_Release(pEnumerator);
517 hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
518 if (!SUCCEEDED(hr)) {
519 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
520 "Win32_NetworkAdapter: 0x%x", (int) hr);
521 IWbemClassObject_Release(pObj);
522 IWbemServices_Release(pSvc);
523 return ndis_events_use_desc(events, desc);
526 wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
527 vt.bstrVal);
528 events->adapter_desc = _wcsdup(vt.bstrVal);
529 VariantClear(&vt);
532 * Try to get even better candidate for matching with InstanceName
533 * from Win32_PnPEntity. This is needed at least for some USB cards
534 * that can change the InstanceName whenever being unplugged and
535 * plugged again.
538 hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
539 if (!SUCCEEDED(hr)) {
540 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
541 "from Win32_NetworkAdapter: 0x%x", (int) hr);
542 IWbemClassObject_Release(pObj);
543 IWbemServices_Release(pSvc);
544 if (events->adapter_desc == NULL)
545 return ndis_events_use_desc(events, desc);
546 return 0; /* use Win32_NetworkAdapter::Name */
549 wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
550 "'%S'", vt.bstrVal);
552 len = _snwprintf(query, MAX_QUERY_LEN,
553 L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
554 if (len < 0 || len >= MAX_QUERY_LEN - 1) {
555 VariantClear(&vt);
556 IWbemClassObject_Release(pObj);
557 IWbemServices_Release(pSvc);
558 if (events->adapter_desc == NULL)
559 return ndis_events_use_desc(events, desc);
560 return 0; /* use Win32_NetworkAdapter::Name */
563 /* Escape \ as \\ */
564 for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
565 if (vt.bstrVal[pos] == '\\') {
566 if (len >= MAX_QUERY_LEN - 3)
567 break;
568 query[len++] = '\\';
570 query[len++] = vt.bstrVal[pos];
572 query[len++] = L'\'';
573 query[len] = L'\0';
574 VariantClear(&vt);
575 IWbemClassObject_Release(pObj);
576 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
578 hr = IWbemServices_ExecQuery(pSvc, L"WQL", query,
579 WBEM_FLAG_FORWARD_ONLY |
580 WBEM_FLAG_RETURN_IMMEDIATELY,
581 NULL, &pEnumerator);
582 if (!SUCCEEDED(hr)) {
583 wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
584 "Name from Win32_PnPEntity: 0x%x", (int) hr);
585 IWbemServices_Release(pSvc);
586 if (events->adapter_desc == NULL)
587 return ndis_events_use_desc(events, desc);
588 return 0; /* use Win32_NetworkAdapter::Name */
591 uReturned = 0;
592 hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
593 &pObj, &uReturned);
594 if (!SUCCEEDED(hr) || uReturned == 0) {
595 wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
596 "from Win32_PnPEntity: 0x%x", (int) hr);
597 IEnumWbemClassObject_Release(pEnumerator);
598 IWbemServices_Release(pSvc);
599 if (events->adapter_desc == NULL)
600 return ndis_events_use_desc(events, desc);
601 return 0; /* use Win32_NetworkAdapter::Name */
603 IEnumWbemClassObject_Release(pEnumerator);
605 hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
606 if (!SUCCEEDED(hr)) {
607 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
608 "Win32_PnPEntity: 0x%x", (int) hr);
609 IWbemClassObject_Release(pObj);
610 IWbemServices_Release(pSvc);
611 if (events->adapter_desc == NULL)
612 return ndis_events_use_desc(events, desc);
613 return 0; /* use Win32_NetworkAdapter::Name */
616 wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
617 vt.bstrVal);
618 os_free(events->adapter_desc);
619 events->adapter_desc = _wcsdup(vt.bstrVal);
620 VariantClear(&vt);
622 IWbemClassObject_Release(pObj);
624 IWbemServices_Release(pSvc);
626 if (events->adapter_desc == NULL)
627 return ndis_events_use_desc(events, desc);
629 return 0;
633 struct ndis_events_data *
634 ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
635 const char *ifname, const char *desc)
637 HRESULT hr;
638 IWbemObjectSink *pSink;
639 struct ndis_events_data *events;
641 events = os_zalloc(sizeof(*events));
642 if (events == NULL) {
643 wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
644 return NULL;
646 events->ifname = os_strdup(ifname);
647 if (events->ifname == NULL) {
648 os_free(events);
649 return NULL;
652 if (wmi_refcnt++ == 0) {
653 hr = CoInitializeEx(0, COINIT_MULTITHREADED);
654 if (FAILED(hr)) {
655 wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
656 "returned 0x%x", (int) hr);
657 os_free(events);
658 return NULL;
662 if (wmi_first) {
663 /* CoInitializeSecurity() must be called once and only once
664 * per process, so let's use wmi_first flag to protect against
665 * multiple calls. */
666 wmi_first = 0;
668 hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
669 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
670 RPC_C_IMP_LEVEL_IMPERSONATE,
671 NULL, EOAC_SECURE_REFS, NULL);
672 if (FAILED(hr)) {
673 wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
674 "- returned 0x%x", (int) hr);
675 os_free(events);
676 return NULL;
680 hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
681 &IID_IWbemLocator, (LPVOID *) &events->pLoc);
682 if (FAILED(hr)) {
683 wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
684 "0x%x", (int) hr);
685 CoUninitialize();
686 os_free(events);
687 return NULL;
690 if (ndis_events_get_adapter(events, ifname, desc) < 0) {
691 CoUninitialize();
692 os_free(events);
693 return NULL;
695 wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
696 events->adapter_desc);
698 hr = IWbemLocator_ConnectServer(events->pLoc, L"ROOT\\WMI", NULL, NULL,
699 0, 0, 0, 0, &events->pSvc);
700 if (FAILED(hr)) {
701 wpa_printf(MSG_ERROR, "Could not connect to server - error "
702 "0x%x", (int) hr);
703 CoUninitialize();
704 os_free(events->adapter_desc);
705 os_free(events);
706 return NULL;
708 wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
710 ndis_events_constructor(events);
711 pSink = &events->sink;
712 pSink->lpVtbl = &events->sink_vtbl;
713 events->sink_vtbl.QueryInterface = ndis_events_query_interface;
714 events->sink_vtbl.AddRef = ndis_events_add_ref;
715 events->sink_vtbl.Release = ndis_events_release;
716 events->sink_vtbl.Indicate = ndis_events_indicate;
717 events->sink_vtbl.SetStatus = ndis_events_set_status;
719 if (register_async_notification(pSink, events->pSvc) < 0) {
720 wpa_printf(MSG_DEBUG, "Failed to register async "
721 "notifications");
722 ndis_events_destructor(events);
723 os_free(events->adapter_desc);
724 os_free(events);
725 return NULL;
728 *read_pipe = events->read_pipe;
729 *event_avail = events->event_avail;
731 return events;