VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbMon.cpp@ 38438

Last change on this file since 38438 was 38425, checked in by vboxsync, 14 years ago

usb/win: better logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.3 KB
Line 
1/* $Id: VBoxUsbMon.cpp 38425 2011-08-11 20:22:34Z vboxsync $ */
2/** @file
3 * VBox USB Monitor
4 */
5/*
6 * Copyright (C) 2011 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include "VBoxUsbMon.h"
18#include "../cmn/VBoxUsbIdc.h"
19#include <vbox/err.h>
20#include <VBox/usblib.h>
21#include <excpt.h>
22#include <stdio.h>
23
24/*
25 * Note: Must match the VID & PID in the USB driver .inf file!!
26 */
27/*
28 BusQueryDeviceID USB\Vid_80EE&Pid_CAFE
29 BusQueryInstanceID 2
30 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE&Rev_0100
31 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE
32 BusQueryCompatibleIDs USB\Class_ff&SubClass_00&Prot_00
33 BusQueryCompatibleIDs USB\Class_ff&SubClass_00
34 BusQueryCompatibleIDs USB\Class_ff
35*/
36
37#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
38#define szBusQueryHardwareIDs L"USB\\Vid_80EE&Pid_CAFE&Rev_0100\0USB\\Vid_80EE&Pid_CAFE\0\0"
39#define szBusQueryCompatibleIDs L"USB\\Class_ff&SubClass_00&Prot_00\0USB\\Class_ff&SubClass_00\0USB\\Class_ff\0\0"
40
41#define szDeviceTextDescription L"VirtualBox USB"
42
43typedef struct VBOXUSBMONINS
44{
45 void * pvDummy;
46} VBOXUSBMONINS, *PVBOXUSBMONINS;
47
48typedef struct VBOXUSBMONCTX
49{
50 VBOXUSBFLTCTX FltCtx;
51} VBOXUSBMONCTX, *PVBOXUSBMONCTX;
52
53typedef struct VBOXUSBHUB_PNPHOOK
54{
55 VBOXUSBHOOK_ENTRY Hook;
56 bool fUninitFailed;
57} VBOXUSBHUB_PNPHOOK, *PVBOXUSBHUB_PNPHOOK;
58
59typedef struct VBOXUSBHUB_PNPHOOK_COMPLETION
60{
61 VBOXUSBHOOK_REQUEST Rq;
62} VBOXUSBHUB_PNPHOOK_COMPLETION, *PVBOXUSBHUB_PNPHOOK_COMPLETION;
63
64typedef struct VBOXUSBMONGLOBALS
65{
66 PDEVICE_OBJECT pDevObj;
67 VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
68 KEVENT OpenSynchEvent;
69 IO_REMOVE_LOCK RmLock;
70 uint32_t cOpens;
71 volatile LONG ulPreventUnloadOn;
72 PFILE_OBJECT pPreventUnloadFileObj;
73} VBOXUSBMONGLOBALS, *PVBOXUSBMONGLOBALS;
74
75static VBOXUSBMONGLOBALS g_VBoxUsbMonGlobals;
76
77#define VBOXUSBMON_MEMTAG 'MUBV'
78
79PVOID VBoxUsbMonMemAlloc(SIZE_T cbBytes)
80{
81 PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSBMON_MEMTAG);
82 Assert(pvMem);
83 return pvMem;
84}
85
86PVOID VBoxUsbMonMemAllocZ(SIZE_T cbBytes)
87{
88 PVOID pvMem = VBoxUsbMonMemAlloc(cbBytes);
89 if (pvMem)
90 {
91 RtlZeroMemory(pvMem, cbBytes);
92 }
93 return pvMem;
94}
95
96VOID VBoxUsbMonMemFree(PVOID pvMem)
97{
98 ExFreePoolWithTag(pvMem, VBOXUSBMON_MEMTAG);
99}
100
101#define VBOXUSBDBG_STRCASE(_t) \
102 case _t: return #_t
103#define VBOXUSBDBG_STRCASE_UNKNOWN(_v) \
104 default: LOG((__FUNCTION__": Unknown Value (0n%d), (0x%x)\n", _v, _v)); return "Unknown"
105
106static const char* vboxUsbDbgStrPnPMn(UCHAR uMn)
107{
108 switch (uMn)
109 {
110 VBOXUSBDBG_STRCASE(IRP_MN_START_DEVICE);
111 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_REMOVE_DEVICE);
112 VBOXUSBDBG_STRCASE(IRP_MN_REMOVE_DEVICE);
113 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_REMOVE_DEVICE);
114 VBOXUSBDBG_STRCASE(IRP_MN_STOP_DEVICE);
115 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_STOP_DEVICE);
116 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_STOP_DEVICE);
117 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_RELATIONS);
118 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_INTERFACE);
119 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_CAPABILITIES);
120 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCES);
121 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCE_REQUIREMENTS);
122 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_TEXT);
123 VBOXUSBDBG_STRCASE(IRP_MN_FILTER_RESOURCE_REQUIREMENTS);
124 VBOXUSBDBG_STRCASE(IRP_MN_READ_CONFIG);
125 VBOXUSBDBG_STRCASE(IRP_MN_WRITE_CONFIG);
126 VBOXUSBDBG_STRCASE(IRP_MN_EJECT);
127 VBOXUSBDBG_STRCASE(IRP_MN_SET_LOCK);
128 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_ID);
129 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_PNP_DEVICE_STATE);
130 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_BUS_INFORMATION);
131 VBOXUSBDBG_STRCASE(IRP_MN_DEVICE_USAGE_NOTIFICATION);
132 VBOXUSBDBG_STRCASE(IRP_MN_SURPRISE_REMOVAL);
133 VBOXUSBDBG_STRCASE_UNKNOWN(uMn);
134 }
135}
136
137void vboxUsbDbgPrintUnicodeString(PUNICODE_STRING pUnicodeString)
138{
139 PWSTR pStr = pUnicodeString->Buffer;
140 for (int i = 0; i < pUnicodeString->Length/2; ++i)
141 {
142 LOG(("%c", *pStr++));
143 }
144}
145
146/**
147 * Send IRP_MN_QUERY_DEVICE_RELATIONS
148 *
149 * @returns NT Status
150 * @param pDevObj USB device pointer
151 * @param pFileObj Valid file object pointer
152 * @param pDevRelations Pointer to DEVICE_RELATIONS pointer (out)
153 */
154NTSTATUS VBoxUsbMonQueryBusRelations(PDEVICE_OBJECT pDevObj, PFILE_OBJECT pFileObj, PDEVICE_RELATIONS *pDevRelations)
155{
156 IO_STATUS_BLOCK IoStatus;
157 KEVENT Event;
158 NTSTATUS Status;
159 PIRP pIrp;
160 PIO_STACK_LOCATION pSl;
161
162 KeInitializeEvent(&Event, NotificationEvent, FALSE);
163
164 Assert(pDevRelations);
165 *pDevRelations = NULL;
166
167 pIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, &Event, &IoStatus);
168 if (!pIrp)
169 {
170 WARN(("IoBuildDeviceIoControlRequest failed!!\n"));
171 return STATUS_INSUFFICIENT_RESOURCES;
172 }
173 IoStatus.Status = STATUS_NOT_SUPPORTED;
174
175 pSl = IoGetNextIrpStackLocation(pIrp);
176 pSl->MajorFunction = IRP_MJ_PNP;
177 pSl->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
178 pSl->Parameters.QueryDeviceRelations.Type = BusRelations;
179 pSl->FileObject = pFileObj;
180
181 Status = IoCallDriver(pDevObj, pIrp);
182 if (Status == STATUS_PENDING)
183 {
184 LOG(("IoCallDriver returned STATUS_PENDING!!\n"));
185 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
186 Status = IoStatus.Status;
187 }
188
189 if (Status == STATUS_SUCCESS)
190 {
191 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)IoStatus.Information;
192 LOG(("pRel = %p\n", pRel));
193 if (VALID_PTR(pRel))
194 {
195 *pDevRelations = pRel;
196 }
197 else
198 {
199 WARN(("Invalid pointer %p\n", pRel));
200 }
201 }
202 else
203 {
204 WARN(("IRP_MN_QUERY_DEVICE_RELATIONS failed Status(0x%x)\n", Status));
205 }
206
207 LOG(("IoCallDriver returned %x\n", Status));
208 return Status;
209}
210
211static PDRIVER_OBJECT vboxUsbMonHookFindHubDrvObj()
212{
213 NTSTATUS Status = STATUS_UNSUCCESSFUL;
214 UNICODE_STRING szStandardHubName;
215 PDRIVER_OBJECT pDrvObj = NULL;
216 szStandardHubName.Length = 0;
217 szStandardHubName.MaximumLength = 0;
218 szStandardHubName.Buffer = 0;
219 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
220
221 LOG(("Search USB hub\n"));
222 for (int i = 0; i < 16; i++)
223 {
224 WCHAR szwHubName[32] = {};
225 char szHubName[32] = {};
226 ANSI_STRING AnsiName;
227 UNICODE_STRING UnicodeName;
228 PDEVICE_OBJECT pHubDevObj;
229 PFILE_OBJECT pHubFileObj;
230
231 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
232
233 RtlInitAnsiString(&AnsiName, szHubName);
234
235 UnicodeName.Length = 0;
236 UnicodeName.MaximumLength = sizeof (szwHubName);
237 UnicodeName.Buffer = szwHubName;
238
239 RtlInitAnsiString(&AnsiName, szHubName);
240 Status = RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
241 if (Status == STATUS_SUCCESS)
242 {
243 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
244 if (Status == STATUS_SUCCESS)
245 {
246 LOG(("IoGetDeviceObjectPointer for %S returned %p %p\n", szwHubName, pHubDevObj, pHubFileObj));
247
248 if (pHubDevObj->DriverObject
249 && pHubDevObj->DriverObject->DriverName.Buffer
250 && pHubDevObj->DriverObject->DriverName.Length
251 && !RtlCompareUnicodeString(&szStandardHubName, &pHubDevObj->DriverObject->DriverName, TRUE /* case insensitive */))
252 {
253 LOG(("Associated driver"));
254 LOG_USTR(&pHubDevObj->DriverObject->DriverName);
255 LOG(("pnp handler %p\n", pHubDevObj->DriverObject->MajorFunction[IRP_MJ_PNP]));
256
257 pDrvObj = pHubDevObj->DriverObject;
258 /* ensure the driver object is not destroyed */
259 ObReferenceObject(pDrvObj);
260 /* release the file object which will releade the dev objectas well,
261 * as we do not need those anymore */
262 ObDereferenceObject(pHubFileObj);
263 break;
264 }
265 else
266 {
267 LOG(("driver object (0x%p) no match", pHubDevObj->DriverObject));
268 if (pHubDevObj->DriverObject)
269 {
270 if ( pHubDevObj->DriverObject->DriverName.Buffer
271 && pHubDevObj->DriverObject->DriverName.Length)
272 {
273 LOG(("driver name not match, was:"));
274 LOG_USTR(&pHubDevObj->DriverObject->DriverName);
275 LOG(("but expected:"));
276 LOG_USTR(&szStandardHubName);
277 }
278 else
279 {
280 LOG(("driver name is zero, Length(%d), Buffer(0x%p)",
281 pHubDevObj->DriverObject->DriverName.Length, pHubDevObj->DriverObject->DriverName.Buffer));
282 }
283 }
284 else
285 {
286 LOG(("driver object is NULL"));
287 }
288 }
289 ObDereferenceObject(pHubFileObj);
290 }
291 else
292 {
293 WARN(("IoGetDeviceObjectPointer returned Status (0x%x) for (%S)", Status, szwHubName));
294 }
295 }
296 else
297 {
298 WARN(("RtlAnsiStringToUnicodeString failed, Status (0x%x) for Ansu name (%s)", Status, szHubName));
299 }
300 }
301
302 return pDrvObj;
303}
304
305/* NOTE: the stack location data is not the "actual" IRP stack location,
306 * but a copy being preserved on the IRP way down.
307 * See the note in VBoxUsbPnPCompletion for detail */
308static NTSTATUS vboxUsbMonHandlePnPIoctl(PDEVICE_OBJECT pDevObj, PIO_STACK_LOCATION pSl, PIO_STATUS_BLOCK pIoStatus)
309{
310 LOG(("IRQL = %d\n", KeGetCurrentIrql()));
311 switch(pSl->MinorFunction)
312 {
313 case IRP_MN_QUERY_DEVICE_TEXT:
314 {
315 LOG(("IRP_MN_QUERY_DEVICE_TEXT: pIoStatus->Status = %x\n", pIoStatus->Status));
316 if (pIoStatus->Status == STATUS_SUCCESS)
317 {
318 WCHAR *pId = (WCHAR *)pIoStatus->Information;
319 if (VALID_PTR(pId))
320 {
321 KIRQL Iqrl = KeGetCurrentIrql();
322 /* IRQL should be always passive here */
323 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
324 switch(pSl->Parameters.QueryDeviceText.DeviceTextType)
325 {
326 case DeviceTextLocationInformation:
327 LOG(("DeviceTextLocationInformation"));
328 LOG_STRW(pId);
329 break;
330
331 case DeviceTextDescription:
332 LOG(("DeviceTextDescription"));
333 LOG_STRW(pId);
334 if (VBoxUsbFltPdoIsFiltered(pDevObj))
335 {
336 LOG(("PDO (0x%p) is filtered", pDevObj));
337 WCHAR *pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szDeviceTextDescription));
338 if (!pId)
339 {
340 AssertFailed();
341 break;
342 }
343 memcpy(pId, szDeviceTextDescription, sizeof(szDeviceTextDescription));
344 LOG(("NEW szDeviceTextDescription"));
345 LOG_STRW(pId);
346 ExFreePool((PVOID)pIoStatus->Information);
347 pIoStatus->Information = (ULONG_PTR)pId;
348 }
349 else
350 {
351 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
352 }
353 break;
354 default:
355 LOG(("DeviceText %d", pSl->Parameters.QueryDeviceText.DeviceTextType));
356 break;
357 }
358 }
359 else
360 LOG(("Invalid pointer %p\n", pId));
361 }
362 break;
363 }
364
365 case IRP_MN_QUERY_ID:
366 {
367 LOG(("IRP_MN_QUERY_ID: Irp->pIoStatus->Status = %x\n", pIoStatus->Status));
368 if (pIoStatus->Status == STATUS_SUCCESS && pDevObj)
369 {
370 WCHAR *pId = (WCHAR *)pIoStatus->Information;
371#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
372 WCHAR *pTmp;
373#endif
374 if (VALID_PTR(pId))
375 {
376 KIRQL Iqrl = KeGetCurrentIrql();
377 /* IRQL should be always passive here */
378 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
379
380 switch (pSl->Parameters.QueryDeviceRelations.Type)
381 {
382 case BusQueryInstanceID:
383 LOG(("BusQueryInstanceID"));
384 LOG_STRW(pId);
385 break;
386
387 case BusQueryDeviceID:
388 {
389 LOG(("BusQueryDeviceID"));
390 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryDeviceId));
391 if (!pId)
392 {
393 WARN(("ExAllocatePool failed"));
394 break;
395 }
396
397 BOOLEAN bFiltered = FALSE;
398 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
399 if (Status != STATUS_SUCCESS || !bFiltered)
400 {
401 if(Status == STATUS_SUCCESS)
402 {
403 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
404 }
405 else
406 {
407 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
408 }
409 ExFreePool(pId);
410 break;
411 }
412
413 LOG(("PDO (0x%p) is filtered", pDevObj));
414 ExFreePool((PVOID)pIoStatus->Information);
415 memcpy(pId, szBusQueryDeviceId, sizeof(szBusQueryDeviceId));
416 pIoStatus->Information = (ULONG_PTR)pId;
417 break;
418 }
419 case BusQueryHardwareIDs:
420 {
421 LOG(("BusQueryHardwareIDs"));
422#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
423 while(*pId) //MULTI_SZ
424 {
425 LOG_STRW(pId);
426 while(*pId) pId++;
427 pId++;
428 }
429#endif
430 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryHardwareIDs));
431 if (!pId)
432 {
433 WARN(("ExAllocatePool failed"));
434 break;
435 }
436
437 BOOLEAN bFiltered = FALSE;
438 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
439 if (Status != STATUS_SUCCESS || !bFiltered)
440 {
441 if(Status == STATUS_SUCCESS)
442 {
443 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
444 }
445 else
446 {
447 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
448 }
449 ExFreePool(pId);
450 break;
451 }
452
453 LOG(("PDO (0x%p) is filtered", pDevObj));
454
455 memcpy(pId, szBusQueryHardwareIDs, sizeof(szBusQueryHardwareIDs));
456#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
457 LOG(("NEW BusQueryHardwareIDs"));
458 pTmp = pId;
459 while(*pTmp) //MULTI_SZ
460 {
461
462 LOG_STRW(pTmp);
463 while(*pTmp) pTmp++;
464 pTmp++;
465 }
466#endif
467 ExFreePool((PVOID)pIoStatus->Information);
468 pIoStatus->Information = (ULONG_PTR)pId;
469 break;
470 }
471 case BusQueryCompatibleIDs:
472 LOG(("BusQueryCompatibleIDs"));
473#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
474 while(*pId) //MULTI_SZ
475 {
476 LOG_STRW(pId);
477 while(*pId) pId++;
478 pId++;
479 }
480#endif
481 if (VBoxUsbFltPdoIsFiltered(pDevObj))
482 {
483 LOG(("PDO (0x%p) is filtered", pDevObj));
484 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryCompatibleIDs));
485 if (!pId)
486 {
487 WARN(("ExAllocatePool failed"));
488 break;
489 }
490 memcpy(pId, szBusQueryCompatibleIDs, sizeof(szBusQueryCompatibleIDs));
491#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
492 LOG(("NEW BusQueryCompatibleIDs"));
493 pTmp = pId;
494 while(*pTmp) //MULTI_SZ
495 {
496 LOG_STRW(pTmp);
497 while(*pTmp) pTmp++;
498 pTmp++;
499 }
500#endif
501 ExFreePool((PVOID)pIoStatus->Information);
502 pIoStatus->Information = (ULONG_PTR)pId;
503 }
504 else
505 {
506 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
507 }
508 break;
509 }
510 }
511 else
512 {
513 LOG(("Invalid pointer %p\n", pId));
514 }
515 }
516 break;
517 }
518
519#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
520 case IRP_MN_QUERY_DEVICE_RELATIONS:
521 {
522 switch(pSl->Parameters.QueryDeviceRelations.Type)
523 {
524 case BusRelations:
525 {
526 LOG(("BusRelations\n"));
527
528 if (pIoStatus->Status == STATUS_SUCCESS)
529 {
530 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)pIoStatus->Information;
531 LOG(("pRel = %p\n", pRel));
532 if (VALID_PTR(pRel))
533 {
534 for (unsigned i=0;i<pRel->Count;i++)
535 {
536 if (VBoxUsbFltPdoIsFiltered(pDevObj))
537 LOG(("New PDO %p\n", pRel->Objects[i]));
538 }
539 }
540 else
541 LOG(("Invalid pointer %p\n", pRel));
542 }
543 break;
544 }
545 case TargetDeviceRelation:
546 LOG(("TargetDeviceRelation\n"));
547 break;
548 case RemovalRelations:
549 LOG(("RemovalRelations\n"));
550 break;
551 case EjectionRelations:
552 LOG(("EjectionRelations\n"));
553 break;
554 }
555 break;
556 }
557
558 case IRP_MN_QUERY_CAPABILITIES:
559 {
560 LOG(("IRP_MN_QUERY_CAPABILITIES: pIoStatus->Status = %x\n", pIoStatus->Status));
561 if (pIoStatus->Status == STATUS_SUCCESS)
562 {
563 PDEVICE_CAPABILITIES pCaps = pSl->Parameters.DeviceCapabilities.Capabilities;
564 if (VALID_PTR(pCaps))
565 {
566 LOG(("Caps.SilentInstall = %d\n", pCaps->SilentInstall));
567 LOG(("Caps.UniqueID = %d\n", pCaps->UniqueID ));
568 LOG(("Caps.Address = %d\n", pCaps->Address ));
569 LOG(("Caps.UINumber = %d\n", pCaps->UINumber ));
570 }
571 else
572 LOG(("Invalid pointer %p\n", pCaps));
573 }
574 break;
575 }
576
577 default:
578 break;
579#endif
580 } /*switch */
581
582 LOG(("Done returns %x (IRQL = %d)\n", pIoStatus->Status, KeGetCurrentIrql()));
583 return pIoStatus->Status;
584}
585
586NTSTATUS _stdcall VBoxUsbPnPCompletion(DEVICE_OBJECT *pDevObj, IRP *pIrp, void *pvContext)
587{
588 LOG(("Completion PDO(0x%p), IRP(0x%p), Status(0x%x)\n", pDevObj, pIrp, pIrp->IoStatus.Status));
589 ASSERT_WARN(pvContext, ("zero context"));
590
591 PVBOXUSBHOOK_REQUEST pRequest = (PVBOXUSBHOOK_REQUEST)pvContext;
592 /* NOTE: despite a regular IRP processing the stack location in our completion
593 * differs from those of the PnP hook since the hook is invoked in the "context" of the calle,
594 * while the completion is in the "coller" context in terms of IRP,
595 * so the completion stack location is one level "up" here.
596 *
597 * Moreover we CAN NOT access irp stack location in the completion because we might not have one at all
598 * in case the hooked driver is at the top of the irp call stack
599 *
600 * This is why we use the stack location we saved on IRP way down.
601 * */
602 PIO_STACK_LOCATION pSl = &pRequest->OldLocation;
603 ASSERT_WARN(pIrp == pRequest->pIrp, ("completed IRP(0x%x) not match request IRP(0x%x)", pIrp, pRequest->pIrp));
604 /* NOTE: we can not rely on pDevObj passed in IoCompletion since it may be zero
605 * in case IRP was created with extra stack locations and the caller did not initialize
606 * the IO_STACK_LOCATION::DeviceObject */
607 DEVICE_OBJECT *pRealDevObj = pRequest->pDevObj;
608// Assert(!pDevObj || pDevObj == pRealDevObj);
609// Assert(pSl->DeviceObject == pDevObj);
610
611 switch(pSl->MinorFunction)
612 {
613 case IRP_MN_QUERY_DEVICE_TEXT:
614 case IRP_MN_QUERY_ID:
615#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
616 case IRP_MN_QUERY_DEVICE_RELATIONS:
617 case IRP_MN_QUERY_CAPABILITIES:
618#endif
619 if (NT_SUCCESS(pIrp->IoStatus.Status))
620 {
621 vboxUsbMonHandlePnPIoctl(pRealDevObj, pSl, &pIrp->IoStatus);
622 }
623 else
624 {
625 ASSERT_WARN(pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED, ("Irp failed with status(0x%x)", pIrp->IoStatus.Status));
626 }
627 break;
628
629 case IRP_MN_SURPRISE_REMOVAL:
630 case IRP_MN_REMOVE_DEVICE:
631 if (NT_SUCCESS(pIrp->IoStatus.Status))
632 {
633 VBoxUsbFltPdoRemove(pRealDevObj);
634 }
635 else
636 {
637 AssertFailed();
638 }
639 break;
640
641 /* These two IRPs are received when the PnP subsystem has determined the id of the newly arrived device */
642 /* IRP_MN_START_DEVICE only arrives if it's a USB device of a known class or with a present host driver */
643 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
644 case IRP_MN_QUERY_RESOURCES:
645 if (NT_SUCCESS(pIrp->IoStatus.Status) || pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
646 {
647 VBoxUsbFltPdoAddCompleted(pRealDevObj);
648 }
649 else
650 {
651 AssertFailed();
652 }
653 break;
654
655 default:
656 break;
657 }
658
659 LOG(("<==PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x), Sl PDO(0x%p), Compl PDO(0x%p)\n",
660 vboxUsbDbgStrPnPMn(pSl->MinorFunction),
661 pRealDevObj, pIrp, pIrp->IoStatus.Status,
662 pSl->DeviceObject, pDevObj));
663#ifdef DEBUG_misha
664 NTSTATUS tmpStatus = pIrp->IoStatus.Status;
665#endif
666 NTSTATUS Status = VBoxUsbHookRequestComplete(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp, pRequest);
667 VBoxUsbMonMemFree(pRequest);
668#ifdef DEBUG_misha
669 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
670 {
671 Assert(pIrp->IoStatus.Status == tmpStatus);
672 }
673#endif
674 VBoxUsbHookRelease(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
675 return Status;
676}
677
678/**
679 * Device PnP hook
680 *
681 * @param pDevObj Device object.
682 * @param pIrp Request packet.
683 */
684NTSTATUS _stdcall VBoxUsbMonPnPHook(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
685{
686 LOG(("==>PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x)\n", vboxUsbDbgStrPnPMn(IoGetCurrentIrpStackLocation(pIrp)->MinorFunction), pDevObj, pIrp, pIrp->IoStatus.Status));
687
688 if(!VBoxUsbHookRetain(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook))
689 {
690 WARN(("VBoxUsbHookRetain failed"));
691 return VBoxUsbHookRequestPassDownHookSkip(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp);
692 }
693
694 PVBOXUSBHUB_PNPHOOK_COMPLETION pCompletion = (PVBOXUSBHUB_PNPHOOK_COMPLETION)VBoxUsbMonMemAlloc(sizeof (*pCompletion));
695 if (!pCompletion)
696 {
697 WARN(("VBoxUsbMonMemAlloc failed"));
698 VBoxUsbHookRelease(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
699 pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
700 pIrp->IoStatus.Information = 0;
701 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
702 return STATUS_INSUFFICIENT_RESOURCES;
703 }
704
705 NTSTATUS Status = VBoxUsbHookRequestPassDownHookCompletion(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
706#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
707 if (Status != STATUS_PENDING)
708 {
709 LOG(("Request completed, Status(0x%x)", Status));
710 VBoxUsbHookVerifyCompletion(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, &pCompletion->Rq, pIrp);
711 }
712 else
713 {
714 LOG(("Request pending"));
715 }
716#endif
717 return Status;
718}
719
720
721static NTSTATUS vboxUsbMonHookCheckInit()
722{
723 static bool fIsHookInited = false;
724 if (fIsHookInited)
725 {
726 LOG(("hook inited already, success"));
727 return STATUS_SUCCESS;
728 }
729 PDRIVER_OBJECT pDrvObj = vboxUsbMonHookFindHubDrvObj();
730 if (pDrvObj)
731 {
732 VBoxUsbHookInit(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDrvObj, IRP_MJ_PNP, VBoxUsbMonPnPHook);
733 fIsHookInited = true;
734 LOG(("SUCCESS"));
735 return STATUS_SUCCESS;
736 }
737 WARN(("hub drv obj not found, fail"));
738 return STATUS_UNSUCCESSFUL;
739}
740
741static NTSTATUS vboxUsbMonHookInstall()
742{
743#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
744 return STATUS_SUCCESS;
745#else
746 if (g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed)
747 {
748 WARN(("trying to hook usbhub pnp after the unhook failed, do nothing & pretend success"));
749 return STATUS_SUCCESS;
750 }
751 return VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
752#endif
753}
754
755static NTSTATUS vboxUsbMonHookUninstall()
756{
757#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
758 return STATUS_SUCCESS;
759#else
760 NTSTATUS Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
761 if (!NT_SUCCESS(Status))
762 {
763 AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)\n", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
764 g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed = true;
765 }
766 return Status;
767#endif
768}
769
770
771static NTSTATUS vboxUsbMonCheckTermStuff()
772{
773 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
774 Executive, KernelMode,
775 FALSE, /* BOOLEAN Alertable */
776 NULL /* IN PLARGE_INTEGER Timeout */
777 );
778 AssertRelease(Status == STATUS_SUCCESS);
779
780 do
781 {
782 if (--g_VBoxUsbMonGlobals.cOpens)
783 break;
784
785 Status = vboxUsbMonHookUninstall();
786
787 NTSTATUS tmpStatus = VBoxUsbFltTerm();
788 if (!NT_SUCCESS(tmpStatus))
789 {
790 /* this means a driver state is screwed up, KeBugCheckEx here ? */
791 AssertReleaseFailed();
792 }
793 } while (0);
794
795 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
796
797 return Status;
798}
799
800static NTSTATUS vboxUsbMonCheckInitStuff()
801{
802 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
803 Executive, KernelMode,
804 FALSE, /* BOOLEAN Alertable */
805 NULL /* IN PLARGE_INTEGER Timeout */
806 );
807 if (Status == STATUS_SUCCESS)
808 {
809 do
810 {
811 if (g_VBoxUsbMonGlobals.cOpens++)
812 {
813 LOG(("opens: %d, success", g_VBoxUsbMonGlobals.cOpens));
814 break;
815 }
816
817 Status = VBoxUsbFltInit();
818 if (NT_SUCCESS(Status))
819 {
820 Status = vboxUsbMonHookCheckInit();
821 if (NT_SUCCESS(Status))
822 {
823 Status = vboxUsbMonHookInstall();
824 if (NT_SUCCESS(Status))
825 {
826 Status = STATUS_SUCCESS;
827 LOG(("succeded!!"));
828 break;
829 }
830 else
831 {
832 WARN(("vboxUsbMonHookInstall failed, Status (0x%x)", Status));
833 }
834 }
835 else
836 {
837 WARN(("vboxUsbMonHookCheckInit failed, Status (0x%x)", Status));
838 }
839 VBoxUsbFltTerm();
840 }
841 else
842 {
843 WARN(("VBoxUsbFltInit failed, Status (0x%x)", Status));
844 }
845
846 --g_VBoxUsbMonGlobals.cOpens;
847 Assert(!g_VBoxUsbMonGlobals.cOpens);
848 } while (0);
849
850 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
851 }
852 else
853 {
854 WARN(("KeWaitForSingleObject failed, Status (0x%x)", Status));
855 }
856 return Status;
857}
858
859static NTSTATUS vboxUsbMonContextCreate(PVBOXUSBMONCTX *ppCtx)
860{
861 NTSTATUS Status;
862 *ppCtx = NULL;
863 PVBOXUSBMONCTX pFileCtx = (PVBOXUSBMONCTX)VBoxUsbMonMemAllocZ(sizeof (*pFileCtx));
864 if (pFileCtx)
865 {
866 Status = vboxUsbMonCheckInitStuff();
867 if (Status == STATUS_SUCCESS)
868 {
869 Status = VBoxUsbFltCreate(&pFileCtx->FltCtx);
870 if (Status == STATUS_SUCCESS)
871 {
872 *ppCtx = pFileCtx;
873 LOG(("succeeded!!"));
874 return STATUS_SUCCESS;
875 }
876 else
877 {
878 WARN(("VBoxUsbFltCreate failed"));
879 }
880 vboxUsbMonCheckTermStuff();
881 }
882 else
883 {
884 WARN(("vboxUsbMonCheckInitStuff failed"));
885 }
886 VBoxUsbMonMemFree(pFileCtx);
887 }
888 else
889 {
890 WARN(("VBoxUsbMonMemAllocZ failed"));
891 Status = STATUS_NO_MEMORY;
892 }
893
894 return Status;
895}
896
897static NTSTATUS vboxUsbMonContextClose(PVBOXUSBMONCTX pCtx)
898{
899 NTSTATUS Status = VBoxUsbFltClose(&pCtx->FltCtx);
900 if (Status == STATUS_SUCCESS)
901 {
902 Status = vboxUsbMonCheckTermStuff();
903 Assert(Status == STATUS_SUCCESS);
904 /* ignore the failure */
905 VBoxUsbMonMemFree(pCtx);
906 }
907
908 return Status;
909}
910
911static NTSTATUS _stdcall VBoxUsbMonClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
912{
913 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
914 PFILE_OBJECT pFileObj = pStack->FileObject;
915 Assert(pFileObj->FsContext);
916 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
917
918 LOG(("VBoxUsbMonClose"));
919
920 NTSTATUS Status = vboxUsbMonContextClose(pCtx);
921 if (Status != STATUS_SUCCESS)
922 {
923 WARN(("vboxUsbMonContextClose failed, Status (0x%x), prefent unload", Status));
924 if (!InterlockedExchange(&g_VBoxUsbMonGlobals.ulPreventUnloadOn, 1))
925 {
926 LOGREL(("ulPreventUnloadOn not set, preventing unload\n"));
927 UNICODE_STRING UniName;
928 PDEVICE_OBJECT pTmpDevObj;
929 RtlInitUnicodeString(&UniName, USBMON_DEVICE_NAME_NT);
930 NTSTATUS tmpStatus = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_VBoxUsbMonGlobals.pPreventUnloadFileObj, &pTmpDevObj);
931 AssertRelease(NT_SUCCESS(tmpStatus));
932 AssertRelease(pTmpDevObj == pDevObj);
933 }
934 else
935 {
936 WARN(("ulPreventUnloadOn already set"));
937 }
938 LOG(("success!!"));
939 Status = STATUS_SUCCESS;
940 }
941 pFileObj->FsContext = NULL;
942 pIrp->IoStatus.Status = Status;
943 pIrp->IoStatus.Information = 0;
944 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
945 return Status;
946}
947
948
949static NTSTATUS _stdcall VBoxUsbMonCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
950{
951 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
952 PFILE_OBJECT pFileObj = pStack->FileObject;
953 NTSTATUS Status;
954
955 LOG(("VBoxUSBMonCreate"));
956
957 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
958 {
959 WARN(("trying to open as a directory"));
960 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
961 pIrp->IoStatus.Information = 0;
962 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
963 return STATUS_NOT_A_DIRECTORY;
964 }
965
966 pFileObj->FsContext = NULL;
967 PVBOXUSBMONCTX pCtx = NULL;
968 Status = vboxUsbMonContextCreate(&pCtx);
969 if (Status == STATUS_SUCCESS)
970 {
971 Assert(pCtx);
972 pFileObj->FsContext = pCtx;
973 }
974 else
975 {
976 WARN(("vboxUsbMonContextCreate failed Status (0x%x)", Status));
977 }
978
979 pIrp->IoStatus.Status = Status;
980 pIrp->IoStatus.Information = 0;
981 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
982 return Status;
983}
984
985static int VBoxUsbMonSetNotifyEvent(PVBOXUSBMONCTX pContext, HANDLE hEvent)
986{
987 int rc = VBoxUsbFltSetNotifyEvent(&pContext->FltCtx, hEvent);
988 return rc;
989}
990
991static int VBoxUsbMonFltAdd(PVBOXUSBMONCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
992{
993#ifdef VBOXUSBMON_DBG_NO_FILTERS
994 static uintptr_t idDummy = 1;
995 *pId = idDummy;
996 ++idDummy;
997 return VINF_SUCCESS;
998#else
999 int rc = VBoxUsbFltAdd(&pContext->FltCtx, pFilter, pId);
1000 return rc;
1001#endif
1002}
1003
1004static int VBoxUsbMonFltRemove(PVBOXUSBMONCTX pContext, uintptr_t uId)
1005{
1006#ifdef VBOXUSBMON_DBG_NO_FILTERS
1007 return VINF_SUCCESS;
1008#else
1009 int rc = VBoxUsbFltRemove(&pContext->FltCtx, uId);
1010 return rc;
1011#endif
1012}
1013
1014static NTSTATUS VBoxUsbMonRunFilters(PVBOXUSBMONCTX pContext)
1015{
1016 NTSTATUS Status = VBoxUsbFltFilterCheck(&pContext->FltCtx);
1017 return Status;
1018}
1019
1020static NTSTATUS VBoxUsbMonGetDevice(PVBOXUSBMONCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
1021{
1022 NTSTATUS Status = VBoxUsbFltGetDevice(&pContext->FltCtx, hDevice, pInfo);
1023 return Status;
1024}
1025
1026static NTSTATUS vboxUsbMonIoctlDispatch(PVBOXUSBMONCTX pContext, ULONG Ctl, PVOID pvBuffer, ULONG cbInBuffer, ULONG cbOutBuffer, ULONG_PTR* pInfo)
1027{
1028 NTSTATUS Status = STATUS_SUCCESS;
1029 ULONG_PTR Info = 0;
1030 switch (Ctl)
1031 {
1032 case SUPUSBFLT_IOCTL_GET_VERSION:
1033 {
1034 PUSBSUP_VERSION pOut = (PUSBSUP_VERSION)pvBuffer;
1035
1036 LOG(("SUPUSBFLT_IOCTL_GET_VERSION\n"));
1037 if (!pvBuffer || cbOutBuffer != sizeof(*pOut) || cbInBuffer != 0)
1038 {
1039 WARN(("SUPUSBFLT_IOCTL_GET_VERSION: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
1040 cbInBuffer, 0, cbOutBuffer, sizeof (*pOut)));
1041 Status = STATUS_INVALID_PARAMETER;
1042 break;
1043 }
1044 pOut->u32Major = USBMON_MAJOR_VERSION;
1045 pOut->u32Minor = USBMON_MINOR_VERSION;
1046 Info = sizeof (*pOut);
1047 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1048 break;
1049 }
1050
1051 case SUPUSBFLT_IOCTL_ADD_FILTER:
1052 {
1053 PUSBFILTER pFilter = (PUSBFILTER)pvBuffer;
1054 PUSBSUP_FLTADDOUT pOut = (PUSBSUP_FLTADDOUT)pvBuffer;
1055 uintptr_t uId = 0;
1056 int rc;
1057 if (RT_UNLIKELY(!pvBuffer || cbInBuffer != sizeof (*pFilter) || cbOutBuffer != sizeof (*pOut)))
1058 {
1059 WARN(("SUPUSBFLT_IOCTL_ADD_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
1060 cbInBuffer, sizeof (*pFilter), cbOutBuffer, sizeof (*pOut)));
1061 Status = STATUS_INVALID_PARAMETER;
1062 break;
1063 }
1064
1065 rc = VBoxUsbMonFltAdd(pContext, pFilter, &uId);
1066 pOut->rc = rc;
1067 pOut->uId = uId;
1068 Info = sizeof (*pOut);
1069 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1070 break;
1071 }
1072
1073 case SUPUSBFLT_IOCTL_REMOVE_FILTER:
1074 {
1075 uintptr_t *pIn = (uintptr_t *)pvBuffer;
1076 int *pRc = (int *)pvBuffer;
1077
1078 if (!pvBuffer || cbInBuffer != sizeof (*pIn) || (cbOutBuffer && cbOutBuffer != sizeof (*pRc)))
1079 {
1080 WARN(("SUPUSBFLT_IOCTL_REMOVE_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
1081 cbInBuffer, sizeof (*pIn), cbOutBuffer, 0));
1082 Status = STATUS_INVALID_PARAMETER;
1083 break;
1084 }
1085 LOG(("SUPUSBFLT_IOCTL_REMOVE_FILTER %x\n", *pIn));
1086 int rc = VBoxUsbMonFltRemove(pContext, *pIn);
1087 if (cbOutBuffer)
1088 {
1089 /* we've validated that already */
1090 Assert(cbOutBuffer == *pRc);
1091 *pRc = rc;
1092 Info = sizeof (*pRc);
1093 }
1094 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1095 break;
1096 }
1097
1098 case SUPUSBFLT_IOCTL_RUN_FILTERS:
1099 {
1100 if (pvBuffer || cbInBuffer || cbOutBuffer)
1101 {
1102 WARN(("SUPUSBFLT_IOCTL_RUN_FILTERS: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
1103 cbInBuffer, 0, cbOutBuffer, 0));
1104 Status = STATUS_INVALID_PARAMETER;
1105 break;
1106 }
1107 LOG(("SUPUSBFLT_IOCTL_RUN_FILTERS \n"));
1108 Status = VBoxUsbMonRunFilters(pContext);
1109 ASSERT_WARN(Status != STATUS_PENDING, ("status pending!"));
1110 break;
1111 }
1112
1113 case SUPUSBFLT_IOCTL_GET_DEVICE:
1114 {
1115 HVBOXUSBDEVUSR hDevice = *((HVBOXUSBDEVUSR*)pvBuffer);
1116 PUSBSUP_GETDEV_MON pOut = (PUSBSUP_GETDEV_MON)pvBuffer;
1117 if (!pvBuffer || cbInBuffer != sizeof (hDevice) || cbOutBuffer < sizeof (*pOut))
1118 {
1119 WARN(("SUPUSBFLT_IOCTL_GET_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected >= %d.\n",
1120 cbInBuffer, sizeof (hDevice), cbOutBuffer, sizeof (*pOut)));
1121 Status = STATUS_INVALID_PARAMETER;
1122 break;
1123 }
1124
1125 Status = VBoxUsbMonGetDevice(pContext, hDevice, pOut);
1126
1127 if (NT_SUCCESS(Status))
1128 {
1129 Info = sizeof (*pOut);
1130 }
1131 else
1132 {
1133 WARN(("VBoxUsbMonGetDevice fail 0x%x", Status));
1134 }
1135 break;
1136 }
1137
1138 case SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT:
1139 {
1140 PUSBSUP_SET_NOTIFY_EVENT pSne = (PUSBSUP_SET_NOTIFY_EVENT)pvBuffer;
1141 if (!pvBuffer || cbInBuffer != sizeof (*pSne) || cbOutBuffer != sizeof (*pSne))
1142 {
1143 WARN(("SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
1144 cbInBuffer, sizeof (*pSne), cbOutBuffer, sizeof (*pSne)));
1145 Status = STATUS_INVALID_PARAMETER;
1146 break;
1147 }
1148
1149 pSne->u.rc = VBoxUsbMonSetNotifyEvent(pContext, pSne->u.hEvent);
1150 Info = sizeof (*pSne);
1151 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1152 break;
1153 }
1154
1155 default:
1156 WARN(("Unknown code 0x%x", Ctl));
1157 Status = STATUS_INVALID_PARAMETER;
1158 break;
1159 }
1160
1161 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending!"));
1162
1163 *pInfo = Info;
1164 return Status;
1165}
1166
1167static NTSTATUS _stdcall VBoxUsbMonDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1168{
1169 ULONG_PTR Info = 0;
1170 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1171 if (NT_SUCCESS(Status))
1172 {
1173 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1174 PFILE_OBJECT pFileObj = pSl->FileObject;
1175 Assert(pFileObj);
1176 Assert(pFileObj->FsContext);
1177 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1178 Assert(pCtx);
1179 Status = vboxUsbMonIoctlDispatch(pCtx,
1180 pSl->Parameters.DeviceIoControl.IoControlCode,
1181 pIrp->AssociatedIrp.SystemBuffer,
1182 pSl->Parameters.DeviceIoControl.InputBufferLength,
1183 pSl->Parameters.DeviceIoControl.OutputBufferLength,
1184 &Info);
1185 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending"));
1186
1187 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1188 }
1189 else
1190 {
1191 WARN(("IoAcquireRemoveLock failed Status (0x%x)", Status));
1192 }
1193
1194 pIrp->IoStatus.Information = Info;
1195 pIrp->IoStatus.Status = Status;
1196 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1197 return Status;
1198}
1199
1200static NTSTATUS vboxUsbMonInternalIoctlDispatch(ULONG Ctl, PVOID pvBuffer, ULONG_PTR *pInfo)
1201{
1202 NTSTATUS Status = STATUS_SUCCESS;
1203 *pInfo = 0;
1204 switch (Ctl)
1205 {
1206 case VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION:
1207 {
1208 PVBOXUSBIDC_VERSION pOut = (PVBOXUSBIDC_VERSION)pvBuffer;
1209
1210 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION\n"));
1211 if (!pvBuffer)
1212 {
1213 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION: Buffer is NULL\n"));
1214 Status = STATUS_INVALID_PARAMETER;
1215 break;
1216 }
1217 pOut->u32Major = VBOXUSBIDC_VERSION_MAJOR;
1218 pOut->u32Minor = VBOXUSBIDC_VERSION_MINOR;
1219 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1220 break;
1221 }
1222
1223 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP:
1224 {
1225 PVBOXUSBIDC_PROXY_STARTUP pOut = (PVBOXUSBIDC_PROXY_STARTUP)pvBuffer;
1226
1227 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP\n"));
1228 if (!pvBuffer)
1229 {
1230 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP: Buffer is NULL\n"));
1231 Status = STATUS_INVALID_PARAMETER;
1232 break;
1233 }
1234
1235 pOut->u.hDev = VBoxUsbFltProxyStarted(pOut->u.pPDO);
1236 ASSERT_WARN(pOut->u.hDev, ("zero hDev"));
1237 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1238 break;
1239 }
1240
1241 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN:
1242 {
1243 PVBOXUSBIDC_PROXY_TEARDOWN pOut = (PVBOXUSBIDC_PROXY_TEARDOWN)pvBuffer;
1244
1245 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN\n"));
1246 if (!pvBuffer)
1247 {
1248 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN: Buffer is NULL\n"));
1249 Status = STATUS_INVALID_PARAMETER;
1250 break;
1251 }
1252
1253 ASSERT_WARN(pOut->hDev, ("zero hDev"));
1254 VBoxUsbFltProxyStopped(pOut->hDev);
1255 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1256 break;
1257 }
1258
1259 default:
1260 {
1261 WARN(("Unknown code 0x%x", Ctl));
1262 Status = STATUS_INVALID_PARAMETER;
1263 break;
1264 }
1265 }
1266
1267 return Status;
1268}
1269
1270static NTSTATUS _stdcall VBoxUsbMonInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1271{
1272 ULONG_PTR Info = 0;
1273 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1274 if (NT_SUCCESS(Status))
1275 {
1276 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1277 Status = vboxUsbMonInternalIoctlDispatch(pSl->Parameters.DeviceIoControl.IoControlCode,
1278 pSl->Parameters.Others.Argument1,
1279 &Info);
1280 Assert(Status != STATUS_PENDING);
1281
1282 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1283 }
1284
1285 pIrp->IoStatus.Information = Info;
1286 pIrp->IoStatus.Status = Status;
1287 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1288 return Status;
1289}
1290
1291/**
1292 * Unload the driver.
1293 *
1294 * @param pDrvObj Driver object.
1295 */
1296static void _stdcall VBoxUsbMonUnload(PDRIVER_OBJECT pDrvObj)
1297{
1298 LOG(("VBoxUSBMonUnload pDrvObj (0x%p)\n", pDrvObj));
1299
1300 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1301
1302 Assert(!g_VBoxUsbMonGlobals.cOpens);
1303
1304 UNICODE_STRING DosName;
1305 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1306 NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
1307
1308 IoDeleteDevice(g_VBoxUsbMonGlobals.pDevObj);
1309
1310 /* cleanup the logger */
1311 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
1312 if (pLogger)
1313 {
1314 RTLogDestroy(pLogger);
1315 }
1316 pLogger = RTLogSetDefaultInstance(NULL);
1317 if (pLogger)
1318 {
1319 RTLogDestroy(pLogger);
1320 }
1321}
1322
1323RT_C_DECLS_BEGIN
1324NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
1325RT_C_DECLS_END
1326
1327/**
1328 * Driver entry point.
1329 *
1330 * @returns appropriate status code.
1331 * @param pDrvObj Pointer to driver object.
1332 * @param pRegPath Registry base path.
1333 */
1334NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1335{
1336#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1337 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
1338 RTLogDestinations(0, "debugger");
1339#endif
1340
1341 LOGREL(("Built %s %s", __DATE__, __TIME__));
1342
1343 memset (&g_VBoxUsbMonGlobals, 0, sizeof (g_VBoxUsbMonGlobals));
1344 KeInitializeEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, SynchronizationEvent, TRUE /* signaled */);
1345 IoInitializeRemoveLock(&g_VBoxUsbMonGlobals.RmLock, VBOXUSBMON_MEMTAG, 1, 100);
1346 UNICODE_STRING DevName;
1347 PDEVICE_OBJECT pDevObj;
1348 /* create the device */
1349 RtlInitUnicodeString(&DevName, USBMON_DEVICE_NAME_NT);
1350 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1351 if (NT_SUCCESS(Status))
1352 {
1353 Status = IoCreateDevice(pDrvObj, sizeof (VBOXUSBMONINS), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
1354 if (NT_SUCCESS(Status))
1355 {
1356 UNICODE_STRING DosName;
1357 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1358 Status = IoCreateSymbolicLink(&DosName, &DevName);
1359 if (NT_SUCCESS(Status))
1360 {
1361 PVBOXUSBMONINS pDevExt = (PVBOXUSBMONINS)pDevObj->DeviceExtension;
1362 memset(pDevExt, 0, sizeof(*pDevExt));
1363
1364 pDrvObj->DriverUnload = VBoxUsbMonUnload;
1365 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxUsbMonCreate;
1366 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxUsbMonClose;
1367 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxUsbMonDeviceControl;
1368 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxUsbMonInternalDeviceControl;
1369
1370 g_VBoxUsbMonGlobals.pDevObj = pDevObj;
1371 LOG(("VBoxUSBMon::DriverEntry returning STATUS_SUCCESS\n"));
1372 return STATUS_SUCCESS;
1373 }
1374 IoDeleteDevice(pDevObj);
1375 }
1376 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1377 }
1378
1379 return Status;
1380}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette