xref: /freebsd/contrib/wpa/src/drivers/ndis_events.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
13157ba21SRui Paulo /*
23157ba21SRui Paulo  * ndis_events - Receive NdisMIndicateStatus() events using WMI
33157ba21SRui Paulo  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
43157ba21SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui 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 {
375*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
376*a90b9d01SCy Schubert 				   "Unexpected event - __CLASS: '%S'",
377*a90b9d01SCy Schubert 				   vtClass.bstrVal);
3783157ba21SRui Paulo 		}
3793157ba21SRui Paulo 
3803157ba21SRui Paulo 		VariantClear(&vtClass);
3813157ba21SRui Paulo 	}
3823157ba21SRui Paulo 
3833157ba21SRui Paulo 	return WBEM_NO_ERROR;
3843157ba21SRui Paulo }
3853157ba21SRui Paulo 
3863157ba21SRui Paulo 
3873157ba21SRui Paulo static HRESULT STDMETHODCALLTYPE
ndis_events_set_status(IWbemObjectSink * this,long lFlags,HRESULT hResult,BSTR strParam,IWbemClassObject __RPC_FAR * pObjParam)3883157ba21SRui Paulo ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
3893157ba21SRui Paulo 		       BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
3903157ba21SRui Paulo {
3913157ba21SRui Paulo 	return WBEM_NO_ERROR;
3923157ba21SRui Paulo }
3933157ba21SRui Paulo 
3943157ba21SRui Paulo 
notification_query(IWbemObjectSink * pDestSink,IWbemServices * pSvc,const char * class_name)3953157ba21SRui Paulo static int notification_query(IWbemObjectSink *pDestSink,
3963157ba21SRui Paulo 			      IWbemServices *pSvc, const char *class_name)
3973157ba21SRui Paulo {
3983157ba21SRui Paulo 	HRESULT hr;
3993157ba21SRui Paulo 	WCHAR query[256];
4003157ba21SRui Paulo 
4013157ba21SRui Paulo 	_snwprintf(query, 256,
4023157ba21SRui Paulo 		  L"SELECT * FROM %S", class_name);
4033157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
4043157ba21SRui Paulo 	hr = call_IWbemServices_ExecNotificationQueryAsync(
4053157ba21SRui Paulo 		pSvc, L"WQL", query, 0, 0, pDestSink);
4063157ba21SRui Paulo 	if (FAILED(hr)) {
4073157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
4083157ba21SRui Paulo 			   "failed with hresult of 0x%x",
4093157ba21SRui Paulo 			   class_name, (int) hr);
4103157ba21SRui Paulo 		return -1;
4113157ba21SRui Paulo 	}
4123157ba21SRui Paulo 
4133157ba21SRui Paulo 	return 0;
4143157ba21SRui Paulo }
4153157ba21SRui Paulo 
4163157ba21SRui Paulo 
register_async_notification(IWbemObjectSink * pDestSink,IWbemServices * pSvc)4173157ba21SRui Paulo static int register_async_notification(IWbemObjectSink *pDestSink,
4183157ba21SRui Paulo 				       IWbemServices *pSvc)
4193157ba21SRui Paulo {
4203157ba21SRui Paulo 	int i;
4213157ba21SRui Paulo 	const char *class_list[] = {
4223157ba21SRui Paulo 		"MSNdis_StatusMediaConnect",
4233157ba21SRui Paulo 		"MSNdis_StatusMediaDisconnect",
4243157ba21SRui Paulo 		"MSNdis_StatusMediaSpecificIndication",
4253157ba21SRui Paulo 		"MSNdis_NotifyAdapterArrival",
4263157ba21SRui Paulo 		"MSNdis_NotifyAdapterRemoval",
4273157ba21SRui Paulo 		NULL
4283157ba21SRui Paulo 	};
4293157ba21SRui Paulo 
4303157ba21SRui Paulo 	for (i = 0; class_list[i]; i++) {
4313157ba21SRui Paulo 		if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
4323157ba21SRui Paulo 			return -1;
4333157ba21SRui Paulo 	}
4343157ba21SRui Paulo 
4353157ba21SRui Paulo 	return 0;
4363157ba21SRui Paulo }
4373157ba21SRui Paulo 
4383157ba21SRui Paulo 
ndis_events_deinit(struct ndis_events_data * events)4393157ba21SRui Paulo void ndis_events_deinit(struct ndis_events_data *events)
4403157ba21SRui Paulo {
4413157ba21SRui Paulo 	events->terminating = 1;
4423157ba21SRui Paulo 	IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
4433157ba21SRui Paulo 	IWbemObjectSink_Release(&events->sink);
4443157ba21SRui Paulo 	/*
4453157ba21SRui Paulo 	 * Rest of deinitialization is done in ndis_events_destructor() once
4463157ba21SRui Paulo 	 * all reference count drops to zero.
4473157ba21SRui Paulo 	 */
4483157ba21SRui Paulo }
4493157ba21SRui Paulo 
4503157ba21SRui Paulo 
ndis_events_use_desc(struct ndis_events_data * events,const char * desc)4513157ba21SRui Paulo static int ndis_events_use_desc(struct ndis_events_data *events,
4523157ba21SRui Paulo 				const char *desc)
4533157ba21SRui Paulo {
4543157ba21SRui Paulo 	char *tmp, *pos;
4553157ba21SRui Paulo 	size_t len;
4563157ba21SRui Paulo 
4573157ba21SRui Paulo 	if (desc == NULL) {
4583157ba21SRui Paulo 		if (events->adapter_desc == NULL)
4593157ba21SRui Paulo 			return -1;
4603157ba21SRui Paulo 		/* Continue using old description */
4613157ba21SRui Paulo 		return 0;
4623157ba21SRui Paulo 	}
4633157ba21SRui Paulo 
4643157ba21SRui Paulo 	tmp = os_strdup(desc);
4653157ba21SRui Paulo 	if (tmp == NULL)
4663157ba21SRui Paulo 		return -1;
4673157ba21SRui Paulo 
4683157ba21SRui Paulo 	pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
4693157ba21SRui Paulo 	if (pos)
4703157ba21SRui Paulo 		*pos = '\0';
4713157ba21SRui Paulo 
4723157ba21SRui Paulo 	len = os_strlen(tmp);
4733157ba21SRui Paulo 	events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
4743157ba21SRui Paulo 	if (events->adapter_desc == NULL) {
4753157ba21SRui Paulo 		os_free(tmp);
4763157ba21SRui Paulo 		return -1;
4773157ba21SRui Paulo 	}
4783157ba21SRui Paulo 	_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
4793157ba21SRui Paulo 	os_free(tmp);
4803157ba21SRui Paulo 	return 0;
4813157ba21SRui Paulo }
4823157ba21SRui Paulo 
4833157ba21SRui Paulo 
ndis_events_get_adapter(struct ndis_events_data * events,const char * ifname,const char * desc)4843157ba21SRui Paulo static int ndis_events_get_adapter(struct ndis_events_data *events,
4853157ba21SRui Paulo 				   const char *ifname, const char *desc)
4863157ba21SRui Paulo {
4873157ba21SRui Paulo 	HRESULT hr;
4883157ba21SRui Paulo 	IWbemServices *pSvc;
4893157ba21SRui Paulo #define MAX_QUERY_LEN 256
4903157ba21SRui Paulo 	WCHAR query[MAX_QUERY_LEN];
4913157ba21SRui Paulo 	IEnumWbemClassObject *pEnumerator;
4923157ba21SRui Paulo 	IWbemClassObject *pObj;
4933157ba21SRui Paulo 	ULONG uReturned;
4943157ba21SRui Paulo 	VARIANT vt;
4953157ba21SRui Paulo 	int len, pos;
4963157ba21SRui Paulo 
4973157ba21SRui Paulo 	/*
4983157ba21SRui Paulo 	 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
4993157ba21SRui Paulo 	 * to have better probability of matching with InstanceName from
5003157ba21SRui Paulo 	 * MSNdis events. If this fails, use the provided description.
5013157ba21SRui Paulo 	 */
5023157ba21SRui Paulo 
5033157ba21SRui Paulo 	os_free(events->adapter_desc);
5043157ba21SRui Paulo 	events->adapter_desc = NULL;
5053157ba21SRui Paulo 
5063157ba21SRui Paulo 	hr = call_IWbemLocator_ConnectServer(
5073157ba21SRui Paulo 		events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
5083157ba21SRui Paulo 	if (FAILED(hr)) {
5093157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
5103157ba21SRui Paulo 			   "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
5113157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5123157ba21SRui Paulo 	}
5133157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
5143157ba21SRui Paulo 
5153157ba21SRui Paulo 	_snwprintf(query, MAX_QUERY_LEN,
5163157ba21SRui Paulo 		  L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
5173157ba21SRui Paulo 		  L"WHERE SettingID='%S'", ifname);
5183157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
5193157ba21SRui Paulo 
5203157ba21SRui Paulo 	hr = call_IWbemServices_ExecQuery(
5213157ba21SRui Paulo 		pSvc, L"WQL", query,
5223157ba21SRui Paulo 		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
5233157ba21SRui Paulo 		NULL, &pEnumerator);
5243157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5253157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
5263157ba21SRui Paulo 			   "GUID from Win32_NetworkAdapterConfiguration: "
5273157ba21SRui Paulo 			   "0x%x", (int) hr);
5283157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5293157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5303157ba21SRui Paulo 	}
5313157ba21SRui Paulo 
5323157ba21SRui Paulo 	uReturned = 0;
5333157ba21SRui Paulo 	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
5343157ba21SRui Paulo 				       &pObj, &uReturned);
5353157ba21SRui Paulo 	if (!SUCCEEDED(hr) || uReturned == 0) {
5363157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
5373157ba21SRui Paulo 			   "GUID from Win32_NetworkAdapterConfiguration: "
5383157ba21SRui Paulo 			   "0x%x", (int) hr);
5393157ba21SRui Paulo 		IEnumWbemClassObject_Release(pEnumerator);
5403157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5413157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5423157ba21SRui Paulo 	}
5433157ba21SRui Paulo 	IEnumWbemClassObject_Release(pEnumerator);
5443157ba21SRui Paulo 
5453157ba21SRui Paulo 	VariantInit(&vt);
5463157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
5473157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5483157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
5493157ba21SRui Paulo 			   "Win32_NetworkAdapterConfiguration: 0x%x",
5503157ba21SRui Paulo 			   (int) hr);
5513157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5523157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5533157ba21SRui Paulo 	}
5543157ba21SRui Paulo 
5553157ba21SRui Paulo 	_snwprintf(query, MAX_QUERY_LEN,
5563157ba21SRui Paulo 		  L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
5573157ba21SRui Paulo 		  L"Index=%d",
5583157ba21SRui Paulo 		  vt.uintVal);
5593157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
5603157ba21SRui Paulo 	VariantClear(&vt);
5613157ba21SRui Paulo 	IWbemClassObject_Release(pObj);
5623157ba21SRui Paulo 
5633157ba21SRui Paulo 	hr = call_IWbemServices_ExecQuery(
5643157ba21SRui Paulo 		pSvc, L"WQL", query,
5653157ba21SRui Paulo 		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
5663157ba21SRui Paulo 		NULL, &pEnumerator);
5673157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5683157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
5693157ba21SRui Paulo 			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
5703157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5713157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5723157ba21SRui Paulo 	}
5733157ba21SRui Paulo 
5743157ba21SRui Paulo 	uReturned = 0;
5753157ba21SRui Paulo 	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
5763157ba21SRui Paulo 				       &pObj, &uReturned);
5773157ba21SRui Paulo 	if (!SUCCEEDED(hr) || uReturned == 0) {
5783157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
5793157ba21SRui Paulo 			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
5803157ba21SRui Paulo 		IEnumWbemClassObject_Release(pEnumerator);
5813157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5823157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5833157ba21SRui Paulo 	}
5843157ba21SRui Paulo 	IEnumWbemClassObject_Release(pEnumerator);
5853157ba21SRui Paulo 
5863157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
5873157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
5883157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
5893157ba21SRui Paulo 			   "Win32_NetworkAdapter: 0x%x", (int) hr);
5903157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
5913157ba21SRui Paulo 		IWbemServices_Release(pSvc);
5923157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
5933157ba21SRui Paulo 	}
5943157ba21SRui Paulo 
5953157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
5963157ba21SRui Paulo 		   vt.bstrVal);
5973157ba21SRui Paulo 	events->adapter_desc = _wcsdup(vt.bstrVal);
5983157ba21SRui Paulo 	VariantClear(&vt);
5993157ba21SRui Paulo 
6003157ba21SRui Paulo 	/*
6013157ba21SRui Paulo 	 * Try to get even better candidate for matching with InstanceName
6023157ba21SRui Paulo 	 * from Win32_PnPEntity. This is needed at least for some USB cards
6033157ba21SRui Paulo 	 * that can change the InstanceName whenever being unplugged and
6043157ba21SRui Paulo 	 * plugged again.
6053157ba21SRui Paulo 	 */
6063157ba21SRui Paulo 
6073157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
6083157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
6093157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
6103157ba21SRui Paulo 			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
6113157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
6123157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6133157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6143157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6153157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6163157ba21SRui Paulo 	}
6173157ba21SRui Paulo 
6183157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
6193157ba21SRui Paulo 		   "'%S'", vt.bstrVal);
6203157ba21SRui Paulo 
6213157ba21SRui Paulo 	len = _snwprintf(query, MAX_QUERY_LEN,
6223157ba21SRui Paulo 			L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
6233157ba21SRui Paulo 	if (len < 0 || len >= MAX_QUERY_LEN - 1) {
6243157ba21SRui Paulo 		VariantClear(&vt);
6253157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
6263157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6273157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6283157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6293157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6303157ba21SRui Paulo 	}
6313157ba21SRui Paulo 
6323157ba21SRui Paulo 	/* Escape \ as \\ */
6333157ba21SRui Paulo 	for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
6343157ba21SRui Paulo 		if (vt.bstrVal[pos] == '\\') {
6353157ba21SRui Paulo 			if (len >= MAX_QUERY_LEN - 3)
6363157ba21SRui Paulo 				break;
6373157ba21SRui Paulo 			query[len++] = '\\';
6383157ba21SRui Paulo 		}
6393157ba21SRui Paulo 		query[len++] = vt.bstrVal[pos];
6403157ba21SRui Paulo 	}
6413157ba21SRui Paulo 	query[len++] = L'\'';
6423157ba21SRui Paulo 	query[len] = L'\0';
6433157ba21SRui Paulo 	VariantClear(&vt);
6443157ba21SRui Paulo 	IWbemClassObject_Release(pObj);
6453157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
6463157ba21SRui Paulo 
6473157ba21SRui Paulo 	hr = call_IWbemServices_ExecQuery(
6483157ba21SRui Paulo 		pSvc, L"WQL", query,
6493157ba21SRui Paulo 		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
6503157ba21SRui Paulo 		NULL, &pEnumerator);
6513157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
6523157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
6533157ba21SRui Paulo 			   "Name from Win32_PnPEntity: 0x%x", (int) hr);
6543157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6553157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6563157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6573157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6583157ba21SRui Paulo 	}
6593157ba21SRui Paulo 
6603157ba21SRui Paulo 	uReturned = 0;
6613157ba21SRui Paulo 	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
6623157ba21SRui Paulo 				       &pObj, &uReturned);
6633157ba21SRui Paulo 	if (!SUCCEEDED(hr) || uReturned == 0) {
6643157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
6653157ba21SRui Paulo 			   "from Win32_PnPEntity: 0x%x", (int) hr);
6663157ba21SRui Paulo 		IEnumWbemClassObject_Release(pEnumerator);
6673157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6683157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6693157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6703157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6713157ba21SRui Paulo 	}
6723157ba21SRui Paulo 	IEnumWbemClassObject_Release(pEnumerator);
6733157ba21SRui Paulo 
6743157ba21SRui Paulo 	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
6753157ba21SRui Paulo 	if (!SUCCEEDED(hr)) {
6763157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
6773157ba21SRui Paulo 			   "Win32_PnPEntity: 0x%x", (int) hr);
6783157ba21SRui Paulo 		IWbemClassObject_Release(pObj);
6793157ba21SRui Paulo 		IWbemServices_Release(pSvc);
6803157ba21SRui Paulo 		if (events->adapter_desc == NULL)
6813157ba21SRui Paulo 			return ndis_events_use_desc(events, desc);
6823157ba21SRui Paulo 		return 0; /* use Win32_NetworkAdapter::Name */
6833157ba21SRui Paulo 	}
6843157ba21SRui Paulo 
6853157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
6863157ba21SRui Paulo 		   vt.bstrVal);
6873157ba21SRui Paulo 	os_free(events->adapter_desc);
6883157ba21SRui Paulo 	events->adapter_desc = _wcsdup(vt.bstrVal);
6893157ba21SRui Paulo 	VariantClear(&vt);
6903157ba21SRui Paulo 
6913157ba21SRui Paulo 	IWbemClassObject_Release(pObj);
6923157ba21SRui Paulo 
6933157ba21SRui Paulo 	IWbemServices_Release(pSvc);
6943157ba21SRui Paulo 
6953157ba21SRui Paulo 	if (events->adapter_desc == NULL)
6963157ba21SRui Paulo 		return ndis_events_use_desc(events, desc);
6973157ba21SRui Paulo 
6983157ba21SRui Paulo 	return 0;
6993157ba21SRui Paulo }
7003157ba21SRui Paulo 
7013157ba21SRui Paulo 
7023157ba21SRui Paulo struct ndis_events_data *
ndis_events_init(HANDLE * read_pipe,HANDLE * event_avail,const char * ifname,const char * desc)7033157ba21SRui Paulo ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
7043157ba21SRui Paulo 		 const char *ifname, const char *desc)
7053157ba21SRui Paulo {
7063157ba21SRui Paulo 	HRESULT hr;
7073157ba21SRui Paulo 	IWbemObjectSink *pSink;
7083157ba21SRui Paulo 	struct ndis_events_data *events;
7093157ba21SRui Paulo 
7103157ba21SRui Paulo 	events = os_zalloc(sizeof(*events));
7113157ba21SRui Paulo 	if (events == NULL) {
7123157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
7133157ba21SRui Paulo 		return NULL;
7143157ba21SRui Paulo 	}
7153157ba21SRui Paulo 	events->ifname = os_strdup(ifname);
7163157ba21SRui Paulo 	if (events->ifname == NULL) {
7173157ba21SRui Paulo 		os_free(events);
7183157ba21SRui Paulo 		return NULL;
7193157ba21SRui Paulo 	}
7203157ba21SRui Paulo 
7213157ba21SRui Paulo 	if (wmi_refcnt++ == 0) {
7223157ba21SRui Paulo 		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
7233157ba21SRui Paulo 		if (FAILED(hr)) {
7243157ba21SRui Paulo 			wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
7253157ba21SRui Paulo 				   "returned 0x%x", (int) hr);
7263157ba21SRui Paulo 			os_free(events);
7273157ba21SRui Paulo 			return NULL;
7283157ba21SRui Paulo 		}
7293157ba21SRui Paulo 	}
7303157ba21SRui Paulo 
7313157ba21SRui Paulo 	if (wmi_first) {
7323157ba21SRui Paulo 		/* CoInitializeSecurity() must be called once and only once
7333157ba21SRui Paulo 		 * per process, so let's use wmi_first flag to protect against
7343157ba21SRui Paulo 		 * multiple calls. */
7353157ba21SRui Paulo 		wmi_first = 0;
7363157ba21SRui Paulo 
7373157ba21SRui Paulo 		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
7383157ba21SRui Paulo 					  RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
7393157ba21SRui Paulo 					  RPC_C_IMP_LEVEL_IMPERSONATE,
7403157ba21SRui Paulo 					  NULL, EOAC_SECURE_REFS, NULL);
7413157ba21SRui Paulo 		if (FAILED(hr)) {
7423157ba21SRui Paulo 			wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
7433157ba21SRui Paulo 				   "- returned 0x%x", (int) hr);
7443157ba21SRui Paulo 			os_free(events);
7453157ba21SRui Paulo 			return NULL;
7463157ba21SRui Paulo 		}
7473157ba21SRui Paulo 	}
7483157ba21SRui Paulo 
7493157ba21SRui Paulo 	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
7503157ba21SRui Paulo 			      &IID_IWbemLocator,
7513157ba21SRui Paulo 			      (LPVOID *) (void *) &events->pLoc);
7523157ba21SRui Paulo 	if (FAILED(hr)) {
7533157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
7543157ba21SRui Paulo 			   "0x%x", (int) hr);
7553157ba21SRui Paulo 		CoUninitialize();
7563157ba21SRui Paulo 		os_free(events);
7573157ba21SRui Paulo 		return NULL;
7583157ba21SRui Paulo 	}
7593157ba21SRui Paulo 
7603157ba21SRui Paulo 	if (ndis_events_get_adapter(events, ifname, desc) < 0) {
7613157ba21SRui Paulo 		CoUninitialize();
7623157ba21SRui Paulo 		os_free(events);
7633157ba21SRui Paulo 		return NULL;
7643157ba21SRui Paulo 	}
7653157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
7663157ba21SRui Paulo 		   events->adapter_desc);
7673157ba21SRui Paulo 
7683157ba21SRui Paulo 	hr = call_IWbemLocator_ConnectServer(
7693157ba21SRui Paulo 		events->pLoc, L"ROOT\\WMI", NULL, NULL,
7703157ba21SRui Paulo 		0, 0, 0, 0, &events->pSvc);
7713157ba21SRui Paulo 	if (FAILED(hr)) {
7723157ba21SRui Paulo 		wpa_printf(MSG_ERROR, "Could not connect to server - error "
7733157ba21SRui Paulo 			   "0x%x", (int) hr);
7743157ba21SRui Paulo 		CoUninitialize();
7753157ba21SRui Paulo 		os_free(events->adapter_desc);
7763157ba21SRui Paulo 		os_free(events);
7773157ba21SRui Paulo 		return NULL;
7783157ba21SRui Paulo 	}
7793157ba21SRui Paulo 	wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
7803157ba21SRui Paulo 
7813157ba21SRui Paulo 	ndis_events_constructor(events);
7823157ba21SRui Paulo 	pSink = &events->sink;
7833157ba21SRui Paulo 	pSink->lpVtbl = &events->sink_vtbl;
7843157ba21SRui Paulo 	events->sink_vtbl.QueryInterface = ndis_events_query_interface;
7853157ba21SRui Paulo 	events->sink_vtbl.AddRef = ndis_events_add_ref;
7863157ba21SRui Paulo 	events->sink_vtbl.Release = ndis_events_release;
7873157ba21SRui Paulo 	events->sink_vtbl.Indicate = ndis_events_indicate;
7883157ba21SRui Paulo 	events->sink_vtbl.SetStatus = ndis_events_set_status;
7893157ba21SRui Paulo 
7903157ba21SRui Paulo 	if (register_async_notification(pSink, events->pSvc) < 0) {
7913157ba21SRui Paulo 		wpa_printf(MSG_DEBUG, "Failed to register async "
7923157ba21SRui Paulo 			   "notifications");
7933157ba21SRui Paulo 		ndis_events_destructor(events);
7943157ba21SRui Paulo 		os_free(events->adapter_desc);
7953157ba21SRui Paulo 		os_free(events);
7963157ba21SRui Paulo 		return NULL;
7973157ba21SRui Paulo 	}
7983157ba21SRui Paulo 
7993157ba21SRui Paulo 	*read_pipe = events->read_pipe;
8003157ba21SRui Paulo 	*event_avail = events->event_avail;
8013157ba21SRui Paulo 
8023157ba21SRui Paulo 	return events;
8033157ba21SRui Paulo }
804