18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ndis_events - Receive NdisMIndicateStatus() events using WMI
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define _WIN32_WINNT    0x0400
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef COBJMACROS
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define COBJMACROS
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* COBJMACROS */
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <wbemidl.h>
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wmi_refcnt = 0;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wmi_first = 1;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ndis_events_data {
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemObjectSink sink;
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemObjectSinkVtbl sink_vtbl;
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices *pSvc;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemLocator *pLoc;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HANDLE read_pipe, write_pipe, event_avail;
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	UINT ref;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int terminating;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *ifname; /* {GUID..} */
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WCHAR *adapter_desc;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define BstrFree(x) if (x) SysFreeString(x)
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * BSTRs */
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtHRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BSTR bsQueryLanguage, bsQuery;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsQueryLanguage = BstrAlloc(strQueryLanguage);
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsQuery = BstrAlloc(strQuery);
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     pCtx, ppEnum);
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsQueryLanguage);
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsQuery);
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hr;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtHRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BSTR bsQueryLanguage, bsQuery;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsQueryLanguage = BstrAlloc(strQueryLanguage);
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsQuery = BstrAlloc(strQuery);
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						      bsQuery, lFlags, pCtx,
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						      pResponseHandler);
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsQueryLanguage);
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsQuery);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hr;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtHRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsNetworkResource = BstrAlloc(strNetworkResource);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsUser = BstrAlloc(strUser);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsPassword = BstrAlloc(strPassword);
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsLocale = BstrAlloc(strLocale);
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bsAuthority = BstrAlloc(strAuthority);
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					bsPassword, bsLocale, lSecurityFlags,
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					bsAuthority, pCtx, ppNamespace);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsNetworkResource);
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsUser);
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsPassword);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsLocale);
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BstrFree(bsAuthority);
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return hr;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ndis_events_get_adapter(struct ndis_events_data *events,
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const char *ifname, const char *desc);
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ndis_events_constructor(struct ndis_events_data *events)
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->ref = 1;
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) GetLastError());
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (events->event_avail == NULL) {
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) GetLastError());
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(events->read_pipe);
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CloseHandle(events->write_pipe);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ndis_events_destructor(struct ndis_events_data *events)
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CloseHandle(events->read_pipe);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CloseHandle(events->write_pipe);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CloseHandle(events->event_avail);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices_Release(events->pSvc);
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemLocator_Release(events->pLoc);
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (--wmi_refcnt == 0)
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CoUninitialize();
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic HRESULT STDMETHODCALLTYPE
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*obj = NULL;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (IsEqualIID(riid, &IID_IUnknown) ||
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    IsEqualIID(riid, &IID_IWbemObjectSink)) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*obj = this;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemObjectSink_AddRef(this);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NOERROR;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return E_NOINTERFACE;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ndis_events_data *events = (struct ndis_events_data *) this;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ++events->ref;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ndis_events_data *events = (struct ndis_events_data *) this;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (--events->ref != 0)
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return events->ref;
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_destructor(events);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: terminated");
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(events->adapter_desc);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(events->ifname);
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(events);
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ndis_events_send_event(struct ndis_events_data *events,
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  enum event_types type,
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  char *data, size_t data_len)
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[512], *pos, *end;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int _type;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	DWORD written;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = buf + sizeof(buf);
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_type = (int) type;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf, &_type, sizeof(_type));
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf + sizeof(_type);
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data) {
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (2 + data_len > (size_t) (end - pos)) {
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Not enough room for send_event "
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "data (%d)", data_len);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pos++ = data_len >> 8;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pos++ = data_len & 0xff;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, data, data_len);
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += data_len;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SetEvent(events->event_avail);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ndis_events_media_connect(struct ndis_events_data *events)
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ndis_events_media_disconnect(struct ndis_events_data *events)
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ndis_events_media_specific(struct ndis_events_data *events,
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       IWbemClassObject *pObj)
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VARIANT vt;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	LONG lower, upper, k;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	UCHAR ch;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *data, *pos;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* This is the StatusBuffer from NdisMIndicateStatus() call */
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  0, &vt, NULL, NULL);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (FAILED(hr)) {
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not get "
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "NdisStatusMediaSpecificIndication from "
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "the object?!");
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data_len = upper - lower + 1;
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = os_malloc(data_len);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL) {
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "data");
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		VariantClear(&vt);
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = data;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (k = lower; k <= upper; k++) {
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pos++ = ch;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VariantClear(&vt);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ndis_events_adapter_arrival(struct ndis_events_data *events)
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ndis_events_adapter_removal(struct ndis_events_data *events)
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic HRESULT STDMETHODCALLTYPE
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ndis_events_data *events = (struct ndis_events_data *) this;
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	long i;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (events->terminating) {
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "indication - terminating");
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WBEM_NO_ERROR;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	   lObjectCount); */
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < lObjectCount; i++) {
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemClassObject *pObj = ppObjArray[i];
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		HRESULT hr;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		VARIANT vtClass, vt;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  NULL);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (FAILED(hr)) {
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "event.");
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  NULL);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (FAILED(hr)) {
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "from event.");
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			VariantClear(&vtClass);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wcscmp(vtClass.bstrVal,
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   L"MSNdis_NotifyAdapterArrival") == 0) {
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "update adapter description since it may "
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "have changed with new adapter instance");
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ndis_events_get_adapter(events, events->ifname, NULL);
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "indication for foreign adapter: "
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "InstanceName: '%S' __CLASS: '%S'",
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   vt.bstrVal, vtClass.bstrVal);
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			VariantClear(&vtClass);
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			VariantClear(&vt);
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		VariantClear(&vt);
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wcscmp(vtClass.bstrVal,
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   L"MSNdis_StatusMediaSpecificIndication") == 0) {
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ndis_events_media_specific(events, pObj);
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (wcscmp(vtClass.bstrVal,
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  L"MSNdis_StatusMediaConnect") == 0) {
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ndis_events_media_connect(events);
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (wcscmp(vtClass.bstrVal,
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  L"MSNdis_StatusMediaDisconnect") == 0) {
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ndis_events_media_disconnect(events);
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (wcscmp(vtClass.bstrVal,
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  L"MSNdis_NotifyAdapterArrival") == 0) {
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ndis_events_adapter_arrival(events);
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (wcscmp(vtClass.bstrVal,
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  L"MSNdis_NotifyAdapterRemoval") == 0) {
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ndis_events_adapter_removal(events);
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "'%S'", vtClass.bstrVal);
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		VariantClear(&vtClass);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WBEM_NO_ERROR;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic HRESULT STDMETHODCALLTYPE
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WBEM_NO_ERROR;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int notification_query(IWbemObjectSink *pDestSink,
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      IWbemServices *pSvc, const char *class_name)
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WCHAR query[256];
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_snwprintf(query, 256,
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  L"SELECT * FROM %S", class_name);
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = call_IWbemServices_ExecNotificationQueryAsync(
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pSvc, L"WQL", query, 0, 0, pDestSink);
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (FAILED(hr)) {
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed with hresult of 0x%x",
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   class_name, (int) hr);
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int register_async_notification(IWbemObjectSink *pDestSink,
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       IWbemServices *pSvc)
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *class_list[] = {
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"MSNdis_StatusMediaConnect",
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"MSNdis_StatusMediaDisconnect",
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"MSNdis_StatusMediaSpecificIndication",
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"MSNdis_NotifyAdapterArrival",
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"MSNdis_NotifyAdapterRemoval",
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NULL
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; class_list[i]; i++) {
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ndis_events_deinit(struct ndis_events_data *events)
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->terminating = 1;
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemObjectSink_Release(&events->sink);
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Rest of deinitialization is done in ndis_events_destructor() once
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * all reference count drops to zero.
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ndis_events_use_desc(struct ndis_events_data *events,
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const char *desc)
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *tmp, *pos;
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (desc == NULL) {
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (events->adapter_desc == NULL)
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Continue using old description */
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp = os_strdup(desc);
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tmp == NULL)
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos)
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pos = '\0';
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = os_strlen(tmp);
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (events->adapter_desc == NULL) {
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tmp);
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(tmp);
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ndis_events_get_adapter(struct ndis_events_data *events,
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const char *ifname, const char *desc)
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices *pSvc;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_QUERY_LEN 256
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WCHAR query[MAX_QUERY_LEN];
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IEnumWbemClassObject *pEnumerator;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemClassObject *pObj;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ULONG uReturned;
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VARIANT vt;
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int len, pos;
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to have better probability of matching with InstanceName from
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * MSNdis events. If this fails, use the provided description.
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(events->adapter_desc);
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->adapter_desc = NULL;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = call_IWbemLocator_ConnectServer(
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (FAILED(hr)) {
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_snwprintf(query, MAX_QUERY_LEN,
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  L"WHERE SettingID='%S'", ifname);
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = call_IWbemServices_ExecQuery(
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pSvc, L"WQL", query,
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NULL, &pEnumerator);
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "GUID from Win32_NetworkAdapterConfiguration: "
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%x", (int) hr);
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uReturned = 0;
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       &pObj, &uReturned);
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr) || uReturned == 0) {
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "GUID from Win32_NetworkAdapterConfiguration: "
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%x", (int) hr);
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEnumWbemClassObject_Release(pEnumerator);
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IEnumWbemClassObject_Release(pEnumerator);
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VariantInit(&vt);
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Win32_NetworkAdapterConfiguration: 0x%x",
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) hr);
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	_snwprintf(query, MAX_QUERY_LEN,
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  L"Index=%d",
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  vt.uintVal);
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VariantClear(&vt);
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemClassObject_Release(pObj);
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = call_IWbemServices_ExecQuery(
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pSvc, L"WQL", query,
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NULL, &pEnumerator);
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uReturned = 0;
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       &pObj, &uReturned);
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr) || uReturned == 0) {
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEnumWbemClassObject_Release(pEnumerator);
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IEnumWbemClassObject_Release(pEnumerator);
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Win32_NetworkAdapter: 0x%x", (int) hr);
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemClassObject_Release(pObj);
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   vt.bstrVal);
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->adapter_desc = _wcsdup(vt.bstrVal);
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VariantClear(&vt);
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Try to get even better candidate for matching with InstanceName
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * from Win32_PnPEntity. This is needed at least for some USB cards
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that can change the InstanceName whenever being unplugged and
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * plugged again.
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemClassObject_Release(pObj);
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (events->adapter_desc == NULL)
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ndis_events_use_desc(events, desc);
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* use Win32_NetworkAdapter::Name */
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "'%S'", vt.bstrVal);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = _snwprintf(query, MAX_QUERY_LEN,
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 0 || len >= MAX_QUERY_LEN - 1) {
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		VariantClear(&vt);
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemClassObject_Release(pObj);
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (events->adapter_desc == NULL)
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ndis_events_use_desc(events, desc);
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* use Win32_NetworkAdapter::Name */
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Escape \ as \\ */
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (vt.bstrVal[pos] == '\\') {
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (len >= MAX_QUERY_LEN - 3)
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			query[len++] = '\\';
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query[len++] = vt.bstrVal[pos];
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	query[len++] = L'\'';
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	query[len] = L'\0';
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VariantClear(&vt);
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemClassObject_Release(pObj);
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = call_IWbemServices_ExecQuery(
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pSvc, L"WQL", query,
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NULL, &pEnumerator);
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Name from Win32_PnPEntity: 0x%x", (int) hr);
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (events->adapter_desc == NULL)
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ndis_events_use_desc(events, desc);
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* use Win32_NetworkAdapter::Name */
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uReturned = 0;
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       &pObj, &uReturned);
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr) || uReturned == 0) {
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "from Win32_PnPEntity: 0x%x", (int) hr);
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEnumWbemClassObject_Release(pEnumerator);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (events->adapter_desc == NULL)
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ndis_events_use_desc(events, desc);
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* use Win32_NetworkAdapter::Name */
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IEnumWbemClassObject_Release(pEnumerator);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!SUCCEEDED(hr)) {
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Win32_PnPEntity: 0x%x", (int) hr);
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemClassObject_Release(pObj);
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IWbemServices_Release(pSvc);
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (events->adapter_desc == NULL)
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ndis_events_use_desc(events, desc);
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* use Win32_NetworkAdapter::Name */
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   vt.bstrVal);
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(events->adapter_desc);
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->adapter_desc = _wcsdup(vt.bstrVal);
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	VariantClear(&vt);
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemClassObject_Release(pObj);
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemServices_Release(pSvc);
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (events->adapter_desc == NULL)
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ndis_events_use_desc(events, desc);
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ndis_events_data *
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 const char *ifname, const char *desc)
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	HRESULT hr;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	IWbemObjectSink *pSink;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ndis_events_data *events;
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events = os_zalloc(sizeof(*events));
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (events == NULL) {
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->ifname = os_strdup(ifname);
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (events->ifname == NULL) {
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events);
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wmi_refcnt++ == 0) {
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (FAILED(hr)) {
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "returned 0x%x", (int) hr);
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(events);
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wmi_first) {
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* CoInitializeSecurity() must be called once and only once
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * per process, so let's use wmi_first flag to protect against
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * multiple calls. */
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wmi_first = 0;
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  RPC_C_IMP_LEVEL_IMPERSONATE,
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  NULL, EOAC_SECURE_REFS, NULL);
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (FAILED(hr)) {
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "- returned 0x%x", (int) hr);
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(events);
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      &IID_IWbemLocator,
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      (LPVOID *) (void *) &events->pLoc);
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (FAILED(hr)) {
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%x", (int) hr);
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CoUninitialize();
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events);
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ndis_events_get_adapter(events, ifname, desc) < 0) {
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CoUninitialize();
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events);
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   events->adapter_desc);
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hr = call_IWbemLocator_ConnectServer(
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		events->pLoc, L"ROOT\\WMI", NULL, NULL,
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0, 0, 0, 0, &events->pSvc);
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (FAILED(hr)) {
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Could not connect to server - error "
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%x", (int) hr);
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CoUninitialize();
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events->adapter_desc);
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events);
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ndis_events_constructor(events);
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pSink = &events->sink;
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pSink->lpVtbl = &events->sink_vtbl;
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->sink_vtbl.QueryInterface = ndis_events_query_interface;
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->sink_vtbl.AddRef = ndis_events_add_ref;
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->sink_vtbl.Release = ndis_events_release;
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->sink_vtbl.Indicate = ndis_events_indicate;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	events->sink_vtbl.SetStatus = ndis_events_set_status;
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (register_async_notification(pSink, events->pSvc) < 0) {
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to register async "
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "notifications");
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ndis_events_destructor(events);
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events->adapter_desc);
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(events);
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*read_pipe = events->read_pipe;
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*event_avail = events->event_avail;
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return events;
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
803