00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #define _WIN32_WINNT 0x0400
00016
00017 #include "includes.h"
00018
00019 #ifndef COBJMACROS
00020 #define COBJMACROS
00021 #endif
00022 #include <wbemidl.h>
00023
00024 #include "common.h"
00025
00026
00027 static int wmi_refcnt = 0;
00028 static int wmi_first = 1;
00029
00030 struct ndis_events_data {
00031 IWbemObjectSink sink;
00032 IWbemObjectSinkVtbl sink_vtbl;
00033
00034 IWbemServices *pSvc;
00035 IWbemLocator *pLoc;
00036
00037 HANDLE read_pipe, write_pipe, event_avail;
00038 UINT ref;
00039 int terminating;
00040 char *ifname;
00041 WCHAR *adapter_desc;
00042 };
00043
00044 #define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
00045 #define BstrFree(x) if (x) SysFreeString(x)
00046
00047
00048
00049 HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
00050 IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
00051 long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
00052 {
00053 BSTR bsQueryLanguage, bsQuery;
00054 HRESULT hr;
00055
00056 bsQueryLanguage = BstrAlloc(strQueryLanguage);
00057 bsQuery = BstrAlloc(strQuery);
00058
00059 hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
00060 pCtx, ppEnum);
00061
00062 BstrFree(bsQueryLanguage);
00063 BstrFree(bsQuery);
00064
00065 return hr;
00066 }
00067
00068
00069 HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
00070 IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
00071 long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
00072 {
00073 BSTR bsQueryLanguage, bsQuery;
00074 HRESULT hr;
00075
00076 bsQueryLanguage = BstrAlloc(strQueryLanguage);
00077 bsQuery = BstrAlloc(strQuery);
00078
00079 hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
00080 bsQuery, lFlags, pCtx,
00081 pResponseHandler);
00082
00083 BstrFree(bsQueryLanguage);
00084 BstrFree(bsQuery);
00085
00086 return hr;
00087 }
00088
00089
00090 HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
00091 IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
00092 LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
00093 LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
00094 {
00095 BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
00096 HRESULT hr;
00097
00098 bsNetworkResource = BstrAlloc(strNetworkResource);
00099 bsUser = BstrAlloc(strUser);
00100 bsPassword = BstrAlloc(strPassword);
00101 bsLocale = BstrAlloc(strLocale);
00102 bsAuthority = BstrAlloc(strAuthority);
00103
00104 hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
00105 bsPassword, bsLocale, lSecurityFlags,
00106 bsAuthority, pCtx, ppNamespace);
00107
00108 BstrFree(bsNetworkResource);
00109 BstrFree(bsUser);
00110 BstrFree(bsPassword);
00111 BstrFree(bsLocale);
00112 BstrFree(bsAuthority);
00113
00114 return hr;
00115 }
00116
00117
00118 enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
00119 EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
00120
00121 static int ndis_events_get_adapter(struct ndis_events_data *events,
00122 const char *ifname, const char *desc);
00123
00124
00125 static int ndis_events_constructor(struct ndis_events_data *events)
00126 {
00127 events->ref = 1;
00128
00129 if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
00130 wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
00131 (int) GetLastError());
00132 return -1;
00133 }
00134 events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
00135 if (events->event_avail == NULL) {
00136 wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
00137 (int) GetLastError());
00138 CloseHandle(events->read_pipe);
00139 CloseHandle(events->write_pipe);
00140 return -1;
00141 }
00142
00143 return 0;
00144 }
00145
00146
00147 static void ndis_events_destructor(struct ndis_events_data *events)
00148 {
00149 CloseHandle(events->read_pipe);
00150 CloseHandle(events->write_pipe);
00151 CloseHandle(events->event_avail);
00152 IWbemServices_Release(events->pSvc);
00153 IWbemLocator_Release(events->pLoc);
00154 if (--wmi_refcnt == 0)
00155 CoUninitialize();
00156 }
00157
00158
00159 static HRESULT STDMETHODCALLTYPE
00160 ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
00161 {
00162 *obj = NULL;
00163
00164 if (IsEqualIID(riid, &IID_IUnknown) ||
00165 IsEqualIID(riid, &IID_IWbemObjectSink)) {
00166 *obj = this;
00167 IWbemObjectSink_AddRef(this);
00168 return NOERROR;
00169 }
00170
00171 return E_NOINTERFACE;
00172 }
00173
00174
00175 static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
00176 {
00177 struct ndis_events_data *events = (struct ndis_events_data *) this;
00178 return ++events->ref;
00179 }
00180
00181
00182 static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
00183 {
00184 struct ndis_events_data *events = (struct ndis_events_data *) this;
00185
00186 if (--events->ref != 0)
00187 return events->ref;
00188
00189 ndis_events_destructor(events);
00190 wpa_printf(MSG_DEBUG, "ndis_events: terminated");
00191 os_free(events->adapter_desc);
00192 os_free(events->ifname);
00193 os_free(events);
00194 return 0;
00195 }
00196
00197
00198 static int ndis_events_send_event(struct ndis_events_data *events,
00199 enum event_types type,
00200 char *data, size_t data_len)
00201 {
00202 char buf[512], *pos, *end;
00203 int _type;
00204 DWORD written;
00205
00206 end = buf + sizeof(buf);
00207 _type = (int) type;
00208 os_memcpy(buf, &_type, sizeof(_type));
00209 pos = buf + sizeof(_type);
00210
00211 if (data) {
00212 if (2 + data_len > (size_t) (end - pos)) {
00213 wpa_printf(MSG_DEBUG, "Not enough room for send_event "
00214 "data (%d)", data_len);
00215 return -1;
00216 }
00217 *pos++ = data_len >> 8;
00218 *pos++ = data_len & 0xff;
00219 os_memcpy(pos, data, data_len);
00220 pos += data_len;
00221 }
00222
00223 if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
00224 SetEvent(events->event_avail);
00225 return 0;
00226 }
00227 wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
00228 return -1;
00229 }
00230
00231
00232 static void ndis_events_media_connect(struct ndis_events_data *events)
00233 {
00234 wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
00235 ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
00236 }
00237
00238
00239 static void ndis_events_media_disconnect(struct ndis_events_data *events)
00240 {
00241 wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
00242 ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
00243 }
00244
00245
00246 static void ndis_events_media_specific(struct ndis_events_data *events,
00247 IWbemClassObject *pObj)
00248 {
00249 VARIANT vt;
00250 HRESULT hr;
00251 LONG lower, upper, k;
00252 UCHAR ch;
00253 char *data, *pos;
00254 size_t data_len;
00255
00256 wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
00257
00258
00259 hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
00260 0, &vt, NULL, NULL);
00261 if (FAILED(hr)) {
00262 wpa_printf(MSG_DEBUG, "Could not get "
00263 "NdisStatusMediaSpecificIndication from "
00264 "the object?!");
00265 return;
00266 }
00267
00268 SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
00269 SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
00270 data_len = upper - lower + 1;
00271 data = os_malloc(data_len);
00272 if (data == NULL) {
00273 wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
00274 "data");
00275 VariantClear(&vt);
00276 return;
00277 }
00278
00279 pos = data;
00280 for (k = lower; k <= upper; k++) {
00281 SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
00282 *pos++ = ch;
00283 }
00284 wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
00285
00286 VariantClear(&vt);
00287
00288 ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
00289
00290 os_free(data);
00291 }
00292
00293
00294 static void ndis_events_adapter_arrival(struct ndis_events_data *events)
00295 {
00296 wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
00297 ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
00298 }
00299
00300
00301 static void ndis_events_adapter_removal(struct ndis_events_data *events)
00302 {
00303 wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
00304 ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
00305 }
00306
00307
00308 static HRESULT STDMETHODCALLTYPE
00309 ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
00310 IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
00311 {
00312 struct ndis_events_data *events = (struct ndis_events_data *) this;
00313 long i;
00314
00315 if (events->terminating) {
00316 wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
00317 "indication - terminating");
00318 return WBEM_NO_ERROR;
00319 }
00320
00321
00322
00323 for (i = 0; i < lObjectCount; i++) {
00324 IWbemClassObject *pObj = ppObjArray[i];
00325 HRESULT hr;
00326 VARIANT vtClass, vt;
00327
00328 hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
00329 NULL);
00330 if (FAILED(hr)) {
00331 wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
00332 "event.");
00333 break;
00334 }
00335
00336
00337 hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
00338 NULL);
00339 if (FAILED(hr)) {
00340 wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
00341 "from event.");
00342 VariantClear(&vtClass);
00343 break;
00344 }
00345
00346 if (wcscmp(vtClass.bstrVal,
00347 L"MSNdis_NotifyAdapterArrival") == 0) {
00348 wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
00349 "update adapter description since it may "
00350 "have changed with new adapter instance");
00351 ndis_events_get_adapter(events, events->ifname, NULL);
00352 }
00353
00354 if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
00355 wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
00356 "indication for foreign adapter: "
00357 "InstanceName: '%S' __CLASS: '%S'",
00358 vt.bstrVal, vtClass.bstrVal);
00359 VariantClear(&vtClass);
00360 VariantClear(&vt);
00361 continue;
00362 }
00363 VariantClear(&vt);
00364
00365 if (wcscmp(vtClass.bstrVal,
00366 L"MSNdis_StatusMediaSpecificIndication") == 0) {
00367 ndis_events_media_specific(events, pObj);
00368 } else if (wcscmp(vtClass.bstrVal,
00369 L"MSNdis_StatusMediaConnect") == 0) {
00370 ndis_events_media_connect(events);
00371 } else if (wcscmp(vtClass.bstrVal,
00372 L"MSNdis_StatusMediaDisconnect") == 0) {
00373 ndis_events_media_disconnect(events);
00374 } else if (wcscmp(vtClass.bstrVal,
00375 L"MSNdis_NotifyAdapterArrival") == 0) {
00376 ndis_events_adapter_arrival(events);
00377 } else if (wcscmp(vtClass.bstrVal,
00378 L"MSNdis_NotifyAdapterRemoval") == 0) {
00379 ndis_events_adapter_removal(events);
00380 } else {
00381 wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
00382 "'%S'", vtClass.bstrVal);
00383 }
00384
00385 VariantClear(&vtClass);
00386 }
00387
00388 return WBEM_NO_ERROR;
00389 }
00390
00391
00392 static HRESULT STDMETHODCALLTYPE
00393 ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
00394 BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
00395 {
00396 return WBEM_NO_ERROR;
00397 }
00398
00399
00400 static int notification_query(IWbemObjectSink *pDestSink,
00401 IWbemServices *pSvc, const char *class_name)
00402 {
00403 HRESULT hr;
00404 WCHAR query[256];
00405
00406 _snwprintf(query, 256,
00407 L"SELECT * FROM %S", class_name);
00408 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
00409 hr = call_IWbemServices_ExecNotificationQueryAsync(
00410 pSvc, L"WQL", query, 0, 0, pDestSink);
00411 if (FAILED(hr)) {
00412 wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
00413 "failed with hresult of 0x%x",
00414 class_name, (int) hr);
00415 return -1;
00416 }
00417
00418 return 0;
00419 }
00420
00421
00422 static int register_async_notification(IWbemObjectSink *pDestSink,
00423 IWbemServices *pSvc)
00424 {
00425 int i;
00426 const char *class_list[] = {
00427 "MSNdis_StatusMediaConnect",
00428 "MSNdis_StatusMediaDisconnect",
00429 "MSNdis_StatusMediaSpecificIndication",
00430 "MSNdis_NotifyAdapterArrival",
00431 "MSNdis_NotifyAdapterRemoval",
00432 NULL
00433 };
00434
00435 for (i = 0; class_list[i]; i++) {
00436 if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
00437 return -1;
00438 }
00439
00440 return 0;
00441 }
00442
00443
00444 void ndis_events_deinit(struct ndis_events_data *events)
00445 {
00446 events->terminating = 1;
00447 IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
00448 IWbemObjectSink_Release(&events->sink);
00449
00450
00451
00452
00453 }
00454
00455
00456 static int ndis_events_use_desc(struct ndis_events_data *events,
00457 const char *desc)
00458 {
00459 char *tmp, *pos;
00460 size_t len;
00461
00462 if (desc == NULL) {
00463 if (events->adapter_desc == NULL)
00464 return -1;
00465
00466 return 0;
00467 }
00468
00469 tmp = os_strdup(desc);
00470 if (tmp == NULL)
00471 return -1;
00472
00473 pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
00474 if (pos)
00475 *pos = '\0';
00476
00477 len = os_strlen(tmp);
00478 events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
00479 if (events->adapter_desc == NULL) {
00480 os_free(tmp);
00481 return -1;
00482 }
00483 _snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
00484 os_free(tmp);
00485 return 0;
00486 }
00487
00488
00489 static int ndis_events_get_adapter(struct ndis_events_data *events,
00490 const char *ifname, const char *desc)
00491 {
00492 HRESULT hr;
00493 IWbemServices *pSvc;
00494 #define MAX_QUERY_LEN 256
00495 WCHAR query[MAX_QUERY_LEN];
00496 IEnumWbemClassObject *pEnumerator;
00497 IWbemClassObject *pObj;
00498 ULONG uReturned;
00499 VARIANT vt;
00500 int len, pos;
00501
00502
00503
00504
00505
00506
00507
00508 os_free(events->adapter_desc);
00509 events->adapter_desc = NULL;
00510
00511 hr = call_IWbemLocator_ConnectServer(
00512 events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
00513 if (FAILED(hr)) {
00514 wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
00515 "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
00516 return ndis_events_use_desc(events, desc);
00517 }
00518 wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
00519
00520 _snwprintf(query, MAX_QUERY_LEN,
00521 L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
00522 L"WHERE SettingID='%S'", ifname);
00523 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
00524
00525 hr = call_IWbemServices_ExecQuery(
00526 pSvc, L"WQL", query,
00527 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
00528 NULL, &pEnumerator);
00529 if (!SUCCEEDED(hr)) {
00530 wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
00531 "GUID from Win32_NetworkAdapterConfiguration: "
00532 "0x%x", (int) hr);
00533 IWbemServices_Release(pSvc);
00534 return ndis_events_use_desc(events, desc);
00535 }
00536
00537 uReturned = 0;
00538 hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
00539 &pObj, &uReturned);
00540 if (!SUCCEEDED(hr) || uReturned == 0) {
00541 wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
00542 "GUID from Win32_NetworkAdapterConfiguration: "
00543 "0x%x", (int) hr);
00544 IEnumWbemClassObject_Release(pEnumerator);
00545 IWbemServices_Release(pSvc);
00546 return ndis_events_use_desc(events, desc);
00547 }
00548 IEnumWbemClassObject_Release(pEnumerator);
00549
00550 VariantInit(&vt);
00551 hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
00552 if (!SUCCEEDED(hr)) {
00553 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
00554 "Win32_NetworkAdapterConfiguration: 0x%x",
00555 (int) hr);
00556 IWbemServices_Release(pSvc);
00557 return ndis_events_use_desc(events, desc);
00558 }
00559
00560 _snwprintf(query, MAX_QUERY_LEN,
00561 L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
00562 L"Index=%d",
00563 vt.uintVal);
00564 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
00565 VariantClear(&vt);
00566 IWbemClassObject_Release(pObj);
00567
00568 hr = call_IWbemServices_ExecQuery(
00569 pSvc, L"WQL", query,
00570 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
00571 NULL, &pEnumerator);
00572 if (!SUCCEEDED(hr)) {
00573 wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
00574 "from Win32_NetworkAdapter: 0x%x", (int) hr);
00575 IWbemServices_Release(pSvc);
00576 return ndis_events_use_desc(events, desc);
00577 }
00578
00579 uReturned = 0;
00580 hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
00581 &pObj, &uReturned);
00582 if (!SUCCEEDED(hr) || uReturned == 0) {
00583 wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
00584 "from Win32_NetworkAdapter: 0x%x", (int) hr);
00585 IEnumWbemClassObject_Release(pEnumerator);
00586 IWbemServices_Release(pSvc);
00587 return ndis_events_use_desc(events, desc);
00588 }
00589 IEnumWbemClassObject_Release(pEnumerator);
00590
00591 hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
00592 if (!SUCCEEDED(hr)) {
00593 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
00594 "Win32_NetworkAdapter: 0x%x", (int) hr);
00595 IWbemClassObject_Release(pObj);
00596 IWbemServices_Release(pSvc);
00597 return ndis_events_use_desc(events, desc);
00598 }
00599
00600 wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
00601 vt.bstrVal);
00602 events->adapter_desc = _wcsdup(vt.bstrVal);
00603 VariantClear(&vt);
00604
00605
00606
00607
00608
00609
00610
00611
00612 hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
00613 if (!SUCCEEDED(hr)) {
00614 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
00615 "from Win32_NetworkAdapter: 0x%x", (int) hr);
00616 IWbemClassObject_Release(pObj);
00617 IWbemServices_Release(pSvc);
00618 if (events->adapter_desc == NULL)
00619 return ndis_events_use_desc(events, desc);
00620 return 0;
00621 }
00622
00623 wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
00624 "'%S'", vt.bstrVal);
00625
00626 len = _snwprintf(query, MAX_QUERY_LEN,
00627 L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
00628 if (len < 0 || len >= MAX_QUERY_LEN - 1) {
00629 VariantClear(&vt);
00630 IWbemClassObject_Release(pObj);
00631 IWbemServices_Release(pSvc);
00632 if (events->adapter_desc == NULL)
00633 return ndis_events_use_desc(events, desc);
00634 return 0;
00635 }
00636
00637
00638 for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
00639 if (vt.bstrVal[pos] == '\\') {
00640 if (len >= MAX_QUERY_LEN - 3)
00641 break;
00642 query[len++] = '\\';
00643 }
00644 query[len++] = vt.bstrVal[pos];
00645 }
00646 query[len++] = L'\'';
00647 query[len] = L'\0';
00648 VariantClear(&vt);
00649 IWbemClassObject_Release(pObj);
00650 wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
00651
00652 hr = call_IWbemServices_ExecQuery(
00653 pSvc, L"WQL", query,
00654 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
00655 NULL, &pEnumerator);
00656 if (!SUCCEEDED(hr)) {
00657 wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
00658 "Name from Win32_PnPEntity: 0x%x", (int) hr);
00659 IWbemServices_Release(pSvc);
00660 if (events->adapter_desc == NULL)
00661 return ndis_events_use_desc(events, desc);
00662 return 0;
00663 }
00664
00665 uReturned = 0;
00666 hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
00667 &pObj, &uReturned);
00668 if (!SUCCEEDED(hr) || uReturned == 0) {
00669 wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
00670 "from Win32_PnPEntity: 0x%x", (int) hr);
00671 IEnumWbemClassObject_Release(pEnumerator);
00672 IWbemServices_Release(pSvc);
00673 if (events->adapter_desc == NULL)
00674 return ndis_events_use_desc(events, desc);
00675 return 0;
00676 }
00677 IEnumWbemClassObject_Release(pEnumerator);
00678
00679 hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
00680 if (!SUCCEEDED(hr)) {
00681 wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
00682 "Win32_PnPEntity: 0x%x", (int) hr);
00683 IWbemClassObject_Release(pObj);
00684 IWbemServices_Release(pSvc);
00685 if (events->adapter_desc == NULL)
00686 return ndis_events_use_desc(events, desc);
00687 return 0;
00688 }
00689
00690 wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
00691 vt.bstrVal);
00692 os_free(events->adapter_desc);
00693 events->adapter_desc = _wcsdup(vt.bstrVal);
00694 VariantClear(&vt);
00695
00696 IWbemClassObject_Release(pObj);
00697
00698 IWbemServices_Release(pSvc);
00699
00700 if (events->adapter_desc == NULL)
00701 return ndis_events_use_desc(events, desc);
00702
00703 return 0;
00704 }
00705
00706
00707 struct ndis_events_data *
00708 ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
00709 const char *ifname, const char *desc)
00710 {
00711 HRESULT hr;
00712 IWbemObjectSink *pSink;
00713 struct ndis_events_data *events;
00714
00715 events = os_zalloc(sizeof(*events));
00716 if (events == NULL) {
00717 wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
00718 return NULL;
00719 }
00720 events->ifname = os_strdup(ifname);
00721 if (events->ifname == NULL) {
00722 os_free(events);
00723 return NULL;
00724 }
00725
00726 if (wmi_refcnt++ == 0) {
00727 hr = CoInitializeEx(0, COINIT_MULTITHREADED);
00728 if (FAILED(hr)) {
00729 wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
00730 "returned 0x%x", (int) hr);
00731 os_free(events);
00732 return NULL;
00733 }
00734 }
00735
00736 if (wmi_first) {
00737
00738
00739
00740 wmi_first = 0;
00741
00742 hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
00743 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
00744 RPC_C_IMP_LEVEL_IMPERSONATE,
00745 NULL, EOAC_SECURE_REFS, NULL);
00746 if (FAILED(hr)) {
00747 wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
00748 "- returned 0x%x", (int) hr);
00749 os_free(events);
00750 return NULL;
00751 }
00752 }
00753
00754 hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
00755 &IID_IWbemLocator,
00756 (LPVOID *) (void *) &events->pLoc);
00757 if (FAILED(hr)) {
00758 wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
00759 "0x%x", (int) hr);
00760 CoUninitialize();
00761 os_free(events);
00762 return NULL;
00763 }
00764
00765 if (ndis_events_get_adapter(events, ifname, desc) < 0) {
00766 CoUninitialize();
00767 os_free(events);
00768 return NULL;
00769 }
00770 wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
00771 events->adapter_desc);
00772
00773 hr = call_IWbemLocator_ConnectServer(
00774 events->pLoc, L"ROOT\\WMI", NULL, NULL,
00775 0, 0, 0, 0, &events->pSvc);
00776 if (FAILED(hr)) {
00777 wpa_printf(MSG_ERROR, "Could not connect to server - error "
00778 "0x%x", (int) hr);
00779 CoUninitialize();
00780 os_free(events->adapter_desc);
00781 os_free(events);
00782 return NULL;
00783 }
00784 wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
00785
00786 ndis_events_constructor(events);
00787 pSink = &events->sink;
00788 pSink->lpVtbl = &events->sink_vtbl;
00789 events->sink_vtbl.QueryInterface = ndis_events_query_interface;
00790 events->sink_vtbl.AddRef = ndis_events_add_ref;
00791 events->sink_vtbl.Release = ndis_events_release;
00792 events->sink_vtbl.Indicate = ndis_events_indicate;
00793 events->sink_vtbl.SetStatus = ndis_events_set_status;
00794
00795 if (register_async_notification(pSink, events->pSvc) < 0) {
00796 wpa_printf(MSG_DEBUG, "Failed to register async "
00797 "notifications");
00798 ndis_events_destructor(events);
00799 os_free(events->adapter_desc);
00800 os_free(events);
00801 return NULL;
00802 }
00803
00804 *read_pipe = events->read_pipe;
00805 *event_avail = events->event_avail;
00806
00807 return events;
00808 }