~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/drivers/ndis_events.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

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