~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to ndis_events.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

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