xref: /freebsd/contrib/wpa/src/drivers/ndis_events.c (revision f05cddf9)
13157ba21SRui Paulo /*
23157ba21SRui Paulo  * ndis_events - Receive NdisMIndicateStatus() events using WMI
33157ba21SRui Paulo  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
43157ba21SRui Paulo  *
5*f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6*f05cddf9SRui Paulo  * See README for more details.
73157ba21SRui Paulo  */
83157ba21SRui Paulo 
93157ba21SRui Paulo #define _WIN32_WINNT    0x0400
103157ba21SRui Paulo 
113157ba21SRui Paulo #include "includes.h"
123157ba21SRui Paulo 
133157ba21SRui Paulo #ifndef COBJMACROS
143157ba21SRui Paulo #define COBJMACROS
153157ba21SRui Paulo #endif /* COBJMACROS */
163157ba21SRui Paulo #include <wbemidl.h>
173157ba21SRui Paulo 
183157ba21SRui Paulo #include "common.h"
193157ba21SRui Paulo 
203157ba21SRui Paulo 
213157ba21SRui Paulo static int wmi_refcnt = 0;
223157ba21SRui Paulo static int wmi_first = 1;
233157ba21SRui Paulo 
243157ba21SRui Paulo struct ndis_events_data {
253157ba21SRui Paulo 	IWbemObjectSink sink;
263157ba21SRui Paulo 	IWbemObjectSinkVtbl sink_vtbl;
273157ba21SRui Paulo 
283157ba21SRui Paulo 	IWbemServices *pSvc;
293157ba21SRui Paulo 	IWbemLocator *pLoc;
303157ba21SRui Paulo 
313157ba21SRui Paulo 	HANDLE read_pipe, write_pipe, event_avail;
323157ba21SRui Paulo 	UINT ref;
333157ba21SRui Paulo 	int terminating;
343157ba21SRui Paulo 	char *ifname; /* {GUID..} */
353157ba21SRui Paulo 	WCHAR *adapter_desc;
363157ba21SRui Paulo };
373157ba21SRui Paulo 
383157ba21SRui Paulo #define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
393157ba21SRui Paulo #define BstrFree(x) if (x) SysFreeString(x)
403157ba21SRui Paulo 
413157ba21SRui Paulo /* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
423157ba21SRui Paulo  * BSTRs */
call_IWbemServices_ExecQuery(IWbemServices * pSvc,LPCWSTR strQueryLanguage,LPCWSTR strQuery,long lFlags,IWbemContext * pCtx,IEnumWbemClassObject ** ppEnum)433157ba21SRui Paulo HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
443157ba21SRui Paulo 	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
453157ba21SRui Paulo 	long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
463157ba21SRui Paulo {
473157ba21SRui Paulo 	BSTR bsQueryLanguage, bsQuery;
483157ba21SRui Paulo 	HRESULT hr;
493157ba21SRui Paulo 
503157ba21SRui Paulo 	bsQueryLanguage = BstrAlloc(strQueryLanguage);
513157ba21SRui Paulo 	bsQuery = BstrAlloc(strQuery);
523157ba21SRui Paulo 
533157ba21SRui Paulo 	hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
543157ba21SRui Paulo 				     pCtx, ppEnum);
553157ba21SRui Paulo 
563157ba21SRui Paulo 	BstrFree(bsQueryLanguage);
573157ba21SRui Paulo 	BstrFree(bsQuery);
583157ba21SRui Paulo 
593157ba21SRui Paulo 	return hr;
603157ba21SRui Paulo }
613157ba21SRui Paulo 
623157ba21SRui Paulo 
call_IWbemServices_ExecNotificationQueryAsync(IWbemServices * pSvc,LPCWSTR strQueryLanguage,LPCWSTR strQuery,long lFlags,IWbemContext * pCtx,IWbemObjectSink * pResponseHandler)633157ba21SRui Paulo HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
643157ba21SRui Paulo 	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
653157ba21SRui Paulo 	long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
663157ba21SRui Paulo {
673157ba21SRui Paulo 	BSTR bsQueryLanguage, bsQuery;
683157ba21SRui Paulo 	HRESULT hr;
693157ba21SRui Paulo 
703157ba21SRui Paulo 	bsQueryLanguage = BstrAlloc(strQueryLanguage);
713157ba21SRui Paulo 	bsQuery = BstrAlloc(strQuery);
723157ba21SRui Paulo 
733157ba21SRui Paulo 	hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
743157ba21SRui Paulo 						      bsQuery, lFlags, pCtx,
753157ba21SRui Paulo 						      pResponseHandler);
763157ba21SRui Paulo 
773157ba21SRui Paulo 	BstrFree(bsQueryLanguage);
783157ba21SRui Paulo 	BstrFree(bsQuery);
793157ba21SRui Paulo 
803157ba21SRui Paulo 	return hr;
813157ba21SRui Paulo }
823157ba21SRui Paulo 
833157ba21SRui Paulo 
call_IWbemLocator_ConnectServer(IWbemLocator * pLoc,LPCWSTR strNetworkResource,LPCWSTR strUser,LPCWSTR strPassword,LPCWSTR strLocale,long lSecurityFlags,LPCWSTR strAuthority,IWbemContext * pCtx,IWbemServices ** ppNamespace)843157ba21SRui Paulo HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
853157ba21SRui Paulo 	IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
863157ba21SRui Paulo 	LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
873157ba21SRui Paulo 	LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
883157ba21SRui Paulo {
893157ba21SRui Paulo 	BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
903157ba21SRui Paulo 	HRESULT hr;
913157ba21SRui Paulo 
923157ba21SRui Paulo 	bsNetworkResource = BstrAlloc(strNetworkResource);
933157ba21SRui Paulo 	bsUser = BstrAlloc(strUser);
943157ba21SRui Paulo 	bsPassword = BstrAlloc(strPassword);
953157ba21SRui Paulo 	bsLocale = BstrAlloc(strLocale);
963157ba21SRui Paulo 	bsAuthority = BstrAlloc(strAuthority);
973157ba21SRui Paulo 
983157ba21SRui Paulo 	hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
993157ba21SRui Paulo 					bsPassword, bsLocale, lSecurityFlags,
1003157ba21SRui Paulo 					bsAuthority, pCtx, ppNamespace);
1013157ba21SRui Paulo 
1023157ba21SRui Paulo 	BstrFree(bsNetworkResource);
1033157ba21SRui Paulo 	BstrFree(bsUser);
1043157ba21SRui Paulo 	BstrFree(bsPassword);
1053157ba21SRui Paulo 	BstrFree(bsLocale);
1063157ba21SRui Paulo 	BstrFree(bsAuthority);
1073157ba21SRui Paulo 
1083157ba21SRui Paulo 	return hr;
1093157ba21SRui Paulo }
1103157ba21SRui Paulo 
1113157ba21SRui Paulo 
1123157ba21SRui Paulo enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
1133157ba21SRui Paulo 		   EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
1143157ba21SRui Paulo 
1153157ba21SRui Paulo static int ndis_events_get_adapter(struct ndis_events_data *events,
1163157ba21SRui Paulo 				   const char *ifname, const char *desc);
1173157ba21SRui Paulo 
1183157ba21SRui Paulo 
ndis_events_constructor(struct ndis_events_data * events)1193157ba21SRui Paulo static int ndis_events_constructor(struct ndis_events_data *events)
1203157ba21SRui Paulo {
1213157ba21SRui Paulo 	events->ref = 1;
1223157ba21SRui Paulo 
1233157ba21SRui Paulo 	if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
1243157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
1253157ba21SRui Paulo 			   (int) GetLastError());
1263157ba21SRui Paulo 		return -1;
1273157ba21SRui Paulo 	}
1283157ba21SRui Paulo 	events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
1293157ba21SRui Paulo 	if (events->event_avail == NULL) {
1303157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
1313157ba21SRui Paulo 			   (int) GetLastError());
1323157ba21SRui Paulo 		CloseHandle(events->read_pipe);
1333157ba21SRui Paulo 		CloseHandle(events->write_pipe);
1343157ba21SRui Paulo 		return -1;
1353157ba21SRui Paulo 	}
1363157ba21SRui Paulo 
1373157ba21SRui Paulo 	return 0;
1383157ba21SRui Paulo }
1393157ba21SRui Paulo 
1403157ba21SRui Paulo 
ndis_events_destructor(struct ndis_events_data * events)1413157ba21SRui Paulo static void ndis_events_destructor(struct ndis_events_data *events)
1423157ba21SRui Paulo {
1433157ba21SRui Paulo 	CloseHandle(events->read_pipe);
1443157ba21SRui Paulo 	CloseHandle(events->write_pipe);
1453157ba21SRui Paulo 	CloseHandle(events->event_avail);
1463157ba21SRui Paulo 	IWbemServices_Release(events->pSvc);
1473157ba21SRui Paulo 	IWbemLocator_Release(events->pLoc);
1483157ba21SRui Paulo 	if (--wmi_refcnt == 0)
1493157ba21SRui Paulo 		CoUninitialize();
1503157ba21SRui Paulo }
1513157ba21SRui Paulo 
1523157ba21SRui Paulo 
1533157ba21SRui Paulo static HRESULT STDMETHODCALLTYPE
ndis_events_query_interface(IWbemObjectSink * this,REFIID riid,void ** obj)1543157ba21SRui Paulo ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
1553157ba21SRui Paulo {
1563157ba21SRui Paulo 	*obj = NULL;
1573157ba21SRui Paulo 
1583157ba21SRui Paulo 	if (IsEqualIID(riid, &IID_IUnknown) ||
1593157ba21SRui Paulo 	    IsEqualIID(riid, &IID_IWbemObjectSink)) {
1603157ba21SRui Paulo 		*obj = this;
1613157ba21SRui Paulo 		IWbemObjectSink_AddRef(this);
1623157ba21SRui Paulo 		return NOERROR;
1633157ba21SRui Paulo 	}
1643157ba21SRui Paulo 
1653157ba21SRui Paulo 	return E_NOINTERFACE;
1663157ba21SRui Paulo }
1673157ba21SRui Paulo 
1683157ba21SRui Paulo 
ndis_events_add_ref(IWbemObjectSink * this)1693157ba21SRui Paulo static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
1703157ba21SRui Paulo {
1713157ba21SRui Paulo 	struct ndis_events_data *events = (struct ndis_events_data *) this;
1723157ba21SRui Paulo 	return ++events->ref;
1733157ba21SRui Paulo }
1743157ba21SRui Paulo 
1753157ba21SRui Paulo 
ndis_events_release(IWbemObjectSink * this)1763157ba21SRui Paulo static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
1773157ba21SRui Paulo {
1783157ba21SRui Paulo 	struct ndis_events_data *events = (struct ndis_events_data *) this;
1793157ba21SRui Paulo 
1803157ba21SRui Paulo 	if (--events->ref != 0)
1813157ba21SRui Paulo 		return events->ref;
1823157ba21SRui Paulo 
1833157ba21SRui Paulo 	ndis_events_destructor(events);
1843157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: terminated");
1853157ba21SRui Paulo 	os_free(events->adapter_desc);
1863157ba21SRui Paulo 	os_free(events->ifname);
1873157ba21SRui Paulo 	os_free(events);
1883157ba21SRui Paulo 	return 0;
1893157ba21SRui Paulo }
1903157ba21SRui Paulo 
1913157ba21SRui Paulo 
ndis_events_send_event(struct ndis_events_data * events,enum event_types type,char * data,size_t data_len)1923157ba21SRui Paulo static int ndis_events_send_event(struct ndis_events_data *events,
1933157ba21SRui Paulo 				  enum event_types type,
1943157ba21SRui Paulo 				  char *data, size_t data_len)
1953157ba21SRui Paulo {
1963157ba21SRui Paulo 	char buf[512], *pos, *end;
1973157ba21SRui Paulo 	int _type;
1983157ba21SRui Paulo 	DWORD written;
1993157ba21SRui Paulo 
2003157ba21SRui Paulo 	end = buf + sizeof(buf);
2013157ba21SRui Paulo 	_type = (int) type;
2023157ba21SRui Paulo 	os_memcpy(buf, &_type, sizeof(_type));
2033157ba21SRui Paulo 	pos = buf + sizeof(_type);
2043157ba21SRui Paulo 
2053157ba21SRui Paulo 	if (data) {
2063157ba21SRui Paulo 		if (2 + data_len > (size_t) (end - pos)) {
2073157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "Not enough room for send_event "
2083157ba21SRui Paulo 				   "data (%d)", data_len);
2093157ba21SRui Paulo 			return -1;
2103157ba21SRui Paulo 		}
2113157ba21SRui Paulo 		*pos++ = data_len >> 8;
2123157ba21SRui Paulo 		*pos++ = data_len & 0xff;
2133157ba21SRui Paulo 		os_memcpy(pos, data, data_len);
2143157ba21SRui Paulo 		pos += data_len;
2153157ba21SRui Paulo 	}
2163157ba21SRui Paulo 
2173157ba21SRui Paulo 	if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
2183157ba21SRui Paulo 		SetEvent(events->event_avail);
2193157ba21SRui Paulo 		return 0;
2203157ba21SRui Paulo 	}
2213157ba21SRui Paulo 	wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
2223157ba21SRui Paulo 	return -1;
2233157ba21SRui Paulo }
2243157ba21SRui Paulo 
2253157ba21SRui Paulo 
ndis_events_media_connect(struct ndis_events_data * events)2263157ba21SRui Paulo static void ndis_events_media_connect(struct ndis_events_data *events)
2273157ba21SRui Paulo {
2283157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
2293157ba21SRui Paulo 	ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
2303157ba21SRui Paulo }
2313157ba21SRui Paulo 
2323157ba21SRui Paulo 
ndis_events_media_disconnect(struct ndis_events_data * events)2333157ba21SRui Paulo static void ndis_events_media_disconnect(struct ndis_events_data *events)
2343157ba21SRui Paulo {
2353157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
2363157ba21SRui Paulo 	ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
2373157ba21SRui Paulo }
2383157ba21SRui Paulo 
2393157ba21SRui Paulo 
ndis_events_media_specific(struct ndis_events_data * events,IWbemClassObject * pObj)2403157ba21SRui Paulo static void ndis_events_media_specific(struct ndis_events_data *events,
2413157ba21SRui Paulo 				       IWbemClassObject *pObj)
2423157ba21SRui Paulo {
2433157ba21SRui Paulo 	VARIANT vt;
2443157ba21SRui Paulo 	HRESULT hr;
2453157ba21SRui Paulo 	LONG lower, upper, k;
2463157ba21SRui Paulo 	UCHAR ch;
2473157ba21SRui Paulo 	char *data, *pos;
2483157ba21SRui Paulo 	size_t data_len;
2493157ba21SRui Paulo 
2503157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
2513157ba21SRui Paulo 
2523157ba21SRui Paulo 	/* This is the StatusBuffer from NdisMIndicateStatus() call */
2533157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
2543157ba21SRui Paulo 				  0, &vt, NULL, NULL);
2553157ba21SRui Paulo 	if (FAILED(hr)) {
2563157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "Could not get "
2573157ba21SRui Paulo 			   "NdisStatusMediaSpecificIndication from "
2583157ba21SRui Paulo 			   "the object?!");
2593157ba21SRui Paulo 		return;
2603157ba21SRui Paulo 	}
2613157ba21SRui Paulo 
2623157ba21SRui Paulo 	SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
2633157ba21SRui Paulo 	SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
2643157ba21SRui Paulo 	data_len = upper - lower + 1;
2653157ba21SRui Paulo 	data = os_malloc(data_len);
2663157ba21SRui Paulo 	if (data == NULL) {
2673157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
2683157ba21SRui Paulo 			   "data");
2693157ba21SRui Paulo 		VariantClear(&vt);
2703157ba21SRui Paulo 		return;
2713157ba21SRui Paulo 	}
2723157ba21SRui Paulo 
2733157ba21SRui Paulo 	pos = data;
2743157ba21SRui Paulo 	for (k = lower; k <= upper; k++) {
2753157ba21SRui Paulo 		SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
2763157ba21SRui Paulo 		*pos++ = ch;
2773157ba21SRui Paulo 	}
2783157ba21SRui Paulo 	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
2793157ba21SRui Paulo 
2803157ba21SRui Paulo 	VariantClear(&vt);
2813157ba21SRui Paulo 
2823157ba21SRui Paulo 	ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
2833157ba21SRui Paulo 
2843157ba21SRui Paulo 	os_free(data);
2853157ba21SRui Paulo }
2863157ba21SRui Paulo 
2873157ba21SRui Paulo 
ndis_events_adapter_arrival(struct ndis_events_data * events)2883157ba21SRui Paulo static void ndis_events_adapter_arrival(struct ndis_events_data *events)
2893157ba21SRui Paulo {
2903157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
2913157ba21SRui Paulo 	ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
2923157ba21SRui Paulo }
2933157ba21SRui Paulo 
2943157ba21SRui Paulo 
ndis_events_adapter_removal(struct ndis_events_data * events)2953157ba21SRui Paulo static void ndis_events_adapter_removal(struct ndis_events_data *events)
2963157ba21SRui Paulo {
2973157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
2983157ba21SRui Paulo 	ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
2993157ba21SRui Paulo }
3003157ba21SRui Paulo 
3013157ba21SRui Paulo 
3023157ba21SRui Paulo static HRESULT STDMETHODCALLTYPE
ndis_events_indicate(IWbemObjectSink * this,long lObjectCount,IWbemClassObject __RPC_FAR * __RPC_FAR * ppObjArray)3033157ba21SRui Paulo ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
3043157ba21SRui Paulo 		     IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
3053157ba21SRui Paulo {
3063157ba21SRui Paulo 	struct ndis_events_data *events = (struct ndis_events_data *) this;
3073157ba21SRui Paulo 	long i;
3083157ba21SRui Paulo 
3093157ba21SRui Paulo 	if (events->terminating) {
3103157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
3113157ba21SRui Paulo 			   "indication - terminating");
3123157ba21SRui Paulo 		return WBEM_NO_ERROR;
3133157ba21SRui Paulo 	}
3143157ba21SRui Paulo 	/* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
3153157ba21SRui Paulo 	   lObjectCount); */
3163157ba21SRui Paulo 
3173157ba21SRui Paulo 	for (i = 0; i < lObjectCount; i++) {
3183157ba21SRui Paulo 		IWbemClassObject *pObj = ppObjArray[i];
3193157ba21SRui Paulo 		HRESULT hr;
3203157ba21SRui Paulo 		VARIANT vtClass, vt;
3213157ba21SRui Paulo 
3223157ba21SRui Paulo 		hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
3233157ba21SRui Paulo 					  NULL);
3243157ba21SRui Paulo 		if (FAILED(hr)) {
3253157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
3263157ba21SRui Paulo 				   "event.");
3273157ba21SRui Paulo 			break;
3283157ba21SRui Paulo 		}
3293157ba21SRui Paulo 		/* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
3303157ba21SRui Paulo 
3313157ba21SRui Paulo 		hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
3323157ba21SRui Paulo 					  NULL);
3333157ba21SRui Paulo 		if (FAILED(hr)) {
3343157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
3353157ba21SRui Paulo 				   "from event.");
3363157ba21SRui Paulo 			VariantClear(&vtClass);
3373157ba21SRui Paulo 			break;
3383157ba21SRui Paulo 		}
3393157ba21SRui Paulo 
3403157ba21SRui Paulo 		if (wcscmp(vtClass.bstrVal,
3413157ba21SRui Paulo 			   L"MSNdis_NotifyAdapterArrival") == 0) {
3423157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
3433157ba21SRui Paulo 				   "update adapter description since it may "
3443157ba21SRui Paulo 				   "have changed with new adapter instance");
3453157ba21SRui Paulo 			ndis_events_get_adapter(events, events->ifname, NULL);
3463157ba21SRui Paulo 		}
3473157ba21SRui Paulo 
3483157ba21SRui Paulo 		if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
3493157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
3503157ba21SRui Paulo 				   "indication for foreign adapter: "
3513157ba21SRui Paulo 				   "InstanceName: '%S' __CLASS: '%S'",
3523157ba21SRui Paulo 				   vt.bstrVal, vtClass.bstrVal);
3533157ba21SRui Paulo 			VariantClear(&vtClass);
3543157ba21SRui Paulo 			VariantClear(&vt);
3553157ba21SRui Paulo 			continue;
3563157ba21SRui Paulo 		}
3573157ba21SRui Paulo 		VariantClear(&vt);
3583157ba21SRui Paulo 
3593157ba21SRui Paulo 		if (wcscmp(vtClass.bstrVal,
3603157ba21SRui Paulo 			   L"MSNdis_StatusMediaSpecificIndication") == 0) {
3613157ba21SRui Paulo 			ndis_events_media_specific(events, pObj);
3623157ba21SRui Paulo 		} else if (wcscmp(vtClass.bstrVal,
3633157ba21SRui Paulo 				  L"MSNdis_StatusMediaConnect") == 0) {
3643157ba21SRui Paulo 			ndis_events_media_connect(events);
3653157ba21SRui Paulo 		} else if (wcscmp(vtClass.bstrVal,
3663157ba21SRui Paulo 				  L"MSNdis_StatusMediaDisconnect") == 0) {
3673157ba21SRui Paulo 			ndis_events_media_disconnect(events);
3683157ba21SRui Paulo 		} else if (wcscmp(vtClass.bstrVal,
3693157ba21SRui Paulo 				  L"MSNdis_NotifyAdapterArrival") == 0) {
3703157ba21SRui Paulo 			ndis_events_adapter_arrival(events);
3713157ba21SRui Paulo 		} else if (wcscmp(vtClass.bstrVal,
3723157ba21SRui Paulo 				  L"MSNdis_NotifyAdapterRemoval") == 0) {
3733157ba21SRui Paulo 			ndis_events_adapter_removal(events);
3743157ba21SRui Paulo 		} else {
3753157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
3763157ba21SRui Paulo 				   "'%S'", vtClass.bstrVal);
3773157ba21SRui Paulo 		}
3783157ba21SRui Paulo 
3793157ba21SRui Paulo 		VariantClear(&vtClass);
3803157ba21SRui Paulo 	}
3813157ba21SRui Paulo 
3823157ba21SRui Paulo 	return WBEM_NO_ERROR;
3833157ba21SRui Paulo }
3843157ba21SRui Paulo 
3853157ba21SRui Paulo 
3863157ba21SRui Paulo static HRESULT STDMETHODCALLTYPE
ndis_events_set_status(IWbemObjectSink * this,long lFlags,HRESULT hResult,BSTR strParam,IWbemClassObject __RPC_FAR * pObjParam)3873157ba21SRui Paulo ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
3883157ba21SRui Paulo 		       BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
3893157ba21SRui Paulo {
3903157ba21SRui Paulo 	return WBEM_NO_ERROR;
3913157ba21SRui Paulo }
3923157ba21SRui Paulo 
3933157ba21SRui Paulo 
notification_query(IWbemObjectSink * pDestSink,IWbemServices * pSvc,const char * class_name)3943157ba21SRui Paulo static int notification_query(IWbemObjectSink *pDestSink,
3953157ba21SRui Paulo 			      IWbemServices *pSvc, const char *class_name)
3963157ba21SRui Paulo {
3973157ba21SRui Paulo 	HRESULT hr;
3983157ba21SRui Paulo 	WCHAR query[256];
3993157ba21SRui Paulo 
4003157ba21SRui Paulo 	_snwprintf(query, 256,
4013157ba21SRui Paulo 		  L"SELECT * FROM %S", class_name);
4023157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
4033157ba21SRui Paulo 	hr = call_IWbemServices_ExecNotificationQueryAsync(
4043157ba21SRui Paulo 		pSvc, L"WQL", query, 0, 0, pDestSink);
4053157ba21SRui Paulo 	if (FAILED(hr)) {
4063157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
4073157ba21SRui Paulo 			   "failed with hresult of 0x%x",
4083157ba21SRui Paulo 			   class_name, (int) hr);
4093157ba21SRui Paulo 		return -1;
4103157ba21SRui Paulo 	}
4113157ba21SRui Paulo 
4123157ba21SRui Paulo 	return 0;
4133157ba21SRui Paulo }
4143157ba21SRui Paulo 
4153157ba21SRui Paulo 
register_async_notification(IWbemObjectSink * pDestSink,IWbemServices * pSvc)4163157ba21SRui Paulo static int register_async_notification(IWbemObjectSink *pDestSink,
4173157ba21SRui Paulo 				       IWbemServices *pSvc)
4183157ba21SRui Paulo {
4193157ba21SRui Paulo 	int i;
4203157ba21SRui Paulo 	const char *class_list[] = {
4213157ba21SRui Paulo 		"MSNdis_StatusMediaConnect",
4223157ba21SRui Paulo 		"MSNdis_StatusMediaDisconnect",
4233157ba21SRui Paulo 		"MSNdis_StatusMediaSpecificIndication",
4243157ba21SRui Paulo 		"MSNdis_NotifyAdapterArrival",
4253157ba21SRui Paulo 		"MSNdis_NotifyAdapterRemoval",
4263157ba21SRui Paulo 		NULL
4273157ba21SRui Paulo 	};
4283157ba21SRui Paulo 
4293157ba21SRui Paulo 	for (i = 0; class_list[i]; i++) {
4303157ba21SRui Paulo 		if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
4313157ba21SRui Paulo 			return -1;
4323157ba21SRui Paulo 	}
4333157ba21SRui Paulo 
4343157ba21SRui Paulo 	return 0;
4353157ba21SRui Paulo }
4363157ba21SRui Paulo 
4373157ba21SRui Paulo 
ndis_events_deinit(struct ndis_events_data * events)4383157ba21SRui Paulo void ndis_events_deinit(struct ndis_events_data *events)
4393157ba21SRui Paulo {
4403157ba21SRui Paulo 	events->terminating = 1;
4413157ba21SRui Paulo 	IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
4423157ba21SRui Paulo 	IWbemObjectSink_Release(&events->sink);
4433157ba21SRui Paulo 	/*
4443157ba21SRui Paulo 	 * Rest of deinitialization is done in ndis_events_destructor() once
4453157ba21SRui Paulo 	 * all reference count drops to zero.
4463157ba21SRui Paulo 	 */
4473157ba21SRui Paulo }
4483157ba21SRui Paulo 
4493157ba21SRui Paulo 
ndis_events_use_desc(struct ndis_events_data * events,const char * desc)4503157ba21SRui Paulo static int ndis_events_use_desc(struct ndis_events_data *events,
4513157ba21SRui Paulo 				const char *desc)
4523157ba21SRui Paulo {
4533157ba21SRui Paulo 	char *tmp, *pos;
4543157ba21SRui Paulo 	size_t len;
4553157ba21SRui Paulo 
4563157ba21SRui Paulo 	if (desc == NULL) {
4573157ba21SRui Paulo 		if (events->adapter_desc == NULL)
4583157ba21SRui Paulo 			return -1;
4593157ba21SRui Paulo 		/* Continue using old description */
4603157ba21SRui Paulo 		return 0;
4613157ba21SRui Paulo 	}
4623157ba21SRui Paulo 
4633157ba21SRui Paulo 	tmp = os_strdup(desc);
4643157ba21SRui Paulo 	if (tmp == NULL)
4653157ba21SRui Paulo 		return -1;
4663157ba21SRui Paulo 
4673157ba21SRui Paulo 	pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
4683157ba21SRui Paulo 	if (pos)
4693157ba21SRui Paulo 		*pos = '\0';
4703157ba21SRui Paulo 
4713157ba21SRui Paulo 	len = os_strlen(tmp);
4723157ba21SRui Paulo 	events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
4733157ba21SRui Paulo 	if (events->adapter_desc == NULL) {
4743157ba21SRui Paulo 		os_free(tmp);
4753157ba21SRui Paulo 		return -1;
4763157ba21SRui Paulo 	}
4773157ba21SRui Paulo 	_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
4783157ba21SRui Paulo 	os_free(tmp);
4793157ba21SRui Paulo 	return 0;
4803157ba21SRui Paulo }
4813157ba21SRui Paulo 
4823157ba21SRui Paulo 
ndis_events_get_adapter(struct ndis_events_data * events,const char * ifname,const char * desc)4833157ba21SRui Paulo static int ndis_events_get_adapter(struct ndis_events_data *events,
4843157ba21SRui Paulo 				   const char *ifname, const char *desc)
4853157ba21SRui Paulo {
4863157ba21SRui Paulo 	HRESULT hr;
4873157ba21SRui Paulo 	IWbemServices *pSvc;
4883157ba21SRui Paulo #define MAX_QUERY_LEN 256
4893157ba21SRui Paulo 	WCHAR query[MAX_QUERY_LEN];
4903157ba21SRui Paulo 	IEnumWbemClassObject *pEnumerator;
4913157ba21SRui Paulo 	IWbemClassObject *pObj;
4923157ba21SRui Paulo 	ULONG uReturned;
4933157ba21SRui Paulo 	VARIANT vt;
4943157ba21SRui Paulo 	int len, pos;
4953157ba21SRui Paulo 
4963157ba21SRui Paulo 	/*
4973157ba21SRui Paulo 	 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
4983157ba21SRui Paulo 	 * to have better probability of matching with InstanceName from
4993157ba21SRui Paulo 	 * MSNdis events. If this fails, use the provided description.
5003157ba21SRui Paulo 	 */
5013157ba21SRui Paulo 
5023157ba21SRui Paulo 	os_free(events->adapter_desc);
5033157ba21SRui Paulo 	events->adapter_desc = NULL;
5043157ba21SRui Paulo 
5053157ba21SRui Paulo 	hr = call_IWbemLocator_ConnectServer(
5063157ba21SRui Paulo 		events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
5073157ba21SRui Paulo 	if (FAILED(hr)) {
5083157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
5093157ba21SRui Paulo 			   "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
5103157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5113157ba21SRui Paulo 	}
5123157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
5133157ba21SRui Paulo 
5143157ba21SRui Paulo 	_snwprintf(query, MAX_QUERY_LEN,
5153157ba21SRui Paulo 		  L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
5163157ba21SRui Paulo 		  L"WHERE SettingID='%S'", ifname);
5173157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
5183157ba21SRui Paulo 
5193157ba21SRui Paulo 	hr = call_IWbemServices_ExecQuery(
5203157ba21SRui Paulo 		pSvc, L"WQL", query,
5213157ba21SRui Paulo 		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
5223157ba21SRui Paulo 		NULL, &pEnumerator);
5233157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5243157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
5253157ba21SRui Paulo 			   "GUID from Win32_NetworkAdapterConfiguration: "
5263157ba21SRui Paulo 			   "0x%x", (int) hr);
5273157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5283157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5293157ba21SRui Paulo 	}
5303157ba21SRui Paulo 
5313157ba21SRui Paulo 	uReturned = 0;
5323157ba21SRui Paulo 	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
5333157ba21SRui Paulo 				       &pObj, &uReturned);
5343157ba21SRui Paulo 	if (!SUCCEEDED(hr) || uReturned == 0) {
5353157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
5363157ba21SRui Paulo 			   "GUID from Win32_NetworkAdapterConfiguration: "
5373157ba21SRui Paulo 			   "0x%x", (int) hr);
5383157ba21SRui Paulo 		IEnumWbemClassObject_Release(pEnumerator);
5393157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5403157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5413157ba21SRui Paulo 	}
5423157ba21SRui Paulo 	IEnumWbemClassObject_Release(pEnumerator);
5433157ba21SRui Paulo 
5443157ba21SRui Paulo 	VariantInit(&vt);
5453157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
5463157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5473157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
5483157ba21SRui Paulo 			   "Win32_NetworkAdapterConfiguration: 0x%x",
5493157ba21SRui Paulo 			   (int) hr);
5503157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5513157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5523157ba21SRui Paulo 	}
5533157ba21SRui Paulo 
5543157ba21SRui Paulo 	_snwprintf(query, MAX_QUERY_LEN,
5553157ba21SRui Paulo 		  L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
5563157ba21SRui Paulo 		  L"Index=%d",
5573157ba21SRui Paulo 		  vt.uintVal);
5583157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
5593157ba21SRui Paulo 	VariantClear(&vt);
5603157ba21SRui Paulo 	IWbemClassObject_Release(pObj);
5613157ba21SRui Paulo 
5623157ba21SRui Paulo 	hr = call_IWbemServices_ExecQuery(
5633157ba21SRui Paulo 		pSvc, L"WQL", query,
5643157ba21SRui Paulo 		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
5653157ba21SRui Paulo 		NULL, &pEnumerator);
5663157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5673157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
5683157ba21SRui Paulo 			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
5693157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5703157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5713157ba21SRui Paulo 	}
5723157ba21SRui Paulo 
5733157ba21SRui Paulo 	uReturned = 0;
5743157ba21SRui Paulo 	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
5753157ba21SRui Paulo 				       &pObj, &uReturned);
5763157ba21SRui Paulo 	if (!SUCCEEDED(hr) || uReturned == 0) {
5773157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
5783157ba21SRui Paulo 			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
5793157ba21SRui Paulo 		IEnumWbemClassObject_Release(pEnumerator);
5803157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5813157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5823157ba21SRui Paulo 	}
5833157ba21SRui Paulo 	IEnumWbemClassObject_Release(pEnumerator);
5843157ba21SRui Paulo 
5853157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
5863157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5873157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
5883157ba21SRui Paulo 			   "Win32_NetworkAdapter: 0x%x", (int) hr);
5893157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
5903157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5913157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5923157ba21SRui Paulo 	}
5933157ba21SRui Paulo 
5943157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
5953157ba21SRui Paulo 		   vt.bstrVal);
5963157ba21SRui Paulo 	events->adapter_desc = _wcsdup(vt.bstrVal);
5973157ba21SRui Paulo 	VariantClear(&vt);
5983157ba21SRui Paulo 
5993157ba21SRui Paulo 	/*
6003157ba21SRui Paulo 	 * Try to get even better candidate for matching with InstanceName
6013157ba21SRui Paulo 	 * from Win32_PnPEntity. This is needed at least for some USB cards
6023157ba21SRui Paulo 	 * that can change the InstanceName whenever being unplugged and
6033157ba21SRui Paulo 	 * plugged again.
6043157ba21SRui Paulo 	 */
6053157ba21SRui Paulo 
6063157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
6073157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
6083157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
6093157ba21SRui Paulo 			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
6103157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
6113157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6123157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6133157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6143157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6153157ba21SRui Paulo 	}
6163157ba21SRui Paulo 
6173157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
6183157ba21SRui Paulo 		   "'%S'", vt.bstrVal);
6193157ba21SRui Paulo 
6203157ba21SRui Paulo 	len = _snwprintf(query, MAX_QUERY_LEN,
6213157ba21SRui Paulo 			L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
6223157ba21SRui Paulo 	if (len < 0 || len >= MAX_QUERY_LEN - 1) {
6233157ba21SRui Paulo 		VariantClear(&vt);
6243157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
6253157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6263157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6273157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6283157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6293157ba21SRui Paulo 	}
6303157ba21SRui Paulo 
6313157ba21SRui Paulo 	/* Escape \ as \\ */
6323157ba21SRui Paulo 	for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
6333157ba21SRui Paulo 		if (vt.bstrVal[pos] == '\\') {
6343157ba21SRui Paulo 			if (len >= MAX_QUERY_LEN - 3)
6353157ba21SRui Paulo 				break;
6363157ba21SRui Paulo 			query[len++] = '\\';
6373157ba21SRui Paulo 		}
6383157ba21SRui Paulo 		query[len++] = vt.bstrVal[pos];
6393157ba21SRui Paulo 	}
6403157ba21SRui Paulo 	query[len++] = L'\'';
6413157ba21SRui Paulo 	query[len] = L'\0';
6423157ba21SRui Paulo 	VariantClear(&vt);
6433157ba21SRui Paulo 	IWbemClassObject_Release(pObj);
6443157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
6453157ba21SRui Paulo 
6463157ba21SRui Paulo 	hr = call_IWbemServices_ExecQuery(
6473157ba21SRui Paulo 		pSvc, L"WQL", query,
6483157ba21SRui Paulo 		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
6493157ba21SRui Paulo 		NULL, &pEnumerator);
6503157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
6513157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
6523157ba21SRui Paulo 			   "Name from Win32_PnPEntity: 0x%x", (int) hr);
6533157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6543157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6553157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6563157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6573157ba21SRui Paulo 	}
6583157ba21SRui Paulo 
6593157ba21SRui Paulo 	uReturned = 0;
6603157ba21SRui Paulo 	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
6613157ba21SRui Paulo 				       &pObj, &uReturned);
6623157ba21SRui Paulo 	if (!SUCCEEDED(hr) || uReturned == 0) {
6633157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
6643157ba21SRui Paulo 			   "from Win32_PnPEntity: 0x%x", (int) hr);
6653157ba21SRui Paulo 		IEnumWbemClassObject_Release(pEnumerator);
6663157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6673157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6683157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6693157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6703157ba21SRui Paulo 	}
6713157ba21SRui Paulo 	IEnumWbemClassObject_Release(pEnumerator);
6723157ba21SRui Paulo 
6733157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
6743157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
6753157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
6763157ba21SRui Paulo 			   "Win32_PnPEntity: 0x%x", (int) hr);
6773157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
6783157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6793157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6803157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6813157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6823157ba21SRui Paulo 	}
6833157ba21SRui Paulo 
6843157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
6853157ba21SRui Paulo 		   vt.bstrVal);
6863157ba21SRui Paulo 	os_free(events->adapter_desc);
6873157ba21SRui Paulo 	events->adapter_desc = _wcsdup(vt.bstrVal);
6883157ba21SRui Paulo 	VariantClear(&vt);
6893157ba21SRui Paulo 
6903157ba21SRui Paulo 	IWbemClassObject_Release(pObj);
6913157ba21SRui Paulo 
6923157ba21SRui Paulo 	IWbemServices_Release(pSvc);
6933157ba21SRui Paulo 
6943157ba21SRui Paulo 	if (events->adapter_desc == NULL)
6953157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
6963157ba21SRui Paulo 
6973157ba21SRui Paulo 	return 0;
6983157ba21SRui Paulo }
6993157ba21SRui Paulo 
7003157ba21SRui Paulo 
7013157ba21SRui Paulo struct ndis_events_data *
ndis_events_init(HANDLE * read_pipe,HANDLE * event_avail,const char * ifname,const char * desc)7023157ba21SRui Paulo ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
7033157ba21SRui Paulo 		 const char *ifname, const char *desc)
7043157ba21SRui Paulo {
7053157ba21SRui Paulo 	HRESULT hr;
7063157ba21SRui Paulo 	IWbemObjectSink *pSink;
7073157ba21SRui Paulo 	struct ndis_events_data *events;
7083157ba21SRui Paulo 
7093157ba21SRui Paulo 	events = os_zalloc(sizeof(*events));
7103157ba21SRui Paulo 	if (events == NULL) {
7113157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
7123157ba21SRui Paulo 		return NULL;
7133157ba21SRui Paulo 	}
7143157ba21SRui Paulo 	events->ifname = os_strdup(ifname);
7153157ba21SRui Paulo 	if (events->ifname == NULL) {
7163157ba21SRui Paulo 		os_free(events);
7173157ba21SRui Paulo 		return NULL;
7183157ba21SRui Paulo 	}
7193157ba21SRui Paulo 
7203157ba21SRui Paulo 	if (wmi_refcnt++ == 0) {
7213157ba21SRui Paulo 		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
7223157ba21SRui Paulo 		if (FAILED(hr)) {
7233157ba21SRui Paulo 			wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
7243157ba21SRui Paulo 				   "returned 0x%x", (int) hr);
7253157ba21SRui Paulo 			os_free(events);
7263157ba21SRui Paulo 			return NULL;
7273157ba21SRui Paulo 		}
7283157ba21SRui Paulo 	}
7293157ba21SRui Paulo 
7303157ba21SRui Paulo 	if (wmi_first) {
7313157ba21SRui Paulo 		/* CoInitializeSecurity() must be called once and only once
7323157ba21SRui Paulo 		 * per process, so let's use wmi_first flag to protect against
7333157ba21SRui Paulo 		 * multiple calls. */
7343157ba21SRui Paulo 		wmi_first = 0;
7353157ba21SRui Paulo 
7363157ba21SRui Paulo 		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
7373157ba21SRui Paulo 					  RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
7383157ba21SRui Paulo 					  RPC_C_IMP_LEVEL_IMPERSONATE,
7393157ba21SRui Paulo 					  NULL, EOAC_SECURE_REFS, NULL);
7403157ba21SRui Paulo 		if (FAILED(hr)) {
7413157ba21SRui Paulo 			wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
7423157ba21SRui Paulo 				   "- returned 0x%x", (int) hr);
7433157ba21SRui Paulo 			os_free(events);
7443157ba21SRui Paulo 			return NULL;
7453157ba21SRui Paulo 		}
7463157ba21SRui Paulo 	}
7473157ba21SRui Paulo 
7483157ba21SRui Paulo 	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
7493157ba21SRui Paulo 			      &IID_IWbemLocator,
7503157ba21SRui Paulo 			      (LPVOID *) (void *) &events->pLoc);
7513157ba21SRui Paulo 	if (FAILED(hr)) {
7523157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
7533157ba21SRui Paulo 			   "0x%x", (int) hr);
7543157ba21SRui Paulo 		CoUninitialize();
7553157ba21SRui Paulo 		os_free(events);
7563157ba21SRui Paulo 		return NULL;
7573157ba21SRui Paulo 	}
7583157ba21SRui Paulo 
7593157ba21SRui Paulo 	if (ndis_events_get_adapter(events, ifname, desc) < 0) {
7603157ba21SRui Paulo 		CoUninitialize();
7613157ba21SRui Paulo 		os_free(events);
7623157ba21SRui Paulo 		return NULL;
7633157ba21SRui Paulo 	}
7643157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
7653157ba21SRui Paulo 		   events->adapter_desc);
7663157ba21SRui Paulo 
7673157ba21SRui Paulo 	hr = call_IWbemLocator_ConnectServer(
7683157ba21SRui Paulo 		events->pLoc, L"ROOT\\WMI", NULL, NULL,
7693157ba21SRui Paulo 		0, 0, 0, 0, &events->pSvc);
7703157ba21SRui Paulo 	if (FAILED(hr)) {
7713157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "Could not connect to server - error "
7723157ba21SRui Paulo 			   "0x%x", (int) hr);
7733157ba21SRui Paulo 		CoUninitialize();
7743157ba21SRui Paulo 		os_free(events->adapter_desc);
7753157ba21SRui Paulo 		os_free(events);
7763157ba21SRui Paulo 		return NULL;
7773157ba21SRui Paulo 	}
7783157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
7793157ba21SRui Paulo 
7803157ba21SRui Paulo 	ndis_events_constructor(events);
7813157ba21SRui Paulo 	pSink = &events->sink;
7823157ba21SRui Paulo 	pSink->lpVtbl = &events->sink_vtbl;
7833157ba21SRui Paulo 	events->sink_vtbl.QueryInterface = ndis_events_query_interface;
7843157ba21SRui Paulo 	events->sink_vtbl.AddRef = ndis_events_add_ref;
7853157ba21SRui Paulo 	events->sink_vtbl.Release = ndis_events_release;
7863157ba21SRui Paulo 	events->sink_vtbl.Indicate = ndis_events_indicate;
7873157ba21SRui Paulo 	events->sink_vtbl.SetStatus = ndis_events_set_status;
7883157ba21SRui Paulo 
7893157ba21SRui Paulo 	if (register_async_notification(pSink, events->pSvc) < 0) {
7903157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "Failed to register async "
7913157ba21SRui Paulo 			   "notifications");
7923157ba21SRui Paulo 		ndis_events_destructor(events);
7933157ba21SRui Paulo 		os_free(events->adapter_desc);
7943157ba21SRui Paulo 		os_free(events);
7953157ba21SRui Paulo 		return NULL;
7963157ba21SRui Paulo 	}
7973157ba21SRui Paulo 
7983157ba21SRui Paulo 	*read_pipe = events->read_pipe;
7993157ba21SRui Paulo 	*event_avail = events->event_avail;
8003157ba21SRui Paulo 
8013157ba21SRui Paulo 	return events;
8023157ba21SRui Paulo }
803