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

« back to all changes in this revision

Viewing changes to src/drivers/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
 
}