ndis_events.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35