1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * ndis_events - Receive NdisMIndicateStatus() events using WMI
3e5b75505Sopenharmony_ci * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#define _WIN32_WINNT    0x0400
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "includes.h"
12e5b75505Sopenharmony_ci
13e5b75505Sopenharmony_ci#ifndef COBJMACROS
14e5b75505Sopenharmony_ci#define COBJMACROS
15e5b75505Sopenharmony_ci#endif /* COBJMACROS */
16e5b75505Sopenharmony_ci#include <wbemidl.h>
17e5b75505Sopenharmony_ci
18e5b75505Sopenharmony_ci#include "common.h"
19e5b75505Sopenharmony_ci
20e5b75505Sopenharmony_ci
21e5b75505Sopenharmony_cistatic int wmi_refcnt = 0;
22e5b75505Sopenharmony_cistatic int wmi_first = 1;
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_cistruct ndis_events_data {
25e5b75505Sopenharmony_ci	IWbemObjectSink sink;
26e5b75505Sopenharmony_ci	IWbemObjectSinkVtbl sink_vtbl;
27e5b75505Sopenharmony_ci
28e5b75505Sopenharmony_ci	IWbemServices *pSvc;
29e5b75505Sopenharmony_ci	IWbemLocator *pLoc;
30e5b75505Sopenharmony_ci
31e5b75505Sopenharmony_ci	HANDLE read_pipe, write_pipe, event_avail;
32e5b75505Sopenharmony_ci	UINT ref;
33e5b75505Sopenharmony_ci	int terminating;
34e5b75505Sopenharmony_ci	char *ifname; /* {GUID..} */
35e5b75505Sopenharmony_ci	WCHAR *adapter_desc;
36e5b75505Sopenharmony_ci};
37e5b75505Sopenharmony_ci
38e5b75505Sopenharmony_ci#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
39e5b75505Sopenharmony_ci#define BstrFree(x) if (x) SysFreeString(x)
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_ci/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
42e5b75505Sopenharmony_ci * BSTRs */
43e5b75505Sopenharmony_ciHRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
44e5b75505Sopenharmony_ci	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
45e5b75505Sopenharmony_ci	long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
46e5b75505Sopenharmony_ci{
47e5b75505Sopenharmony_ci	BSTR bsQueryLanguage, bsQuery;
48e5b75505Sopenharmony_ci	HRESULT hr;
49e5b75505Sopenharmony_ci
50e5b75505Sopenharmony_ci	bsQueryLanguage = BstrAlloc(strQueryLanguage);
51e5b75505Sopenharmony_ci	bsQuery = BstrAlloc(strQuery);
52e5b75505Sopenharmony_ci
53e5b75505Sopenharmony_ci	hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
54e5b75505Sopenharmony_ci				     pCtx, ppEnum);
55e5b75505Sopenharmony_ci
56e5b75505Sopenharmony_ci	BstrFree(bsQueryLanguage);
57e5b75505Sopenharmony_ci	BstrFree(bsQuery);
58e5b75505Sopenharmony_ci
59e5b75505Sopenharmony_ci	return hr;
60e5b75505Sopenharmony_ci}
61e5b75505Sopenharmony_ci
62e5b75505Sopenharmony_ci
63e5b75505Sopenharmony_ciHRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
64e5b75505Sopenharmony_ci	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
65e5b75505Sopenharmony_ci	long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
66e5b75505Sopenharmony_ci{
67e5b75505Sopenharmony_ci	BSTR bsQueryLanguage, bsQuery;
68e5b75505Sopenharmony_ci	HRESULT hr;
69e5b75505Sopenharmony_ci
70e5b75505Sopenharmony_ci	bsQueryLanguage = BstrAlloc(strQueryLanguage);
71e5b75505Sopenharmony_ci	bsQuery = BstrAlloc(strQuery);
72e5b75505Sopenharmony_ci
73e5b75505Sopenharmony_ci	hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
74e5b75505Sopenharmony_ci						      bsQuery, lFlags, pCtx,
75e5b75505Sopenharmony_ci						      pResponseHandler);
76e5b75505Sopenharmony_ci
77e5b75505Sopenharmony_ci	BstrFree(bsQueryLanguage);
78e5b75505Sopenharmony_ci	BstrFree(bsQuery);
79e5b75505Sopenharmony_ci
80e5b75505Sopenharmony_ci	return hr;
81e5b75505Sopenharmony_ci}
82e5b75505Sopenharmony_ci
83e5b75505Sopenharmony_ci
84e5b75505Sopenharmony_ciHRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
85e5b75505Sopenharmony_ci	IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
86e5b75505Sopenharmony_ci	LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
87e5b75505Sopenharmony_ci	LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
88e5b75505Sopenharmony_ci{
89e5b75505Sopenharmony_ci	BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
90e5b75505Sopenharmony_ci	HRESULT hr;
91e5b75505Sopenharmony_ci
92e5b75505Sopenharmony_ci	bsNetworkResource = BstrAlloc(strNetworkResource);
93e5b75505Sopenharmony_ci	bsUser = BstrAlloc(strUser);
94e5b75505Sopenharmony_ci	bsPassword = BstrAlloc(strPassword);
95e5b75505Sopenharmony_ci	bsLocale = BstrAlloc(strLocale);
96e5b75505Sopenharmony_ci	bsAuthority = BstrAlloc(strAuthority);
97e5b75505Sopenharmony_ci
98e5b75505Sopenharmony_ci	hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
99e5b75505Sopenharmony_ci					bsPassword, bsLocale, lSecurityFlags,
100e5b75505Sopenharmony_ci					bsAuthority, pCtx, ppNamespace);
101e5b75505Sopenharmony_ci
102e5b75505Sopenharmony_ci	BstrFree(bsNetworkResource);
103e5b75505Sopenharmony_ci	BstrFree(bsUser);
104e5b75505Sopenharmony_ci	BstrFree(bsPassword);
105e5b75505Sopenharmony_ci	BstrFree(bsLocale);
106e5b75505Sopenharmony_ci	BstrFree(bsAuthority);
107e5b75505Sopenharmony_ci
108e5b75505Sopenharmony_ci	return hr;
109e5b75505Sopenharmony_ci}
110e5b75505Sopenharmony_ci
111e5b75505Sopenharmony_ci
112e5b75505Sopenharmony_cienum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
113e5b75505Sopenharmony_ci		   EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
114e5b75505Sopenharmony_ci
115e5b75505Sopenharmony_cistatic int ndis_events_get_adapter(struct ndis_events_data *events,
116e5b75505Sopenharmony_ci				   const char *ifname, const char *desc);
117e5b75505Sopenharmony_ci
118e5b75505Sopenharmony_ci
119e5b75505Sopenharmony_cistatic int ndis_events_constructor(struct ndis_events_data *events)
120e5b75505Sopenharmony_ci{
121e5b75505Sopenharmony_ci	events->ref = 1;
122e5b75505Sopenharmony_ci
123e5b75505Sopenharmony_ci	if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
124e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
125e5b75505Sopenharmony_ci			   (int) GetLastError());
126e5b75505Sopenharmony_ci		return -1;
127e5b75505Sopenharmony_ci	}
128e5b75505Sopenharmony_ci	events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
129e5b75505Sopenharmony_ci	if (events->event_avail == NULL) {
130e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
131e5b75505Sopenharmony_ci			   (int) GetLastError());
132e5b75505Sopenharmony_ci		CloseHandle(events->read_pipe);
133e5b75505Sopenharmony_ci		CloseHandle(events->write_pipe);
134e5b75505Sopenharmony_ci		return -1;
135e5b75505Sopenharmony_ci	}
136e5b75505Sopenharmony_ci
137e5b75505Sopenharmony_ci	return 0;
138e5b75505Sopenharmony_ci}
139e5b75505Sopenharmony_ci
140e5b75505Sopenharmony_ci
141e5b75505Sopenharmony_cistatic void ndis_events_destructor(struct ndis_events_data *events)
142e5b75505Sopenharmony_ci{
143e5b75505Sopenharmony_ci	CloseHandle(events->read_pipe);
144e5b75505Sopenharmony_ci	CloseHandle(events->write_pipe);
145e5b75505Sopenharmony_ci	CloseHandle(events->event_avail);
146e5b75505Sopenharmony_ci	IWbemServices_Release(events->pSvc);
147e5b75505Sopenharmony_ci	IWbemLocator_Release(events->pLoc);
148e5b75505Sopenharmony_ci	if (--wmi_refcnt == 0)
149e5b75505Sopenharmony_ci		CoUninitialize();
150e5b75505Sopenharmony_ci}
151e5b75505Sopenharmony_ci
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_cistatic HRESULT STDMETHODCALLTYPE
154e5b75505Sopenharmony_cindis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
155e5b75505Sopenharmony_ci{
156e5b75505Sopenharmony_ci	*obj = NULL;
157e5b75505Sopenharmony_ci
158e5b75505Sopenharmony_ci	if (IsEqualIID(riid, &IID_IUnknown) ||
159e5b75505Sopenharmony_ci	    IsEqualIID(riid, &IID_IWbemObjectSink)) {
160e5b75505Sopenharmony_ci		*obj = this;
161e5b75505Sopenharmony_ci		IWbemObjectSink_AddRef(this);
162e5b75505Sopenharmony_ci		return NOERROR;
163e5b75505Sopenharmony_ci	}
164e5b75505Sopenharmony_ci
165e5b75505Sopenharmony_ci	return E_NOINTERFACE;
166e5b75505Sopenharmony_ci}
167e5b75505Sopenharmony_ci
168e5b75505Sopenharmony_ci
169e5b75505Sopenharmony_cistatic ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
170e5b75505Sopenharmony_ci{
171e5b75505Sopenharmony_ci	struct ndis_events_data *events = (struct ndis_events_data *) this;
172e5b75505Sopenharmony_ci	return ++events->ref;
173e5b75505Sopenharmony_ci}
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_ci
176e5b75505Sopenharmony_cistatic ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
177e5b75505Sopenharmony_ci{
178e5b75505Sopenharmony_ci	struct ndis_events_data *events = (struct ndis_events_data *) this;
179e5b75505Sopenharmony_ci
180e5b75505Sopenharmony_ci	if (--events->ref != 0)
181e5b75505Sopenharmony_ci		return events->ref;
182e5b75505Sopenharmony_ci
183e5b75505Sopenharmony_ci	ndis_events_destructor(events);
184e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: terminated");
185e5b75505Sopenharmony_ci	os_free(events->adapter_desc);
186e5b75505Sopenharmony_ci	os_free(events->ifname);
187e5b75505Sopenharmony_ci	os_free(events);
188e5b75505Sopenharmony_ci	return 0;
189e5b75505Sopenharmony_ci}
190e5b75505Sopenharmony_ci
191e5b75505Sopenharmony_ci
192e5b75505Sopenharmony_cistatic int ndis_events_send_event(struct ndis_events_data *events,
193e5b75505Sopenharmony_ci				  enum event_types type,
194e5b75505Sopenharmony_ci				  char *data, size_t data_len)
195e5b75505Sopenharmony_ci{
196e5b75505Sopenharmony_ci	char buf[512], *pos, *end;
197e5b75505Sopenharmony_ci	int _type;
198e5b75505Sopenharmony_ci	DWORD written;
199e5b75505Sopenharmony_ci
200e5b75505Sopenharmony_ci	end = buf + sizeof(buf);
201e5b75505Sopenharmony_ci	_type = (int) type;
202e5b75505Sopenharmony_ci	os_memcpy(buf, &_type, sizeof(_type));
203e5b75505Sopenharmony_ci	pos = buf + sizeof(_type);
204e5b75505Sopenharmony_ci
205e5b75505Sopenharmony_ci	if (data) {
206e5b75505Sopenharmony_ci		if (2 + data_len > (size_t) (end - pos)) {
207e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Not enough room for send_event "
208e5b75505Sopenharmony_ci				   "data (%d)", data_len);
209e5b75505Sopenharmony_ci			return -1;
210e5b75505Sopenharmony_ci		}
211e5b75505Sopenharmony_ci		*pos++ = data_len >> 8;
212e5b75505Sopenharmony_ci		*pos++ = data_len & 0xff;
213e5b75505Sopenharmony_ci		os_memcpy(pos, data, data_len);
214e5b75505Sopenharmony_ci		pos += data_len;
215e5b75505Sopenharmony_ci	}
216e5b75505Sopenharmony_ci
217e5b75505Sopenharmony_ci	if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
218e5b75505Sopenharmony_ci		SetEvent(events->event_avail);
219e5b75505Sopenharmony_ci		return 0;
220e5b75505Sopenharmony_ci	}
221e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
222e5b75505Sopenharmony_ci	return -1;
223e5b75505Sopenharmony_ci}
224e5b75505Sopenharmony_ci
225e5b75505Sopenharmony_ci
226e5b75505Sopenharmony_cistatic void ndis_events_media_connect(struct ndis_events_data *events)
227e5b75505Sopenharmony_ci{
228e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
229e5b75505Sopenharmony_ci	ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
230e5b75505Sopenharmony_ci}
231e5b75505Sopenharmony_ci
232e5b75505Sopenharmony_ci
233e5b75505Sopenharmony_cistatic void ndis_events_media_disconnect(struct ndis_events_data *events)
234e5b75505Sopenharmony_ci{
235e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
236e5b75505Sopenharmony_ci	ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
237e5b75505Sopenharmony_ci}
238e5b75505Sopenharmony_ci
239e5b75505Sopenharmony_ci
240e5b75505Sopenharmony_cistatic void ndis_events_media_specific(struct ndis_events_data *events,
241e5b75505Sopenharmony_ci				       IWbemClassObject *pObj)
242e5b75505Sopenharmony_ci{
243e5b75505Sopenharmony_ci	VARIANT vt;
244e5b75505Sopenharmony_ci	HRESULT hr;
245e5b75505Sopenharmony_ci	LONG lower, upper, k;
246e5b75505Sopenharmony_ci	UCHAR ch;
247e5b75505Sopenharmony_ci	char *data, *pos;
248e5b75505Sopenharmony_ci	size_t data_len;
249e5b75505Sopenharmony_ci
250e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
251e5b75505Sopenharmony_ci
252e5b75505Sopenharmony_ci	/* This is the StatusBuffer from NdisMIndicateStatus() call */
253e5b75505Sopenharmony_ci	hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
254e5b75505Sopenharmony_ci				  0, &vt, NULL, NULL);
255e5b75505Sopenharmony_ci	if (FAILED(hr)) {
256e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "Could not get "
257e5b75505Sopenharmony_ci			   "NdisStatusMediaSpecificIndication from "
258e5b75505Sopenharmony_ci			   "the object?!");
259e5b75505Sopenharmony_ci		return;
260e5b75505Sopenharmony_ci	}
261e5b75505Sopenharmony_ci
262e5b75505Sopenharmony_ci	SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
263e5b75505Sopenharmony_ci	SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
264e5b75505Sopenharmony_ci	data_len = upper - lower + 1;
265e5b75505Sopenharmony_ci	data = os_malloc(data_len);
266e5b75505Sopenharmony_ci	if (data == NULL) {
267e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
268e5b75505Sopenharmony_ci			   "data");
269e5b75505Sopenharmony_ci		VariantClear(&vt);
270e5b75505Sopenharmony_ci		return;
271e5b75505Sopenharmony_ci	}
272e5b75505Sopenharmony_ci
273e5b75505Sopenharmony_ci	pos = data;
274e5b75505Sopenharmony_ci	for (k = lower; k <= upper; k++) {
275e5b75505Sopenharmony_ci		SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
276e5b75505Sopenharmony_ci		*pos++ = ch;
277e5b75505Sopenharmony_ci	}
278e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
279e5b75505Sopenharmony_ci
280e5b75505Sopenharmony_ci	VariantClear(&vt);
281e5b75505Sopenharmony_ci
282e5b75505Sopenharmony_ci	ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
283e5b75505Sopenharmony_ci
284e5b75505Sopenharmony_ci	os_free(data);
285e5b75505Sopenharmony_ci}
286e5b75505Sopenharmony_ci
287e5b75505Sopenharmony_ci
288e5b75505Sopenharmony_cistatic void ndis_events_adapter_arrival(struct ndis_events_data *events)
289e5b75505Sopenharmony_ci{
290e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
291e5b75505Sopenharmony_ci	ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
292e5b75505Sopenharmony_ci}
293e5b75505Sopenharmony_ci
294e5b75505Sopenharmony_ci
295e5b75505Sopenharmony_cistatic void ndis_events_adapter_removal(struct ndis_events_data *events)
296e5b75505Sopenharmony_ci{
297e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
298e5b75505Sopenharmony_ci	ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
299e5b75505Sopenharmony_ci}
300e5b75505Sopenharmony_ci
301e5b75505Sopenharmony_ci
302e5b75505Sopenharmony_cistatic HRESULT STDMETHODCALLTYPE
303e5b75505Sopenharmony_cindis_events_indicate(IWbemObjectSink *this, long lObjectCount,
304e5b75505Sopenharmony_ci		     IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
305e5b75505Sopenharmony_ci{
306e5b75505Sopenharmony_ci	struct ndis_events_data *events = (struct ndis_events_data *) this;
307e5b75505Sopenharmony_ci	long i;
308e5b75505Sopenharmony_ci
309e5b75505Sopenharmony_ci	if (events->terminating) {
310e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
311e5b75505Sopenharmony_ci			   "indication - terminating");
312e5b75505Sopenharmony_ci		return WBEM_NO_ERROR;
313e5b75505Sopenharmony_ci	}
314e5b75505Sopenharmony_ci	/* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
315e5b75505Sopenharmony_ci	   lObjectCount); */
316e5b75505Sopenharmony_ci
317e5b75505Sopenharmony_ci	for (i = 0; i < lObjectCount; i++) {
318e5b75505Sopenharmony_ci		IWbemClassObject *pObj = ppObjArray[i];
319e5b75505Sopenharmony_ci		HRESULT hr;
320e5b75505Sopenharmony_ci		VARIANT vtClass, vt;
321e5b75505Sopenharmony_ci
322e5b75505Sopenharmony_ci		hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
323e5b75505Sopenharmony_ci					  NULL);
324e5b75505Sopenharmony_ci		if (FAILED(hr)) {
325e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
326e5b75505Sopenharmony_ci				   "event.");
327e5b75505Sopenharmony_ci			break;
328e5b75505Sopenharmony_ci		}
329e5b75505Sopenharmony_ci		/* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
330e5b75505Sopenharmony_ci
331e5b75505Sopenharmony_ci		hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
332e5b75505Sopenharmony_ci					  NULL);
333e5b75505Sopenharmony_ci		if (FAILED(hr)) {
334e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
335e5b75505Sopenharmony_ci				   "from event.");
336e5b75505Sopenharmony_ci			VariantClear(&vtClass);
337e5b75505Sopenharmony_ci			break;
338e5b75505Sopenharmony_ci		}
339e5b75505Sopenharmony_ci
340e5b75505Sopenharmony_ci		if (wcscmp(vtClass.bstrVal,
341e5b75505Sopenharmony_ci			   L"MSNdis_NotifyAdapterArrival") == 0) {
342e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
343e5b75505Sopenharmony_ci				   "update adapter description since it may "
344e5b75505Sopenharmony_ci				   "have changed with new adapter instance");
345e5b75505Sopenharmony_ci			ndis_events_get_adapter(events, events->ifname, NULL);
346e5b75505Sopenharmony_ci		}
347e5b75505Sopenharmony_ci
348e5b75505Sopenharmony_ci		if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
349e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
350e5b75505Sopenharmony_ci				   "indication for foreign adapter: "
351e5b75505Sopenharmony_ci				   "InstanceName: '%S' __CLASS: '%S'",
352e5b75505Sopenharmony_ci				   vt.bstrVal, vtClass.bstrVal);
353e5b75505Sopenharmony_ci			VariantClear(&vtClass);
354e5b75505Sopenharmony_ci			VariantClear(&vt);
355e5b75505Sopenharmony_ci			continue;
356e5b75505Sopenharmony_ci		}
357e5b75505Sopenharmony_ci		VariantClear(&vt);
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci		if (wcscmp(vtClass.bstrVal,
360e5b75505Sopenharmony_ci			   L"MSNdis_StatusMediaSpecificIndication") == 0) {
361e5b75505Sopenharmony_ci			ndis_events_media_specific(events, pObj);
362e5b75505Sopenharmony_ci		} else if (wcscmp(vtClass.bstrVal,
363e5b75505Sopenharmony_ci				  L"MSNdis_StatusMediaConnect") == 0) {
364e5b75505Sopenharmony_ci			ndis_events_media_connect(events);
365e5b75505Sopenharmony_ci		} else if (wcscmp(vtClass.bstrVal,
366e5b75505Sopenharmony_ci				  L"MSNdis_StatusMediaDisconnect") == 0) {
367e5b75505Sopenharmony_ci			ndis_events_media_disconnect(events);
368e5b75505Sopenharmony_ci		} else if (wcscmp(vtClass.bstrVal,
369e5b75505Sopenharmony_ci				  L"MSNdis_NotifyAdapterArrival") == 0) {
370e5b75505Sopenharmony_ci			ndis_events_adapter_arrival(events);
371e5b75505Sopenharmony_ci		} else if (wcscmp(vtClass.bstrVal,
372e5b75505Sopenharmony_ci				  L"MSNdis_NotifyAdapterRemoval") == 0) {
373e5b75505Sopenharmony_ci			ndis_events_adapter_removal(events);
374e5b75505Sopenharmony_ci		} else {
375e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
376e5b75505Sopenharmony_ci				   "'%S'", vtClass.bstrVal);
377e5b75505Sopenharmony_ci		}
378e5b75505Sopenharmony_ci
379e5b75505Sopenharmony_ci		VariantClear(&vtClass);
380e5b75505Sopenharmony_ci	}
381e5b75505Sopenharmony_ci
382e5b75505Sopenharmony_ci	return WBEM_NO_ERROR;
383e5b75505Sopenharmony_ci}
384e5b75505Sopenharmony_ci
385e5b75505Sopenharmony_ci
386e5b75505Sopenharmony_cistatic HRESULT STDMETHODCALLTYPE
387e5b75505Sopenharmony_cindis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
388e5b75505Sopenharmony_ci		       BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
389e5b75505Sopenharmony_ci{
390e5b75505Sopenharmony_ci	return WBEM_NO_ERROR;
391e5b75505Sopenharmony_ci}
392e5b75505Sopenharmony_ci
393e5b75505Sopenharmony_ci
394e5b75505Sopenharmony_cistatic int notification_query(IWbemObjectSink *pDestSink,
395e5b75505Sopenharmony_ci			      IWbemServices *pSvc, const char *class_name)
396e5b75505Sopenharmony_ci{
397e5b75505Sopenharmony_ci	HRESULT hr;
398e5b75505Sopenharmony_ci	WCHAR query[256];
399e5b75505Sopenharmony_ci
400e5b75505Sopenharmony_ci	_snwprintf(query, 256,
401e5b75505Sopenharmony_ci		  L"SELECT * FROM %S", class_name);
402e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
403e5b75505Sopenharmony_ci	hr = call_IWbemServices_ExecNotificationQueryAsync(
404e5b75505Sopenharmony_ci		pSvc, L"WQL", query, 0, 0, pDestSink);
405e5b75505Sopenharmony_ci	if (FAILED(hr)) {
406e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
407e5b75505Sopenharmony_ci			   "failed with hresult of 0x%x",
408e5b75505Sopenharmony_ci			   class_name, (int) hr);
409e5b75505Sopenharmony_ci		return -1;
410e5b75505Sopenharmony_ci	}
411e5b75505Sopenharmony_ci
412e5b75505Sopenharmony_ci	return 0;
413e5b75505Sopenharmony_ci}
414e5b75505Sopenharmony_ci
415e5b75505Sopenharmony_ci
416e5b75505Sopenharmony_cistatic int register_async_notification(IWbemObjectSink *pDestSink,
417e5b75505Sopenharmony_ci				       IWbemServices *pSvc)
418e5b75505Sopenharmony_ci{
419e5b75505Sopenharmony_ci	int i;
420e5b75505Sopenharmony_ci	const char *class_list[] = {
421e5b75505Sopenharmony_ci		"MSNdis_StatusMediaConnect",
422e5b75505Sopenharmony_ci		"MSNdis_StatusMediaDisconnect",
423e5b75505Sopenharmony_ci		"MSNdis_StatusMediaSpecificIndication",
424e5b75505Sopenharmony_ci		"MSNdis_NotifyAdapterArrival",
425e5b75505Sopenharmony_ci		"MSNdis_NotifyAdapterRemoval",
426e5b75505Sopenharmony_ci		NULL
427e5b75505Sopenharmony_ci	};
428e5b75505Sopenharmony_ci
429e5b75505Sopenharmony_ci	for (i = 0; class_list[i]; i++) {
430e5b75505Sopenharmony_ci		if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
431e5b75505Sopenharmony_ci			return -1;
432e5b75505Sopenharmony_ci	}
433e5b75505Sopenharmony_ci
434e5b75505Sopenharmony_ci	return 0;
435e5b75505Sopenharmony_ci}
436e5b75505Sopenharmony_ci
437e5b75505Sopenharmony_ci
438e5b75505Sopenharmony_civoid ndis_events_deinit(struct ndis_events_data *events)
439e5b75505Sopenharmony_ci{
440e5b75505Sopenharmony_ci	events->terminating = 1;
441e5b75505Sopenharmony_ci	IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
442e5b75505Sopenharmony_ci	IWbemObjectSink_Release(&events->sink);
443e5b75505Sopenharmony_ci	/*
444e5b75505Sopenharmony_ci	 * Rest of deinitialization is done in ndis_events_destructor() once
445e5b75505Sopenharmony_ci	 * all reference count drops to zero.
446e5b75505Sopenharmony_ci	 */
447e5b75505Sopenharmony_ci}
448e5b75505Sopenharmony_ci
449e5b75505Sopenharmony_ci
450e5b75505Sopenharmony_cistatic int ndis_events_use_desc(struct ndis_events_data *events,
451e5b75505Sopenharmony_ci				const char *desc)
452e5b75505Sopenharmony_ci{
453e5b75505Sopenharmony_ci	char *tmp, *pos;
454e5b75505Sopenharmony_ci	size_t len;
455e5b75505Sopenharmony_ci
456e5b75505Sopenharmony_ci	if (desc == NULL) {
457e5b75505Sopenharmony_ci		if (events->adapter_desc == NULL)
458e5b75505Sopenharmony_ci			return -1;
459e5b75505Sopenharmony_ci		/* Continue using old description */
460e5b75505Sopenharmony_ci		return 0;
461e5b75505Sopenharmony_ci	}
462e5b75505Sopenharmony_ci
463e5b75505Sopenharmony_ci	tmp = os_strdup(desc);
464e5b75505Sopenharmony_ci	if (tmp == NULL)
465e5b75505Sopenharmony_ci		return -1;
466e5b75505Sopenharmony_ci
467e5b75505Sopenharmony_ci	pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
468e5b75505Sopenharmony_ci	if (pos)
469e5b75505Sopenharmony_ci		*pos = '\0';
470e5b75505Sopenharmony_ci
471e5b75505Sopenharmony_ci	len = os_strlen(tmp);
472e5b75505Sopenharmony_ci	events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
473e5b75505Sopenharmony_ci	if (events->adapter_desc == NULL) {
474e5b75505Sopenharmony_ci		os_free(tmp);
475e5b75505Sopenharmony_ci		return -1;
476e5b75505Sopenharmony_ci	}
477e5b75505Sopenharmony_ci	_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
478e5b75505Sopenharmony_ci	os_free(tmp);
479e5b75505Sopenharmony_ci	return 0;
480e5b75505Sopenharmony_ci}
481e5b75505Sopenharmony_ci
482e5b75505Sopenharmony_ci
483e5b75505Sopenharmony_cistatic int ndis_events_get_adapter(struct ndis_events_data *events,
484e5b75505Sopenharmony_ci				   const char *ifname, const char *desc)
485e5b75505Sopenharmony_ci{
486e5b75505Sopenharmony_ci	HRESULT hr;
487e5b75505Sopenharmony_ci	IWbemServices *pSvc;
488e5b75505Sopenharmony_ci#define MAX_QUERY_LEN 256
489e5b75505Sopenharmony_ci	WCHAR query[MAX_QUERY_LEN];
490e5b75505Sopenharmony_ci	IEnumWbemClassObject *pEnumerator;
491e5b75505Sopenharmony_ci	IWbemClassObject *pObj;
492e5b75505Sopenharmony_ci	ULONG uReturned;
493e5b75505Sopenharmony_ci	VARIANT vt;
494e5b75505Sopenharmony_ci	int len, pos;
495e5b75505Sopenharmony_ci
496e5b75505Sopenharmony_ci	/*
497e5b75505Sopenharmony_ci	 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
498e5b75505Sopenharmony_ci	 * to have better probability of matching with InstanceName from
499e5b75505Sopenharmony_ci	 * MSNdis events. If this fails, use the provided description.
500e5b75505Sopenharmony_ci	 */
501e5b75505Sopenharmony_ci
502e5b75505Sopenharmony_ci	os_free(events->adapter_desc);
503e5b75505Sopenharmony_ci	events->adapter_desc = NULL;
504e5b75505Sopenharmony_ci
505e5b75505Sopenharmony_ci	hr = call_IWbemLocator_ConnectServer(
506e5b75505Sopenharmony_ci		events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
507e5b75505Sopenharmony_ci	if (FAILED(hr)) {
508e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
509e5b75505Sopenharmony_ci			   "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
510e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
511e5b75505Sopenharmony_ci	}
512e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
513e5b75505Sopenharmony_ci
514e5b75505Sopenharmony_ci	_snwprintf(query, MAX_QUERY_LEN,
515e5b75505Sopenharmony_ci		  L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
516e5b75505Sopenharmony_ci		  L"WHERE SettingID='%S'", ifname);
517e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
518e5b75505Sopenharmony_ci
519e5b75505Sopenharmony_ci	hr = call_IWbemServices_ExecQuery(
520e5b75505Sopenharmony_ci		pSvc, L"WQL", query,
521e5b75505Sopenharmony_ci		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
522e5b75505Sopenharmony_ci		NULL, &pEnumerator);
523e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
524e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
525e5b75505Sopenharmony_ci			   "GUID from Win32_NetworkAdapterConfiguration: "
526e5b75505Sopenharmony_ci			   "0x%x", (int) hr);
527e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
528e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
529e5b75505Sopenharmony_ci	}
530e5b75505Sopenharmony_ci
531e5b75505Sopenharmony_ci	uReturned = 0;
532e5b75505Sopenharmony_ci	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
533e5b75505Sopenharmony_ci				       &pObj, &uReturned);
534e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr) || uReturned == 0) {
535e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
536e5b75505Sopenharmony_ci			   "GUID from Win32_NetworkAdapterConfiguration: "
537e5b75505Sopenharmony_ci			   "0x%x", (int) hr);
538e5b75505Sopenharmony_ci		IEnumWbemClassObject_Release(pEnumerator);
539e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
540e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
541e5b75505Sopenharmony_ci	}
542e5b75505Sopenharmony_ci	IEnumWbemClassObject_Release(pEnumerator);
543e5b75505Sopenharmony_ci
544e5b75505Sopenharmony_ci	VariantInit(&vt);
545e5b75505Sopenharmony_ci	hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
546e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
547e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
548e5b75505Sopenharmony_ci			   "Win32_NetworkAdapterConfiguration: 0x%x",
549e5b75505Sopenharmony_ci			   (int) hr);
550e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
551e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
552e5b75505Sopenharmony_ci	}
553e5b75505Sopenharmony_ci
554e5b75505Sopenharmony_ci	_snwprintf(query, MAX_QUERY_LEN,
555e5b75505Sopenharmony_ci		  L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
556e5b75505Sopenharmony_ci		  L"Index=%d",
557e5b75505Sopenharmony_ci		  vt.uintVal);
558e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
559e5b75505Sopenharmony_ci	VariantClear(&vt);
560e5b75505Sopenharmony_ci	IWbemClassObject_Release(pObj);
561e5b75505Sopenharmony_ci
562e5b75505Sopenharmony_ci	hr = call_IWbemServices_ExecQuery(
563e5b75505Sopenharmony_ci		pSvc, L"WQL", query,
564e5b75505Sopenharmony_ci		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
565e5b75505Sopenharmony_ci		NULL, &pEnumerator);
566e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
567e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
568e5b75505Sopenharmony_ci			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
569e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
570e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
571e5b75505Sopenharmony_ci	}
572e5b75505Sopenharmony_ci
573e5b75505Sopenharmony_ci	uReturned = 0;
574e5b75505Sopenharmony_ci	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
575e5b75505Sopenharmony_ci				       &pObj, &uReturned);
576e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr) || uReturned == 0) {
577e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
578e5b75505Sopenharmony_ci			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
579e5b75505Sopenharmony_ci		IEnumWbemClassObject_Release(pEnumerator);
580e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
581e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
582e5b75505Sopenharmony_ci	}
583e5b75505Sopenharmony_ci	IEnumWbemClassObject_Release(pEnumerator);
584e5b75505Sopenharmony_ci
585e5b75505Sopenharmony_ci	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
586e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
587e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
588e5b75505Sopenharmony_ci			   "Win32_NetworkAdapter: 0x%x", (int) hr);
589e5b75505Sopenharmony_ci		IWbemClassObject_Release(pObj);
590e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
591e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
592e5b75505Sopenharmony_ci	}
593e5b75505Sopenharmony_ci
594e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
595e5b75505Sopenharmony_ci		   vt.bstrVal);
596e5b75505Sopenharmony_ci	events->adapter_desc = _wcsdup(vt.bstrVal);
597e5b75505Sopenharmony_ci	VariantClear(&vt);
598e5b75505Sopenharmony_ci
599e5b75505Sopenharmony_ci	/*
600e5b75505Sopenharmony_ci	 * Try to get even better candidate for matching with InstanceName
601e5b75505Sopenharmony_ci	 * from Win32_PnPEntity. This is needed at least for some USB cards
602e5b75505Sopenharmony_ci	 * that can change the InstanceName whenever being unplugged and
603e5b75505Sopenharmony_ci	 * plugged again.
604e5b75505Sopenharmony_ci	 */
605e5b75505Sopenharmony_ci
606e5b75505Sopenharmony_ci	hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
607e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
608e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
609e5b75505Sopenharmony_ci			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
610e5b75505Sopenharmony_ci		IWbemClassObject_Release(pObj);
611e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
612e5b75505Sopenharmony_ci		if (events->adapter_desc == NULL)
613e5b75505Sopenharmony_ci			return ndis_events_use_desc(events, desc);
614e5b75505Sopenharmony_ci		return 0; /* use Win32_NetworkAdapter::Name */
615e5b75505Sopenharmony_ci	}
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
618e5b75505Sopenharmony_ci		   "'%S'", vt.bstrVal);
619e5b75505Sopenharmony_ci
620e5b75505Sopenharmony_ci	len = _snwprintf(query, MAX_QUERY_LEN,
621e5b75505Sopenharmony_ci			L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
622e5b75505Sopenharmony_ci	if (len < 0 || len >= MAX_QUERY_LEN - 1) {
623e5b75505Sopenharmony_ci		VariantClear(&vt);
624e5b75505Sopenharmony_ci		IWbemClassObject_Release(pObj);
625e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
626e5b75505Sopenharmony_ci		if (events->adapter_desc == NULL)
627e5b75505Sopenharmony_ci			return ndis_events_use_desc(events, desc);
628e5b75505Sopenharmony_ci		return 0; /* use Win32_NetworkAdapter::Name */
629e5b75505Sopenharmony_ci	}
630e5b75505Sopenharmony_ci
631e5b75505Sopenharmony_ci	/* Escape \ as \\ */
632e5b75505Sopenharmony_ci	for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
633e5b75505Sopenharmony_ci		if (vt.bstrVal[pos] == '\\') {
634e5b75505Sopenharmony_ci			if (len >= MAX_QUERY_LEN - 3)
635e5b75505Sopenharmony_ci				break;
636e5b75505Sopenharmony_ci			query[len++] = '\\';
637e5b75505Sopenharmony_ci		}
638e5b75505Sopenharmony_ci		query[len++] = vt.bstrVal[pos];
639e5b75505Sopenharmony_ci	}
640e5b75505Sopenharmony_ci	query[len++] = L'\'';
641e5b75505Sopenharmony_ci	query[len] = L'\0';
642e5b75505Sopenharmony_ci	VariantClear(&vt);
643e5b75505Sopenharmony_ci	IWbemClassObject_Release(pObj);
644e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
645e5b75505Sopenharmony_ci
646e5b75505Sopenharmony_ci	hr = call_IWbemServices_ExecQuery(
647e5b75505Sopenharmony_ci		pSvc, L"WQL", query,
648e5b75505Sopenharmony_ci		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
649e5b75505Sopenharmony_ci		NULL, &pEnumerator);
650e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
651e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
652e5b75505Sopenharmony_ci			   "Name from Win32_PnPEntity: 0x%x", (int) hr);
653e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
654e5b75505Sopenharmony_ci		if (events->adapter_desc == NULL)
655e5b75505Sopenharmony_ci			return ndis_events_use_desc(events, desc);
656e5b75505Sopenharmony_ci		return 0; /* use Win32_NetworkAdapter::Name */
657e5b75505Sopenharmony_ci	}
658e5b75505Sopenharmony_ci
659e5b75505Sopenharmony_ci	uReturned = 0;
660e5b75505Sopenharmony_ci	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
661e5b75505Sopenharmony_ci				       &pObj, &uReturned);
662e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr) || uReturned == 0) {
663e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
664e5b75505Sopenharmony_ci			   "from Win32_PnPEntity: 0x%x", (int) hr);
665e5b75505Sopenharmony_ci		IEnumWbemClassObject_Release(pEnumerator);
666e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
667e5b75505Sopenharmony_ci		if (events->adapter_desc == NULL)
668e5b75505Sopenharmony_ci			return ndis_events_use_desc(events, desc);
669e5b75505Sopenharmony_ci		return 0; /* use Win32_NetworkAdapter::Name */
670e5b75505Sopenharmony_ci	}
671e5b75505Sopenharmony_ci	IEnumWbemClassObject_Release(pEnumerator);
672e5b75505Sopenharmony_ci
673e5b75505Sopenharmony_ci	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
674e5b75505Sopenharmony_ci	if (!SUCCEEDED(hr)) {
675e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
676e5b75505Sopenharmony_ci			   "Win32_PnPEntity: 0x%x", (int) hr);
677e5b75505Sopenharmony_ci		IWbemClassObject_Release(pObj);
678e5b75505Sopenharmony_ci		IWbemServices_Release(pSvc);
679e5b75505Sopenharmony_ci		if (events->adapter_desc == NULL)
680e5b75505Sopenharmony_ci			return ndis_events_use_desc(events, desc);
681e5b75505Sopenharmony_ci		return 0; /* use Win32_NetworkAdapter::Name */
682e5b75505Sopenharmony_ci	}
683e5b75505Sopenharmony_ci
684e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
685e5b75505Sopenharmony_ci		   vt.bstrVal);
686e5b75505Sopenharmony_ci	os_free(events->adapter_desc);
687e5b75505Sopenharmony_ci	events->adapter_desc = _wcsdup(vt.bstrVal);
688e5b75505Sopenharmony_ci	VariantClear(&vt);
689e5b75505Sopenharmony_ci
690e5b75505Sopenharmony_ci	IWbemClassObject_Release(pObj);
691e5b75505Sopenharmony_ci
692e5b75505Sopenharmony_ci	IWbemServices_Release(pSvc);
693e5b75505Sopenharmony_ci
694e5b75505Sopenharmony_ci	if (events->adapter_desc == NULL)
695e5b75505Sopenharmony_ci		return ndis_events_use_desc(events, desc);
696e5b75505Sopenharmony_ci
697e5b75505Sopenharmony_ci	return 0;
698e5b75505Sopenharmony_ci}
699e5b75505Sopenharmony_ci
700e5b75505Sopenharmony_ci
701e5b75505Sopenharmony_cistruct ndis_events_data *
702e5b75505Sopenharmony_cindis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
703e5b75505Sopenharmony_ci		 const char *ifname, const char *desc)
704e5b75505Sopenharmony_ci{
705e5b75505Sopenharmony_ci	HRESULT hr;
706e5b75505Sopenharmony_ci	IWbemObjectSink *pSink;
707e5b75505Sopenharmony_ci	struct ndis_events_data *events;
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci	events = os_zalloc(sizeof(*events));
710e5b75505Sopenharmony_ci	if (events == NULL) {
711e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
712e5b75505Sopenharmony_ci		return NULL;
713e5b75505Sopenharmony_ci	}
714e5b75505Sopenharmony_ci	events->ifname = os_strdup(ifname);
715e5b75505Sopenharmony_ci	if (events->ifname == NULL) {
716e5b75505Sopenharmony_ci		os_free(events);
717e5b75505Sopenharmony_ci		return NULL;
718e5b75505Sopenharmony_ci	}
719e5b75505Sopenharmony_ci
720e5b75505Sopenharmony_ci	if (wmi_refcnt++ == 0) {
721e5b75505Sopenharmony_ci		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
722e5b75505Sopenharmony_ci		if (FAILED(hr)) {
723e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
724e5b75505Sopenharmony_ci				   "returned 0x%x", (int) hr);
725e5b75505Sopenharmony_ci			os_free(events);
726e5b75505Sopenharmony_ci			return NULL;
727e5b75505Sopenharmony_ci		}
728e5b75505Sopenharmony_ci	}
729e5b75505Sopenharmony_ci
730e5b75505Sopenharmony_ci	if (wmi_first) {
731e5b75505Sopenharmony_ci		/* CoInitializeSecurity() must be called once and only once
732e5b75505Sopenharmony_ci		 * per process, so let's use wmi_first flag to protect against
733e5b75505Sopenharmony_ci		 * multiple calls. */
734e5b75505Sopenharmony_ci		wmi_first = 0;
735e5b75505Sopenharmony_ci
736e5b75505Sopenharmony_ci		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
737e5b75505Sopenharmony_ci					  RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
738e5b75505Sopenharmony_ci					  RPC_C_IMP_LEVEL_IMPERSONATE,
739e5b75505Sopenharmony_ci					  NULL, EOAC_SECURE_REFS, NULL);
740e5b75505Sopenharmony_ci		if (FAILED(hr)) {
741e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
742e5b75505Sopenharmony_ci				   "- returned 0x%x", (int) hr);
743e5b75505Sopenharmony_ci			os_free(events);
744e5b75505Sopenharmony_ci			return NULL;
745e5b75505Sopenharmony_ci		}
746e5b75505Sopenharmony_ci	}
747e5b75505Sopenharmony_ci
748e5b75505Sopenharmony_ci	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
749e5b75505Sopenharmony_ci			      &IID_IWbemLocator,
750e5b75505Sopenharmony_ci			      (LPVOID *) (void *) &events->pLoc);
751e5b75505Sopenharmony_ci	if (FAILED(hr)) {
752e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
753e5b75505Sopenharmony_ci			   "0x%x", (int) hr);
754e5b75505Sopenharmony_ci		CoUninitialize();
755e5b75505Sopenharmony_ci		os_free(events);
756e5b75505Sopenharmony_ci		return NULL;
757e5b75505Sopenharmony_ci	}
758e5b75505Sopenharmony_ci
759e5b75505Sopenharmony_ci	if (ndis_events_get_adapter(events, ifname, desc) < 0) {
760e5b75505Sopenharmony_ci		CoUninitialize();
761e5b75505Sopenharmony_ci		os_free(events);
762e5b75505Sopenharmony_ci		return NULL;
763e5b75505Sopenharmony_ci	}
764e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
765e5b75505Sopenharmony_ci		   events->adapter_desc);
766e5b75505Sopenharmony_ci
767e5b75505Sopenharmony_ci	hr = call_IWbemLocator_ConnectServer(
768e5b75505Sopenharmony_ci		events->pLoc, L"ROOT\\WMI", NULL, NULL,
769e5b75505Sopenharmony_ci		0, 0, 0, 0, &events->pSvc);
770e5b75505Sopenharmony_ci	if (FAILED(hr)) {
771e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "Could not connect to server - error "
772e5b75505Sopenharmony_ci			   "0x%x", (int) hr);
773e5b75505Sopenharmony_ci		CoUninitialize();
774e5b75505Sopenharmony_ci		os_free(events->adapter_desc);
775e5b75505Sopenharmony_ci		os_free(events);
776e5b75505Sopenharmony_ci		return NULL;
777e5b75505Sopenharmony_ci	}
778e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
779e5b75505Sopenharmony_ci
780e5b75505Sopenharmony_ci	ndis_events_constructor(events);
781e5b75505Sopenharmony_ci	pSink = &events->sink;
782e5b75505Sopenharmony_ci	pSink->lpVtbl = &events->sink_vtbl;
783e5b75505Sopenharmony_ci	events->sink_vtbl.QueryInterface = ndis_events_query_interface;
784e5b75505Sopenharmony_ci	events->sink_vtbl.AddRef = ndis_events_add_ref;
785e5b75505Sopenharmony_ci	events->sink_vtbl.Release = ndis_events_release;
786e5b75505Sopenharmony_ci	events->sink_vtbl.Indicate = ndis_events_indicate;
787e5b75505Sopenharmony_ci	events->sink_vtbl.SetStatus = ndis_events_set_status;
788e5b75505Sopenharmony_ci
789e5b75505Sopenharmony_ci	if (register_async_notification(pSink, events->pSvc) < 0) {
790e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "Failed to register async "
791e5b75505Sopenharmony_ci			   "notifications");
792e5b75505Sopenharmony_ci		ndis_events_destructor(events);
793e5b75505Sopenharmony_ci		os_free(events->adapter_desc);
794e5b75505Sopenharmony_ci		os_free(events);
795e5b75505Sopenharmony_ci		return NULL;
796e5b75505Sopenharmony_ci	}
797e5b75505Sopenharmony_ci
798e5b75505Sopenharmony_ci	*read_pipe = events->read_pipe;
799e5b75505Sopenharmony_ci	*event_avail = events->event_avail;
800e5b75505Sopenharmony_ci
801e5b75505Sopenharmony_ci	return events;
802e5b75505Sopenharmony_ci}
803