2
* ndis_events - test program for receiving NdisMIndicateStatus() events
3
* Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
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.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
15
#define _WIN32_WINNT 0x0400
22
struct ndis_events_data {
26
class CNdisSink : public IWbemObjectSink
33
STDMETHODIMP QueryInterface(REFIID, LPVOID *);
34
STDMETHODIMP_(ULONG) AddRef(void);
35
STDMETHODIMP_(ULONG) Release(void);
37
virtual HRESULT STDMETHODCALLTYPE Indicate(
39
IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray);
41
virtual HRESULT STDMETHODCALLTYPE SetStatus(
42
long lFlags, HRESULT hResult, BSTR strParam,
43
IWbemClassObject __RPC_FAR *pObjParam);
45
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
46
HANDLE read_pipe, event_avail;
47
#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
50
void media_connect(IWbemClassObject *pObj);
51
void media_disconnect(IWbemClassObject *pObj);
52
void media_specific(IWbemClassObject *pObj);
53
void adapter_arrival(IWbemClassObject *pObj);
54
void adapter_removal(IWbemClassObject *pObj);
55
enum event_types { EVENT_CONNECT, EVENT_DISCONNECT,
56
EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL,
57
EVENT_ADAPTER_REMOVAL };
58
int send_event(enum event_types type, BSTR instance,
59
char *data = NULL, size_t data_len = 0);
63
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
65
#else /* CONFIG_NDIS_EVENTS_INTEGRATED */
67
struct sockaddr_in dst;
68
#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
72
CNdisSink::CNdisSink()
76
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
77
if (!CreatePipe(&read_pipe, &write_pipe, NULL, 512)) {
78
printf("CreatePipe() failed: %d\n", (int) GetLastError());
81
event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
82
if (event_avail == NULL) {
83
printf("CreateEvent() failed: %d\n", (int) GetLastError());
84
CloseHandle(read_pipe);
85
CloseHandle(write_pipe);
88
#else /* CONFIG_NDIS_EVENTS_INTEGRATED */
89
sock = socket(AF_INET, SOCK_DGRAM, 0);
90
if (sock == INVALID_SOCKET) {
95
memset(&dst, 0, sizeof(dst));
96
dst.sin_family = AF_INET;
97
dst.sin_addr.s_addr = inet_addr("127.0.0.1");
98
dst.sin_port = htons(9876);
99
#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
103
CNdisSink::~CNdisSink()
105
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
106
CloseHandle(read_pipe);
107
CloseHandle(write_pipe);
108
CloseHandle(event_avail);
109
#else /* CONFIG_NDIS_EVENTS_INTEGRATED */
110
if (sock != INVALID_SOCKET)
112
#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
116
STDMETHODIMP CNdisSink::QueryInterface(REFIID riid, LPVOID *ppv)
120
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink) {
121
*ppv = (IWbemObjectSink *) this;
126
return E_NOINTERFACE;
130
ULONG CNdisSink::AddRef()
136
ULONG CNdisSink::Release()
146
int CNdisSink::send_event(enum event_types type, BSTR instance,
147
char *data, size_t data_len)
149
char buf[512], *pos, *end;
152
end = buf + sizeof(buf);
154
memcpy(buf, &_type, sizeof(_type));
155
pos = buf + sizeof(_type);
157
len = _snprintf(pos + 1, end - pos - 1, "%S", instance);
162
*pos = (unsigned char) len;
165
if (data_len > 255 || 1 + data_len > (size_t) (end - pos)) {
166
printf("Not enough room for send_event data (%d)\n",
170
*pos++ = (unsigned char) data_len;
171
memcpy(pos, data, data_len);
175
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
177
if (WriteFile(write_pipe, buf, pos - buf, &written, NULL)) {
178
SetEvent(event_avail);
181
printf("WriteFile() failed: %d\n", (int) GetLastError());
183
#else /* CONFIG_NDIS_EVENTS_INTEGRATED */
184
return sendto(sock, buf, pos - buf, 0, (struct sockaddr *) &dst,
186
#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
190
void CNdisSink::media_connect(IWbemClassObject *pObj)
194
printf("MSNdis_StatusMediaConnect\n");
195
hr = pObj->Get(L"InstanceName", 0, &vt, NULL, NULL);
197
printf(" InstanceName: '%S'\n", vt.bstrVal);
198
send_event(EVENT_CONNECT, vt.bstrVal);
204
void CNdisSink::media_disconnect(IWbemClassObject *pObj)
208
printf("MSNdis_StatusMediaDisconnect\n");
209
hr = pObj->Get(L"InstanceName", 0, &vt, NULL, NULL);
211
printf(" InstanceName: '%S'\n", vt.bstrVal);
212
send_event(EVENT_DISCONNECT, vt.bstrVal);
218
void CNdisSink::media_specific(IWbemClassObject *pObj)
222
LONG lower, upper, k;
227
printf("MSNdis_StatusMediaSpecificIndication\n");
229
/* This is the StatusBuffer from NdisMIndicateStatus() call */
230
hr = pObj->Get(L"NdisStatusMediaSpecificIndication", 0, &vt, NULL,
233
printf("Could not get NdisStatusMediaSpecificIndication from "
238
SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
239
SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
240
data_len = upper - lower + 1;
241
data = (char *) malloc(data_len);
243
printf("Failed to allocate buffer for event data\n");
248
printf(" Data(len=%d):", data_len);
250
for (k = lower; k <= upper; k++) {
251
SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
259
hr = pObj->Get(L"InstanceName", 0, &vt, NULL, NULL);
261
printf(" InstanceName: '%S'\n", vt.bstrVal);
262
send_event(EVENT_MEDIA_SPECIFIC, vt.bstrVal, data, data_len);
270
void CNdisSink::adapter_arrival(IWbemClassObject *pObj)
274
printf("MSNdis_NotifyAdapterArrival\n");
275
hr = pObj->Get(L"InstanceName", 0, &vt, NULL, NULL);
277
printf(" InstanceName: '%S'\n", vt.bstrVal);
278
send_event(EVENT_ADAPTER_ARRIVAL, vt.bstrVal);
284
void CNdisSink::adapter_removal(IWbemClassObject *pObj)
288
printf("MSNdis_NotifyAdapterRemoval\n");
289
hr = pObj->Get(L"InstanceName", 0, &vt, NULL, NULL);
291
printf(" InstanceName: '%S'\n", vt.bstrVal);
292
send_event(EVENT_ADAPTER_REMOVAL, vt.bstrVal);
298
HRESULT CNdisSink::Indicate(long lObjectCount,
299
IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
301
//printf("Notification received - %d object(s)\n", lObjectCount);
303
for (long i = 0; i < lObjectCount; i++) {
304
IWbemClassObject *pObj = ppObjArray[i];
308
hr = pObj->Get(L"__CLASS", 0, &vtClass, NULL, NULL);
310
printf("Failed to get __CLASS from event.\n");
313
//printf("CLASS: '%S'\n", vtClass.bstrVal);
315
if (wcscmp(vtClass.bstrVal,
316
L"MSNdis_StatusMediaSpecificIndication") == 0) {
317
media_specific(pObj);
318
} else if (wcscmp(vtClass.bstrVal,
319
L"MSNdis_StatusMediaConnect") == 0) {
321
} else if (wcscmp(vtClass.bstrVal,
322
L"MSNdis_StatusMediaDisconnect") == 0) {
323
media_disconnect(pObj);
324
} else if (wcscmp(vtClass.bstrVal,
325
L"MSNdis_NotifyAdapterArrival") == 0) {
326
adapter_arrival(pObj);
327
} else if (wcscmp(vtClass.bstrVal,
328
L"MSNdis_NotifyAdapterRemoval") == 0) {
329
adapter_removal(pObj);
331
printf("Unepected event - __CLASS: '%S'\n",
335
VariantClear(&vtClass);
338
return WBEM_NO_ERROR;
342
HRESULT CNdisSink::SetStatus(long lFlags, HRESULT hResult, BSTR strParam,
343
IWbemClassObject __RPC_FAR *pObjParam)
345
return WBEM_NO_ERROR;
349
static int register_async_notification(IWbemObjectSink *pDestSink,
354
BSTR lang = ::SysAllocString(L"WQL");
356
BSTR query = ::SysAllocString(
357
L"SELECT * FROM MSNdis_StatusMediaConnect");
358
hr = pSvc->ExecNotificationQueryAsync(lang, query, 0, 0, pDestSink);
359
::SysFreeString(query);
361
printf("ExecNotificationQueryAsync for "
362
"MSNdis_StatusMediaConnect failed with hresult of "
367
query = ::SysAllocString(
368
L"SELECT * FROM MSNdis_StatusMediaDisconnect");
369
hr = pSvc->ExecNotificationQueryAsync(lang, query, 0, 0, pDestSink);
370
::SysFreeString(query);
372
printf("ExecNotificationQueryAsync for "
373
"MSNdis_StatusMediaDisconnect failed with hresult of "
378
query = ::SysAllocString(
379
L"SELECT * FROM MSNdis_StatusMediaSpecificIndication");
380
hr = pSvc->ExecNotificationQueryAsync(lang, query, 0, 0, pDestSink);
381
::SysFreeString(query);
383
printf("ExecNotificationQueryAsync for "
384
"MSNdis_StatusMediaSpecificIndication failed with "
385
"hresult of 0x%x\n", hr);
389
query = ::SysAllocString(
390
L"SELECT * FROM MSNdis_NotifyAdapterArrival");
391
hr = pSvc->ExecNotificationQueryAsync(lang, query, 0, 0, pDestSink);
392
::SysFreeString(query);
394
printf("ExecNotificationQueryAsync for "
395
"MSNdis_NotifyAdapterArrival failed with "
396
"hresult of 0x%x\n", hr);
400
query = ::SysAllocString(
401
L"SELECT * FROM MSNdis_NotifyAdapterRemoval");
402
hr = pSvc->ExecNotificationQueryAsync(lang, query, 0, 0, pDestSink);
403
::SysFreeString(query);
405
printf("ExecNotificationQueryAsync for "
406
"MSNdis_NotifyAdapterRemoval failed with "
407
"hresult of 0x%x\n", hr);
411
::SysFreeString(lang);
417
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
421
static IWbemServices *pSvc = 0;
422
static IWbemLocator *pLoc = NULL;
423
static CNdisSink *pSink = NULL;
425
void ndis_events_deinit(struct ndis_events_data *events)
427
pSvc->CancelAsyncCall(pSink);
435
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
436
int ndis_events_main(HANDLE *read_pipe, HANDLE *event_avail)
438
int main(int argc, char *argv[])
443
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
445
printf("CoInitializeEx() failed - returned 0x%x", hr);
449
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
450
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
451
RPC_C_IMP_LEVEL_IMPERSONATE,
452
NULL, EOAC_SECURE_REFS, NULL);
454
printf("CoInitializeSecurity() failed - returned 0x%x", hr);
458
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
459
IID_IWbemLocator, (LPVOID *) &pLoc);
461
printf("CoCreateInstance() failed - returned 0x%x\n", hr);
466
hr = pLoc->ConnectServer(L"ROOT\\WMI", NULL, NULL, 0, 0, 0, 0, &pSvc);
468
printf("Could not connect to server - error 0x%x\n", hr);
472
printf("Connected to ROOT\\WMI.\n");
474
#ifndef CONFIG_NDIS_EVENTS_INTEGRATED
476
if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
477
printf("Could not find a usable winsock.dll.\n");
483
pSink = new CNdisSink;
485
printf("Could not allocate sink for events.\n");
490
if (register_async_notification(pSink, pSvc) < 0) {
491
printf("Failed to register async notifications\n");
496
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
497
*read_pipe = pSink->read_pipe;
498
*event_avail = pSink->event_avail;
499
#else /* CONFIG_NDIS_EVENTS_INTEGRATED */
500
/* Just wait.. sink will be called with events.. */
501
while (getchar() != '\n');
503
ndis_events_deinit(NULL);
506
#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
511
#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
512
struct ndis_events_data *
513
ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail)
515
struct ndis_events_data *events;
517
events = (struct ndis_events_data *) malloc(sizeof(*events));
521
if (ndis_events_main(read_pipe, event_avail)) {