$search
00001 /* 00002 * ndis_events - Receive NdisMIndicateStatus() events using WMI 00003 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #define _WIN32_WINNT 0x0400 00016 00017 #include "includes.h" 00018 00019 #ifndef COBJMACROS 00020 #define COBJMACROS 00021 #endif /* COBJMACROS */ 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; /* {GUID..} */ 00041 WCHAR *adapter_desc; 00042 }; 00043 00044 #define BstrAlloc(x) (x) ? SysAllocString(x) : NULL 00045 #define BstrFree(x) if (x) SysFreeString(x) 00046 00047 /* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to 00048 * BSTRs */ 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 /* This is the StatusBuffer from NdisMIndicateStatus() call */ 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 /* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)", 00321 lObjectCount); */ 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 /* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */ 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 * Rest of deinitialization is done in ndis_events_destructor() once 00451 * all reference count drops to zero. 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 /* Continue using old description */ 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 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter 00504 * to have better probability of matching with InstanceName from 00505 * MSNdis events. If this fails, use the provided description. 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 * Try to get even better candidate for matching with InstanceName 00607 * from Win32_PnPEntity. This is needed at least for some USB cards 00608 * that can change the InstanceName whenever being unplugged and 00609 * plugged again. 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; /* use Win32_NetworkAdapter::Name */ 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; /* use Win32_NetworkAdapter::Name */ 00635 } 00636 00637 /* Escape \ as \\ */ 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; /* use Win32_NetworkAdapter::Name */ 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; /* use Win32_NetworkAdapter::Name */ 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; /* use Win32_NetworkAdapter::Name */ 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 /* CoInitializeSecurity() must be called once and only once 00738 * per process, so let's use wmi_first flag to protect against 00739 * multiple calls. */ 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 }