VirtualBox

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

Last change on this file since 56315 was 56315, checked in by vboxsync, 9 years ago

whitespace

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.6 KB
Line 
1/* $Id: VBoxUsbMon.cpp 56315 2015-06-09 22:52:04Z vboxsync $ */
2/** @file
3 * VBox USB Monitor
4 */
5/*
6 * Copyright (C) 2011-2015 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
64/*
65 * Comment out VBOX_USB3PORT definition to disable hooking to multiple drivers (#6509)
66 */
67#define VBOX_USB3PORT
68
69#ifdef VBOX_USB3PORT
70#define VBOXUSBMON_MAXDRIVERS 5
71typedef struct VBOXUSB_PNPDRIVER
72{
73 PDRIVER_OBJECT DriverObject;
74 VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
75 PDRIVER_DISPATCH pfnHookStub;
76} VBOXUSB_PNPDRIVER, *PVBOXUSB_PNPDRIVER;
77#endif /* !VBOX_USB3PORT */
78
79typedef struct VBOXUSBMONGLOBALS
80{
81 PDEVICE_OBJECT pDevObj;
82#ifdef VBOX_USB3PORT
83 VBOXUSB_PNPDRIVER pDrivers[VBOXUSBMON_MAXDRIVERS];
84#else /* !VBOX_USB3PORT */
85 VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
86#endif /* !VBOX_USB3PORT */
87 KEVENT OpenSynchEvent;
88 IO_REMOVE_LOCK RmLock;
89 uint32_t cOpens;
90 volatile LONG ulPreventUnloadOn;
91 PFILE_OBJECT pPreventUnloadFileObj;
92} VBOXUSBMONGLOBALS, *PVBOXUSBMONGLOBALS;
93
94static VBOXUSBMONGLOBALS g_VBoxUsbMonGlobals;
95
96#define VBOXUSBMON_MEMTAG 'MUBV'
97
98PVOID VBoxUsbMonMemAlloc(SIZE_T cbBytes)
99{
100 PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSBMON_MEMTAG);
101 Assert(pvMem);
102 return pvMem;
103}
104
105PVOID VBoxUsbMonMemAllocZ(SIZE_T cbBytes)
106{
107 PVOID pvMem = VBoxUsbMonMemAlloc(cbBytes);
108 if (pvMem)
109 {
110 RtlZeroMemory(pvMem, cbBytes);
111 }
112 return pvMem;
113}
114
115VOID VBoxUsbMonMemFree(PVOID pvMem)
116{
117 ExFreePoolWithTag(pvMem, VBOXUSBMON_MEMTAG);
118}
119
120#define VBOXUSBDBG_STRCASE(_t) \
121 case _t: return #_t
122#define VBOXUSBDBG_STRCASE_UNKNOWN(_v) \
123 default: LOG((__FUNCTION__": Unknown Value (0n%d), (0x%x)", _v, _v)); return "Unknown"
124
125static const char* vboxUsbDbgStrPnPMn(UCHAR uMn)
126{
127 switch (uMn)
128 {
129 VBOXUSBDBG_STRCASE(IRP_MN_START_DEVICE);
130 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_REMOVE_DEVICE);
131 VBOXUSBDBG_STRCASE(IRP_MN_REMOVE_DEVICE);
132 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_REMOVE_DEVICE);
133 VBOXUSBDBG_STRCASE(IRP_MN_STOP_DEVICE);
134 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_STOP_DEVICE);
135 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_STOP_DEVICE);
136 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_RELATIONS);
137 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_INTERFACE);
138 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_CAPABILITIES);
139 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCES);
140 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCE_REQUIREMENTS);
141 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_TEXT);
142 VBOXUSBDBG_STRCASE(IRP_MN_FILTER_RESOURCE_REQUIREMENTS);
143 VBOXUSBDBG_STRCASE(IRP_MN_READ_CONFIG);
144 VBOXUSBDBG_STRCASE(IRP_MN_WRITE_CONFIG);
145 VBOXUSBDBG_STRCASE(IRP_MN_EJECT);
146 VBOXUSBDBG_STRCASE(IRP_MN_SET_LOCK);
147 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_ID);
148 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_PNP_DEVICE_STATE);
149 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_BUS_INFORMATION);
150 VBOXUSBDBG_STRCASE(IRP_MN_DEVICE_USAGE_NOTIFICATION);
151 VBOXUSBDBG_STRCASE(IRP_MN_SURPRISE_REMOVAL);
152 VBOXUSBDBG_STRCASE_UNKNOWN(uMn);
153 }
154}
155
156void vboxUsbDbgPrintUnicodeString(PUNICODE_STRING pUnicodeString)
157{
158 PWSTR pStr = pUnicodeString->Buffer;
159 for (int i = 0; i < pUnicodeString->Length/2; ++i)
160 {
161 LOG(("%c", *pStr++));
162 }
163}
164
165/**
166 * Send IRP_MN_QUERY_DEVICE_RELATIONS
167 *
168 * @returns NT Status
169 * @param pDevObj USB device pointer
170 * @param pFileObj Valid file object pointer
171 * @param pDevRelations Pointer to DEVICE_RELATIONS pointer (out)
172 */
173NTSTATUS VBoxUsbMonQueryBusRelations(PDEVICE_OBJECT pDevObj, PFILE_OBJECT pFileObj, PDEVICE_RELATIONS *pDevRelations)
174{
175 IO_STATUS_BLOCK IoStatus;
176 KEVENT Event;
177 NTSTATUS Status;
178 PIRP pIrp;
179 PIO_STACK_LOCATION pSl;
180
181 KeInitializeEvent(&Event, NotificationEvent, FALSE);
182
183 Assert(pDevRelations);
184 *pDevRelations = NULL;
185
186 pIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, &Event, &IoStatus);
187 if (!pIrp)
188 {
189 WARN(("IoBuildDeviceIoControlRequest failed!!"));
190 return STATUS_INSUFFICIENT_RESOURCES;
191 }
192 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
193
194 pSl = IoGetNextIrpStackLocation(pIrp);
195 pSl->MajorFunction = IRP_MJ_PNP;
196 pSl->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
197 pSl->Parameters.QueryDeviceRelations.Type = BusRelations;
198 pSl->FileObject = pFileObj;
199
200 Status = IoCallDriver(pDevObj, pIrp);
201 if (Status == STATUS_PENDING)
202 {
203 LOG(("IoCallDriver returned STATUS_PENDING!!"));
204 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
205 Status = IoStatus.Status;
206 }
207
208 if (Status == STATUS_SUCCESS)
209 {
210 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)IoStatus.Information;
211 LOG(("pRel = %p", pRel));
212 if (VALID_PTR(pRel))
213 {
214 *pDevRelations = pRel;
215 }
216 else
217 {
218 WARN(("Invalid pointer %p", pRel));
219 }
220 }
221 else
222 {
223 WARN(("IRP_MN_QUERY_DEVICE_RELATIONS failed Status(0x%x)", Status));
224 }
225
226 LOG(("IoCallDriver returned %x", Status));
227 return Status;
228}
229
230RT_C_DECLS_BEGIN
231/* these two come from IFS Kit, which is not included in 2K DDK we use,
232 * although they are documented and exported in ntoskrnl,
233 * and both should be present for >= XP according to MSDN */
234NTKERNELAPI
235NTSTATUS
236ObQueryNameString(
237 __in PVOID Object,
238 __out_bcount_opt(Length) POBJECT_NAME_INFORMATION ObjectNameInfo,
239 __in ULONG Length,
240 __out PULONG ReturnLength
241 );
242
243NTKERNELAPI
244PDEVICE_OBJECT
245IoGetLowerDeviceObject(
246 __in PDEVICE_OBJECT DeviceObject
247 );
248
249RT_C_DECLS_END
250
251typedef DECLCALLBACK(VOID) FNVBOXUSBDEVNAMEMATCHER(PDEVICE_OBJECT pDo, PUNICODE_STRING pName, PVOID pvMatcher);
252typedef FNVBOXUSBDEVNAMEMATCHER *PFNVBOXUSBDEVNAMEMATCHER;
253
254static NTSTATUS vboxUsbObjCheckName(PDEVICE_OBJECT pDo, PFNVBOXUSBDEVNAMEMATCHER pfnMatcher, PVOID pvMatcher)
255{
256 union
257 {
258 OBJECT_NAME_INFORMATION Info;
259 char buf[1024];
260 } buf;
261 ULONG cbLength = 0;
262
263 POBJECT_NAME_INFORMATION pInfo = &buf.Info;
264 NTSTATUS Status = ObQueryNameString(pDo, &buf.Info, sizeof (buf), &cbLength);
265 if (!NT_SUCCESS(Status))
266 {
267 if (STATUS_INFO_LENGTH_MISMATCH != Status)
268 {
269 WARN(("ObQueryNameString failed 0x%x", Status));
270 return Status;
271 }
272
273 LOG(("ObQueryNameString returned STATUS_INFO_LENGTH_MISMATCH, required size %d", cbLength));
274
275 pInfo = (POBJECT_NAME_INFORMATION)VBoxUsbMonMemAlloc(cbLength);
276 if (!pInfo)
277 {
278 WARN(("VBoxUsbMonMemAlloc failed"));
279 return STATUS_NO_MEMORY;
280 }
281 Status = ObQueryNameString(pDo, pInfo, cbLength, &cbLength);
282 if (!NT_SUCCESS(Status))
283 {
284 WARN(("ObQueryNameString second try failed 0x%x", Status));
285 VBoxUsbMonMemFree(pInfo);
286 return Status;
287 }
288 }
289
290 /* we've got the name! */
291 LOG(("got the name:"));
292 LOG_USTR(&pInfo->Name);
293 pfnMatcher(pDo, &pInfo->Name, pvMatcher);
294
295 if (&buf.Info != pInfo)
296 {
297 LOG(("freeing allocated pInfo(0x%p)", pInfo));
298 VBoxUsbMonMemFree(pInfo);
299 }
300 else
301 {
302 LOG(("no freeing info needed"));
303 }
304
305 return STATUS_SUCCESS;
306}
307
308
309typedef DECLCALLBACK(BOOLEAN) FNVBOXUSBDEVSTACKWALKER(PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pCurDo, PVOID pvContext);
310typedef FNVBOXUSBDEVSTACKWALKER *PFNVBOXUSBDEVSTACKWALKER;
311
312VOID vboxUsbObjDevStackWalk(PDEVICE_OBJECT pDo, PFNVBOXUSBDEVSTACKWALKER pfnWalker, PVOID pvWalker)
313{
314 LOG(("==>tree walk for Do 0x%p", pDo));
315 PDEVICE_OBJECT pCurDo = pDo;
316 ObReferenceObject(pCurDo); /* <- to make sure the dereferencing logic below works correctly */
317 do
318 {
319 LOG(("==Do 0x%p", pCurDo));
320#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
321 {
322 union
323 {
324 OBJECT_NAME_INFORMATION Info;
325 char buf[1024];
326 } buf;
327 ULONG cbLength = 0;
328
329 NTSTATUS tmpStatus = ObQueryNameString(pCurDo, &buf.Info, sizeof (buf), &cbLength);
330 if (NT_SUCCESS(tmpStatus))
331 {
332 LOG((" Obj name:"));
333 LOG_USTR(&buf.Info.Name);
334 }
335 else
336 {
337 if (STATUS_INFO_LENGTH_MISMATCH != tmpStatus)
338 {
339 WARN(("ObQueryNameString failed 0x%x", tmpStatus));
340 }
341 else
342 {
343 WARN(("ObQueryNameString STATUS_INFO_LENGTH_MISMATCH, required %d", cbLength));
344 }
345 }
346
347 if (pCurDo->DriverObject
348 && pCurDo->DriverObject->DriverName.Buffer
349 && pCurDo->DriverObject->DriverName.Length)
350 {
351 LOG((" Drv Obj(0x%p), name:", pCurDo->DriverObject));
352 LOG_USTR(&pCurDo->DriverObject->DriverName);
353 }
354 else
355 {
356 LOG((" No Drv Name, Drv Obj(0x%p)", pCurDo->DriverObject));
357 if (pCurDo->DriverObject)
358 {
359 LOG((" driver name is zero, Length(%d), Buffer(0x%p)",
360 pCurDo->DriverObject->DriverName.Length, pCurDo->DriverObject->DriverName.Buffer));
361 }
362 else
363 {
364 LOG((" driver object is NULL"));
365 }
366 }
367 }
368#endif
369 if (!pfnWalker(pDo, pCurDo, pvWalker))
370 {
371 LOG(("the walker said to stop"));
372 ObDereferenceObject(pCurDo);
373 break;
374 }
375
376 PDEVICE_OBJECT pLowerDo = IoGetLowerDeviceObject(pCurDo);
377 ObDereferenceObject(pCurDo);
378 if (!pLowerDo)
379 {
380 LOG(("IoGetLowerDeviceObject returnned NULL, stop"));
381 break;
382 }
383 pCurDo = pLowerDo;
384 } while (1);
385
386 LOG(("<==tree walk"));
387}
388
389static DECLCALLBACK(BOOLEAN) vboxUsbObjNamePrefixMatch(PUNICODE_STRING pName, PUNICODE_STRING pNamePrefix, BOOLEAN fCaseInSensitive)
390{
391 LOG(("Matching prefix:"));
392 LOG_USTR(pNamePrefix);
393 if (pNamePrefix->Length > pName->Length)
394 {
395 LOG(("Pregix Length(%d) > Name Length(%d)", pNamePrefix->Length, pName->Length));
396 return FALSE;
397 }
398
399 LOG(("Pregix Length(%d) <= Name Length(%d)", pNamePrefix->Length, pName->Length));
400
401 UNICODE_STRING NamePrefix = *pName;
402 NamePrefix.Length = pNamePrefix->Length;
403 LONG rc = RtlCompareUnicodeString(&NamePrefix, pNamePrefix, fCaseInSensitive);
404
405 if (!rc)
406 {
407 LOG(("prefix MATCHED!"));
408 return TRUE;
409 }
410
411 LOG(("prefix NOT matched!"));
412 return FALSE;
413}
414
415typedef struct VBOXUSBOBJNAMEPREFIXMATCHER
416{
417 PUNICODE_STRING pNamePrefix;
418 BOOLEAN fMatched;
419} VBOXUSBOBJNAMEPREFIXMATCHER, *PVBOXUSBOBJNAMEPREFIXMATCHER;
420
421static DECLCALLBACK(VOID) vboxUsbObjDevNamePrefixMatcher(PDEVICE_OBJECT pDo, PUNICODE_STRING pName, PVOID pvMatcher)
422{
423 PVBOXUSBOBJNAMEPREFIXMATCHER pData = (PVBOXUSBOBJNAMEPREFIXMATCHER)pvMatcher;
424 PUNICODE_STRING pNamePrefix = pData->pNamePrefix;
425 ASSERT_WARN(!pData->fMatched, ("match flag already set!"));
426 pData->fMatched = vboxUsbObjNamePrefixMatch(pName, pNamePrefix, TRUE /* fCaseInSensitive */);
427 LOG(("match result (%d)", (int)pData->fMatched));
428}
429
430typedef struct VBOXUSBOBJDRVOBJSEARCHER
431{
432 PDEVICE_OBJECT pDevObj;
433 PUNICODE_STRING pDrvName;
434 PUNICODE_STRING pPdoNamePrefix;
435 ULONG fFlags;
436} VBOXUSBOBJDRVOBJSEARCHER, *PVBOXUSBOBJDRVOBJSEARCHER;
437
438static DECLCALLBACK(BOOLEAN) vboxUsbObjDevObjSearcherWalker(PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pCurDo, PVOID pvContext)
439{
440 PVBOXUSBOBJDRVOBJSEARCHER pData = (PVBOXUSBOBJDRVOBJSEARCHER)pvContext;
441 ASSERT_WARN(!pData->pDevObj, ("non-null dev object (0x%p) on enter", pData->pDevObj));
442 pData->pDevObj = NULL;
443 if (pCurDo->DriverObject
444 && pCurDo->DriverObject->DriverName.Buffer
445 && pCurDo->DriverObject->DriverName.Length
446 && !RtlCompareUnicodeString(pData->pDrvName, &pCurDo->DriverObject->DriverName, TRUE /* case insensitive */))
447 {
448 LOG(("MATCHED driver:"));
449 LOG_USTR(&pCurDo->DriverObject->DriverName);
450 if ((pData->fFlags & VBOXUSBMONHUBWALK_F_ALL) != VBOXUSBMONHUBWALK_F_ALL)
451 {
452 VBOXUSBOBJNAMEPREFIXMATCHER Data = {0};
453 Data.pNamePrefix = pData->pPdoNamePrefix;
454 NTSTATUS Status = vboxUsbObjCheckName(pCurDo, vboxUsbObjDevNamePrefixMatcher, &Data);
455 if (!NT_SUCCESS(Status))
456 {
457 WARN(("vboxUsbObjCheckName failed Status (0x%x)", Status));
458 return TRUE;
459 }
460
461
462 LOG(("prefix match result (%d)", Data.fMatched));
463 if ((pData->fFlags & VBOXUSBMONHUBWALK_F_FDO) == VBOXUSBMONHUBWALK_F_FDO)
464 {
465 LOG(("VBOXUSBMONHUBWALK_F_FDO"));
466 if (Data.fMatched)
467 {
468 LOG(("this is a PDO object, skip it and stop search"));
469 /* stop search as we will not find FDO here */
470 return FALSE;
471 }
472
473 LOG(("this is a FDO object, MATCHED!!"));
474 }
475 else if ((pData->fFlags & VBOXUSBMONHUBWALK_F_PDO) == VBOXUSBMONHUBWALK_F_PDO)
476 {
477 LOG(("VBOXUSBMONHUBWALK_F_PDO"));
478 if (!Data.fMatched)
479 {
480 LOG(("this is a FDO object, skip it and continue search"));
481 /* continue seach since since this could be a nested hub that would have a usbhub-originated PDO */
482 return TRUE;
483 }
484
485 LOG(("this is a PDO object, MATCHED!!"));
486 }
487
488 }
489 else
490 {
491 LOG(("VBOXUSBMONHUBWALK_F_ALL"));
492 LOG(("either PDO or FDO, MATCHED!!"));
493 }
494
495 /* ensure the dev object is not destroyed */
496 ObReferenceObject(pCurDo);
497 pData->pDevObj = pCurDo;
498 /* we are done */
499 return FALSE;
500 }
501 else
502 {
503 LOG(("driver object (0x%p) no match", pCurDo->DriverObject));
504 if (pCurDo->DriverObject)
505 {
506 if ( pCurDo->DriverObject->DriverName.Buffer
507 && pCurDo->DriverObject->DriverName.Length)
508 {
509 LOG(("driver name not match, was:"));
510 LOG_USTR(&pCurDo->DriverObject->DriverName);
511 LOG(("but expected:"));
512 LOG_USTR(pData->pDrvName);
513 }
514 else
515 {
516 LOG(("driver name is zero, Length(%d), Buffer(0x%p)",
517 pCurDo->DriverObject->DriverName.Length, pCurDo->DriverObject->DriverName.Buffer));
518 }
519 }
520 else
521 {
522 LOG(("driver object is NULL"));
523 }
524 }
525 return TRUE;
526}
527
528VOID vboxUsbMonHubDevWalk(PFNVBOXUSBMONDEVWALKER pfnWalker, PVOID pvWalker, ULONG fFlags)
529{
530 NTSTATUS Status = STATUS_UNSUCCESSFUL;
531#ifndef VBOX_USB3PORT
532 UNICODE_STRING szStandardHubName;
533 PDRIVER_OBJECT pDrvObj = NULL;
534 szStandardHubName.Length = 0;
535 szStandardHubName.MaximumLength = 0;
536 szStandardHubName.Buffer = 0;
537 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
538 UNICODE_STRING szStandardHubPdoNamePrefix;
539 szStandardHubPdoNamePrefix.Length = 0;
540 szStandardHubPdoNamePrefix.MaximumLength = 0;
541 szStandardHubPdoNamePrefix.Buffer = 0;
542 RtlInitUnicodeString(&szStandardHubPdoNamePrefix, L"\\Device\\USBPDO-");
543
544 for (int i = 0; i < 16; i++)
545 {
546 WCHAR szwHubName[32] = {0};
547 char szHubName[32] = {0};
548 ANSI_STRING AnsiName;
549 UNICODE_STRING UnicodeName;
550 PDEVICE_OBJECT pHubDevObj;
551 PFILE_OBJECT pHubFileObj;
552
553 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
554
555 RtlInitAnsiString(&AnsiName, szHubName);
556
557 UnicodeName.Length = 0;
558 UnicodeName.MaximumLength = sizeof (szwHubName);
559 UnicodeName.Buffer = szwHubName;
560
561 RtlInitAnsiString(&AnsiName, szHubName);
562 Status = RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
563 if (Status == STATUS_SUCCESS)
564 {
565 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
566 if (Status == STATUS_SUCCESS)
567 {
568 LOG(("IoGetDeviceObjectPointer for %S returned %p %p", szwHubName, pHubDevObj, pHubFileObj));
569
570 VBOXUSBOBJDRVOBJSEARCHER Data = {0};
571 Data.pDrvName = &szStandardHubName;
572 Data.pPdoNamePrefix = &szStandardHubPdoNamePrefix;
573 Data.fFlags = fFlags;
574
575 vboxUsbObjDevStackWalk(pHubDevObj, vboxUsbObjDevObjSearcherWalker, &Data);
576 if (Data.pDevObj)
577 {
578 LOG(("found hub dev obj (0x%p)", Data.pDevObj));
579 if (!pfnWalker(pHubFileObj, pHubDevObj, Data.pDevObj, pvWalker))
580 {
581 LOG(("the walker said to stop"));
582 ObDereferenceObject(Data.pDevObj);
583 ObDereferenceObject(pHubFileObj);
584 break;
585 }
586
587 LOG(("going forward.."));
588 ObDereferenceObject(Data.pDevObj);
589 }
590 else
591 {
592 LOG(("no hub driver obj found"));
593 ASSERT_WARN(!Data.pDevObj, ("non-null dev obj poiter returned (0x%p)", Data.pDevObj));
594 }
595
596 /* this will dereference both file and dev obj */
597 ObDereferenceObject(pHubFileObj);
598 }
599 else
600 {
601 LOG(("IoGetDeviceObjectPointer returned Status (0x%x) for (%S)", Status, szwHubName));
602 }
603 }
604 else
605 {
606 WARN(("RtlAnsiStringToUnicodeString failed, Status (0x%x) for Ansu name (%s)", Status, szHubName));
607 }
608 }
609#else /* VBOX_USB3PORT */
610 PWSTR szwHubList;
611 Status = IoGetDeviceInterfaces(&GUID_DEVINTERFACE_USB_HUB, NULL, 0, &szwHubList);
612 if (Status != STATUS_SUCCESS)
613 {
614 LOG(("IoGetDeviceInterfaces failed with %d\n", Status));
615 return;
616 }
617 if (szwHubList)
618 {
619 UNICODE_STRING UnicodeName;
620 PDEVICE_OBJECT pHubDevObj;
621 PFILE_OBJECT pHubFileObj;
622 PWSTR szwHubName = szwHubList;
623 while (*szwHubName != UNICODE_NULL)
624 {
625 RtlInitUnicodeString(&UnicodeName, szwHubName);
626 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
627 if (Status == STATUS_SUCCESS)
628 {
629 /** @todo Replace %S with something else as it does not work for PWSTR. */
630 LOG(("IoGetDeviceObjectPointer for %S returned %p %p", szwHubName, pHubDevObj, pHubFileObj));
631 if (!pfnWalker(pHubFileObj, pHubDevObj, pHubDevObj, pvWalker))
632 {
633 LOG(("the walker said to stop"));
634 ObDereferenceObject(pHubFileObj);
635 break;
636 }
637
638 LOG(("going forward.."));
639 ObDereferenceObject(pHubFileObj);
640 }
641 szwHubName += wcslen(szwHubName) + 1;
642 }
643 ExFreePool(szwHubList);
644 }
645#endif /* VBOX_USB3PORT */
646}
647
648typedef struct VBOXUSBMONFINDHUBWALKER
649{
650 PDRIVER_OBJECT pDrvObj;
651} VBOXUSBMONFINDHUBWALKER, *PVBOXUSBMONFINDHUBWALKER;
652
653static DECLCALLBACK(BOOLEAN) vboxUsbMonFindHubDrvObjWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
654{
655 PVBOXUSBMONFINDHUBWALKER pData = (PVBOXUSBMONFINDHUBWALKER)pvContext;
656 PDRIVER_OBJECT pDrvObj = pHubDo->DriverObject;
657
658 ASSERT_WARN(!pData->pDrvObj, ("pDrvObj expected null on enter, but was(0x%p)", pData->pDrvObj));
659 if(pDrvObj)
660 {
661 LOG(("found driver object 0x%p", pDrvObj));
662 ObReferenceObject(pDrvObj);
663 pData->pDrvObj = pDrvObj;
664 return FALSE;
665 }
666
667 WARN(("null pDrvObj!"));
668 return TRUE;
669}
670
671static PDRIVER_OBJECT vboxUsbMonHookFindHubDrvObj()
672{
673 NTSTATUS Status = STATUS_UNSUCCESSFUL;
674 UNICODE_STRING szStandardHubName;
675 PDRIVER_OBJECT pDrvObj = NULL;
676 szStandardHubName.Length = 0;
677 szStandardHubName.MaximumLength = 0;
678 szStandardHubName.Buffer = 0;
679 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
680
681 LOG(("Search USB hub"));
682 VBOXUSBMONFINDHUBWALKER Data = {0};
683 vboxUsbMonHubDevWalk(vboxUsbMonFindHubDrvObjWalker, &Data, VBOXUSBMONHUBWALK_F_ALL);
684 if (Data.pDrvObj)
685 {
686 LOG(("returning driver object 0x%p", Data.pDrvObj));
687 }
688 else
689 {
690 WARN(("no hub driver object found!"));
691 }
692 return Data.pDrvObj;
693}
694
695/* NOTE: the stack location data is not the "actual" IRP stack location,
696 * but a copy being preserved on the IRP way down.
697 * See the note in VBoxUsbPnPCompletion for detail */
698static NTSTATUS vboxUsbMonHandlePnPIoctl(PDEVICE_OBJECT pDevObj, PIO_STACK_LOCATION pSl, PIO_STATUS_BLOCK pIoStatus)
699{
700 LOG(("IRQL = %d", KeGetCurrentIrql()));
701 switch(pSl->MinorFunction)
702 {
703 case IRP_MN_QUERY_DEVICE_TEXT:
704 {
705 LOG(("IRP_MN_QUERY_DEVICE_TEXT: pIoStatus->Status = %x", pIoStatus->Status));
706 if (pIoStatus->Status == STATUS_SUCCESS)
707 {
708 WCHAR *pId = (WCHAR *)pIoStatus->Information;
709 if (VALID_PTR(pId))
710 {
711 KIRQL Iqrl = KeGetCurrentIrql();
712 /* IRQL should be always passive here */
713 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
714 switch(pSl->Parameters.QueryDeviceText.DeviceTextType)
715 {
716 case DeviceTextLocationInformation:
717 LOG(("DeviceTextLocationInformation"));
718 LOG_STRW(pId);
719 break;
720
721 case DeviceTextDescription:
722 LOG(("DeviceTextDescription"));
723 LOG_STRW(pId);
724 if (VBoxUsbFltPdoIsFiltered(pDevObj))
725 {
726 LOG(("PDO (0x%p) is filtered", pDevObj));
727 WCHAR *pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szDeviceTextDescription));
728 if (!pId)
729 {
730 AssertFailed();
731 break;
732 }
733 memcpy(pId, szDeviceTextDescription, sizeof(szDeviceTextDescription));
734 LOG(("NEW szDeviceTextDescription"));
735 LOG_STRW(pId);
736 ExFreePool((PVOID)pIoStatus->Information);
737 pIoStatus->Information = (ULONG_PTR)pId;
738 }
739 else
740 {
741 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
742 }
743 break;
744 default:
745 LOG(("DeviceText %d", pSl->Parameters.QueryDeviceText.DeviceTextType));
746 break;
747 }
748 }
749 else
750 LOG(("Invalid pointer %p", pId));
751 }
752 break;
753 }
754
755 case IRP_MN_QUERY_ID:
756 {
757 LOG(("IRP_MN_QUERY_ID: Irp->pIoStatus->Status = %x", pIoStatus->Status));
758 if (pIoStatus->Status == STATUS_SUCCESS && pDevObj)
759 {
760 WCHAR *pId = (WCHAR *)pIoStatus->Information;
761#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
762 WCHAR *pTmp;
763#endif
764 if (VALID_PTR(pId))
765 {
766 KIRQL Iqrl = KeGetCurrentIrql();
767 /* IRQL should be always passive here */
768 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
769
770 switch (pSl->Parameters.QueryDeviceRelations.Type)
771 {
772 case BusQueryInstanceID:
773 LOG(("BusQueryInstanceID"));
774 LOG_STRW(pId);
775 break;
776
777 case BusQueryDeviceID:
778 {
779 LOG(("BusQueryDeviceID"));
780 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryDeviceId));
781 if (!pId)
782 {
783 WARN(("ExAllocatePool failed"));
784 break;
785 }
786
787 BOOLEAN bFiltered = FALSE;
788 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
789 if (Status != STATUS_SUCCESS || !bFiltered)
790 {
791 if(Status == STATUS_SUCCESS)
792 {
793 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
794 }
795 else
796 {
797 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
798 }
799 ExFreePool(pId);
800 break;
801 }
802
803 LOG(("PDO (0x%p) is filtered", pDevObj));
804 ExFreePool((PVOID)pIoStatus->Information);
805 memcpy(pId, szBusQueryDeviceId, sizeof(szBusQueryDeviceId));
806 pIoStatus->Information = (ULONG_PTR)pId;
807 break;
808 }
809 case BusQueryHardwareIDs:
810 {
811 LOG(("BusQueryHardwareIDs"));
812#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
813 while(*pId) //MULTI_SZ
814 {
815 LOG_STRW(pId);
816 while(*pId) pId++;
817 pId++;
818 }
819#endif
820 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryHardwareIDs));
821 if (!pId)
822 {
823 WARN(("ExAllocatePool failed"));
824 break;
825 }
826
827 BOOLEAN bFiltered = FALSE;
828 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
829 if (Status != STATUS_SUCCESS || !bFiltered)
830 {
831 if(Status == STATUS_SUCCESS)
832 {
833 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
834 }
835 else
836 {
837 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
838 }
839 ExFreePool(pId);
840 break;
841 }
842
843 LOG(("PDO (0x%p) is filtered", pDevObj));
844
845 memcpy(pId, szBusQueryHardwareIDs, sizeof(szBusQueryHardwareIDs));
846#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
847 LOG(("NEW BusQueryHardwareIDs"));
848 pTmp = pId;
849 while(*pTmp) //MULTI_SZ
850 {
851
852 LOG_STRW(pTmp);
853 while(*pTmp) pTmp++;
854 pTmp++;
855 }
856#endif
857 ExFreePool((PVOID)pIoStatus->Information);
858 pIoStatus->Information = (ULONG_PTR)pId;
859 break;
860 }
861 case BusQueryCompatibleIDs:
862 LOG(("BusQueryCompatibleIDs"));
863#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
864 while(*pId) //MULTI_SZ
865 {
866 LOG_STRW(pId);
867 while(*pId) pId++;
868 pId++;
869 }
870#endif
871 if (VBoxUsbFltPdoIsFiltered(pDevObj))
872 {
873 LOG(("PDO (0x%p) is filtered", pDevObj));
874 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryCompatibleIDs));
875 if (!pId)
876 {
877 WARN(("ExAllocatePool failed"));
878 break;
879 }
880 memcpy(pId, szBusQueryCompatibleIDs, sizeof(szBusQueryCompatibleIDs));
881#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
882 LOG(("NEW BusQueryCompatibleIDs"));
883 pTmp = pId;
884 while(*pTmp) //MULTI_SZ
885 {
886 LOG_STRW(pTmp);
887 while(*pTmp) pTmp++;
888 pTmp++;
889 }
890#endif
891 ExFreePool((PVOID)pIoStatus->Information);
892 pIoStatus->Information = (ULONG_PTR)pId;
893 }
894 else
895 {
896 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
897 }
898 break;
899 }
900 }
901 else
902 {
903 LOG(("Invalid pointer %p", pId));
904 }
905 }
906 break;
907 }
908
909#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
910 case IRP_MN_QUERY_DEVICE_RELATIONS:
911 {
912 switch(pSl->Parameters.QueryDeviceRelations.Type)
913 {
914 case BusRelations:
915 {
916 LOG(("BusRelations"));
917
918 if (pIoStatus->Status == STATUS_SUCCESS)
919 {
920 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)pIoStatus->Information;
921 LOG(("pRel = %p", pRel));
922 if (VALID_PTR(pRel))
923 {
924 for (unsigned i=0;i<pRel->Count;i++)
925 {
926 if (VBoxUsbFltPdoIsFiltered(pDevObj))
927 LOG(("New PDO %p", pRel->Objects[i]));
928 }
929 }
930 else
931 LOG(("Invalid pointer %p", pRel));
932 }
933 break;
934 }
935 case TargetDeviceRelation:
936 LOG(("TargetDeviceRelation"));
937 break;
938 case RemovalRelations:
939 LOG(("RemovalRelations"));
940 break;
941 case EjectionRelations:
942 LOG(("EjectionRelations"));
943 break;
944 }
945 break;
946 }
947
948 case IRP_MN_QUERY_CAPABILITIES:
949 {
950 LOG(("IRP_MN_QUERY_CAPABILITIES: pIoStatus->Status = %x", pIoStatus->Status));
951 if (pIoStatus->Status == STATUS_SUCCESS)
952 {
953 PDEVICE_CAPABILITIES pCaps = pSl->Parameters.DeviceCapabilities.Capabilities;
954 if (VALID_PTR(pCaps))
955 {
956 LOG(("Caps.SilentInstall = %d", pCaps->SilentInstall));
957 LOG(("Caps.UniqueID = %d", pCaps->UniqueID ));
958 LOG(("Caps.Address = %d", pCaps->Address ));
959 LOG(("Caps.UINumber = %d", pCaps->UINumber ));
960 }
961 else
962 LOG(("Invalid pointer %p", pCaps));
963 }
964 break;
965 }
966
967 default:
968 break;
969#endif
970 } /*switch */
971
972 LOG(("Done returns %x (IRQL = %d)", pIoStatus->Status, KeGetCurrentIrql()));
973 return pIoStatus->Status;
974}
975
976NTSTATUS _stdcall VBoxUsbPnPCompletion(DEVICE_OBJECT *pDevObj, IRP *pIrp, void *pvContext)
977{
978 LOG(("Completion PDO(0x%p), IRP(0x%p), Status(0x%x)", pDevObj, pIrp, pIrp->IoStatus.Status));
979 ASSERT_WARN(pvContext, ("zero context"));
980
981 PVBOXUSBHOOK_REQUEST pRequest = (PVBOXUSBHOOK_REQUEST)pvContext;
982 /* NOTE: despite a regular IRP processing the stack location in our completion
983 * differs from those of the PnP hook since the hook is invoked in the "context" of the calle,
984 * while the completion is in the "coller" context in terms of IRP,
985 * so the completion stack location is one level "up" here.
986 *
987 * Moreover we CAN NOT access irp stack location in the completion because we might not have one at all
988 * in case the hooked driver is at the top of the irp call stack
989 *
990 * This is why we use the stack location we saved on IRP way down.
991 * */
992 PIO_STACK_LOCATION pSl = &pRequest->OldLocation;
993 ASSERT_WARN(pIrp == pRequest->pIrp, ("completed IRP(0x%x) not match request IRP(0x%x)", pIrp, pRequest->pIrp));
994 /* NOTE: we can not rely on pDevObj passed in IoCompletion since it may be zero
995 * in case IRP was created with extra stack locations and the caller did not initialize
996 * the IO_STACK_LOCATION::DeviceObject */
997 DEVICE_OBJECT *pRealDevObj = pRequest->pDevObj;
998// Assert(!pDevObj || pDevObj == pRealDevObj);
999// Assert(pSl->DeviceObject == pDevObj);
1000
1001 switch(pSl->MinorFunction)
1002 {
1003 case IRP_MN_QUERY_DEVICE_TEXT:
1004 case IRP_MN_QUERY_ID:
1005#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1006 case IRP_MN_QUERY_DEVICE_RELATIONS:
1007 case IRP_MN_QUERY_CAPABILITIES:
1008#endif
1009 if (NT_SUCCESS(pIrp->IoStatus.Status))
1010 {
1011 vboxUsbMonHandlePnPIoctl(pRealDevObj, pSl, &pIrp->IoStatus);
1012 }
1013 else
1014 {
1015 ASSERT_WARN(pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED, ("Irp failed with status(0x%x)", pIrp->IoStatus.Status));
1016 }
1017 break;
1018
1019 case IRP_MN_SURPRISE_REMOVAL:
1020 case IRP_MN_REMOVE_DEVICE:
1021 if (NT_SUCCESS(pIrp->IoStatus.Status))
1022 {
1023 VBoxUsbFltPdoRemove(pRealDevObj);
1024 }
1025 else
1026 {
1027 AssertFailed();
1028 }
1029 break;
1030
1031 /* These two IRPs are received when the PnP subsystem has determined the id of the newly arrived device */
1032 /* IRP_MN_START_DEVICE only arrives if it's a USB device of a known class or with a present host driver */
1033 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
1034 case IRP_MN_QUERY_RESOURCES:
1035 if (NT_SUCCESS(pIrp->IoStatus.Status) || pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
1036 {
1037 VBoxUsbFltPdoAddCompleted(pRealDevObj);
1038 }
1039 else
1040 {
1041 AssertFailed();
1042 }
1043 break;
1044
1045 default:
1046 break;
1047 }
1048
1049 LOG(("<==PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x), Sl PDO(0x%p), Compl PDO(0x%p)",
1050 vboxUsbDbgStrPnPMn(pSl->MinorFunction),
1051 pRealDevObj, pIrp, pIrp->IoStatus.Status,
1052 pSl->DeviceObject, pDevObj));
1053#ifdef DEBUG_misha
1054 NTSTATUS tmpStatus = pIrp->IoStatus.Status;
1055#endif
1056#ifdef VBOX_USB3PORT
1057 PVBOXUSBHOOK_ENTRY pHook = pRequest->pHook;
1058#else /* !VBOX_USB3PORT */
1059 PVBOXUSBHOOK_ENTRY pHook = &g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook;
1060#endif /* !VBOX_USB3PORT */
1061 NTSTATUS Status = VBoxUsbHookRequestComplete(pHook, pDevObj, pIrp, pRequest);
1062 VBoxUsbMonMemFree(pRequest);
1063#ifdef DEBUG_misha
1064 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
1065 {
1066 Assert(pIrp->IoStatus.Status == tmpStatus);
1067 }
1068#endif
1069 VBoxUsbHookRelease(pHook);
1070 return Status;
1071}
1072
1073/**
1074 * Device PnP hook
1075 *
1076 * @param pDevObj Device object.
1077 * @param pIrp Request packet.
1078 */
1079#ifdef VBOX_USB3PORT
1080static NTSTATUS vboxUsbMonPnPHook(IN PVBOXUSBHOOK_ENTRY pHook, IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
1081#else /* !VBOX_USB3PORT */
1082NTSTATUS _stdcall VBoxUsbMonPnPHook(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
1083#endif /* !VBOX_USB3PORT */
1084{
1085#ifndef VBOX_USB3PORT
1086 PVBOXUSBHOOK_ENTRY pHook = &g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook;
1087#endif /* !VBOX_USB3PORT */
1088 LOG(("==>PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x)", vboxUsbDbgStrPnPMn(IoGetCurrentIrpStackLocation(pIrp)->MinorFunction), pDevObj, pIrp, pIrp->IoStatus.Status));
1089
1090 if(!VBoxUsbHookRetain(pHook))
1091 {
1092 WARN(("VBoxUsbHookRetain failed"));
1093 return VBoxUsbHookRequestPassDownHookSkip(pHook, pDevObj, pIrp);
1094 }
1095
1096 PVBOXUSBHUB_PNPHOOK_COMPLETION pCompletion = (PVBOXUSBHUB_PNPHOOK_COMPLETION)VBoxUsbMonMemAlloc(sizeof (*pCompletion));
1097 if (!pCompletion)
1098 {
1099 WARN(("VBoxUsbMonMemAlloc failed"));
1100 VBoxUsbHookRelease(pHook);
1101 pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1102 pIrp->IoStatus.Information = 0;
1103 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1104 return STATUS_INSUFFICIENT_RESOURCES;
1105 }
1106
1107 NTSTATUS Status = VBoxUsbHookRequestPassDownHookCompletion(pHook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
1108#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1109 if (Status != STATUS_PENDING)
1110 {
1111 LOG(("Request completed, Status(0x%x)", Status));
1112 VBoxUsbHookVerifyCompletion(pHook, &pCompletion->Rq, pIrp);
1113 }
1114 else
1115 {
1116 LOG(("Request pending"));
1117 }
1118#endif
1119 return Status;
1120}
1121
1122#ifdef VBOX_USB3PORT
1123/**
1124 * Device PnP hook stubs.
1125 *
1126 * @param pDevObj Device object.
1127 * @param pIrp Request packet.
1128 */
1129#define VBOX_PNPHOOKSTUB(n) NTSTATUS _stdcall VBoxUsbMonPnPHook##n(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) \
1130{ \
1131 return vboxUsbMonPnPHook(&g_VBoxUsbMonGlobals.pDrivers[n].UsbHubPnPHook.Hook, pDevObj, pIrp); \
1132}
1133
1134#define VBOX_PNPHOOKSTUB_INIT(n) g_VBoxUsbMonGlobals.pDrivers[n].pfnHookStub = VBoxUsbMonPnPHook##n
1135
1136VBOX_PNPHOOKSTUB(0)
1137VBOX_PNPHOOKSTUB(1)
1138VBOX_PNPHOOKSTUB(2)
1139VBOX_PNPHOOKSTUB(3)
1140VBOX_PNPHOOKSTUB(4)
1141AssertCompile(VBOXUSBMON_MAXDRIVERS == 5);
1142
1143typedef struct VBOXUSBMONHOOKDRIVERWALKER
1144{
1145 PDRIVER_OBJECT pDrvObj;
1146} VBOXUSBMONHOOKDRIVERWALKER, *PVBOXUSBMONHOOKDRIVERWALKER;
1147
1148/**
1149 * Logs an error to the system event log.
1150 *
1151 * @param ErrCode Error to report to event log.
1152 * @param ReturnedStatus Error that was reported by the driver to the caller.
1153 * @param uErrId Unique error id representing the location in the driver.
1154 * @param cbDumpData Number of bytes at pDumpData.
1155 * @param pDumpData Pointer to data that will be added to the message (see 'details' tab).
1156 */
1157static void vboxUsbMonLogError(NTSTATUS ErrCode, NTSTATUS ReturnedStatus, ULONG uErrId, USHORT cbDumpData, PVOID pDumpData)
1158{
1159 PIO_ERROR_LOG_PACKET pErrEntry;
1160
1161
1162 /* Truncate dumps that do not fit into IO_ERROR_LOG_PACKET. */
1163 if (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData > ERROR_LOG_MAXIMUM_SIZE)
1164 cbDumpData = ERROR_LOG_MAXIMUM_SIZE - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData);
1165
1166 pErrEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(g_VBoxUsbMonGlobals.pDevObj,
1167 FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData);
1168 if (pErrEntry)
1169 {
1170 uint8_t *pDump = (uint8_t *)pErrEntry->DumpData;
1171 if (cbDumpData)
1172 memcpy(pDump, pDumpData, cbDumpData);
1173 pErrEntry->MajorFunctionCode = 0;
1174 pErrEntry->RetryCount = 0;
1175 pErrEntry->DumpDataSize = cbDumpData;
1176 pErrEntry->NumberOfStrings = 0;
1177 pErrEntry->StringOffset = 0;
1178 pErrEntry->ErrorCode = ErrCode;
1179 pErrEntry->UniqueErrorValue = uErrId;
1180 pErrEntry->FinalStatus = ReturnedStatus;
1181 pErrEntry->IoControlCode = 0;
1182 IoWriteErrorLogEntry(pErrEntry);
1183 }
1184 else
1185 {
1186 LOG(("Failed to allocate error log entry (cb=%d)\n", FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData));
1187 }
1188}
1189
1190static DECLCALLBACK(BOOLEAN) vboxUsbMonHookDrvObjWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
1191{
1192 PDRIVER_OBJECT pDrvObj = pHubDo->DriverObject;
1193
1194 /* First we try to figure out if we are already hooked to this driver. */
1195 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
1196 if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1197 {
1198 LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
1199 /* We've already hooked to this one -- nothing to do. */
1200 return TRUE;
1201 }
1202 /* We are not hooked yet, find an empty slot. */
1203 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
1204 {
1205 if (!g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1206 {
1207 /* Found an emtpy slot, use it. */
1208 g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = pDrvObj;
1209 ObReferenceObject(pDrvObj);
1210 LOG(("pDrivers[%d] = %p, installing the hook...\n", i, pDrvObj));
1211 VBoxUsbHookInit(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook,
1212 pDrvObj,
1213 IRP_MJ_PNP,
1214 g_VBoxUsbMonGlobals.pDrivers[i].pfnHookStub);
1215 VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
1216 return TRUE; /* Must continue to find all drivers. */
1217 }
1218 if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1219 {
1220 LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
1221 /* We've already hooked to this one -- nothing to do. */
1222 return TRUE;
1223 }
1224 }
1225 /* No empty slots! No reason to continue. */
1226 LOG(("No empty slots!\n"));
1227 ANSI_STRING ansiDrvName;
1228 NTSTATUS Status = RtlUnicodeStringToAnsiString(&ansiDrvName, &pDrvObj->DriverName, true);
1229 if (Status != STATUS_SUCCESS)
1230 {
1231 ansiDrvName.Length = 0;
1232 LOG(("RtlUnicodeStringToAnsiString failed with 0x%x", Status));
1233 }
1234 vboxUsbMonLogError(IO_ERR_INSUFFICIENT_RESOURCES, STATUS_SUCCESS, 1, ansiDrvName.Length, ansiDrvName.Buffer);
1235 if (Status == STATUS_SUCCESS)
1236 RtlFreeAnsiString(&ansiDrvName);
1237 return FALSE;
1238}
1239
1240/**
1241 * Finds all USB drivers in the system and installs hooks if haven't done already.
1242 */
1243static NTSTATUS vboxUsbMonInstallAllHooks()
1244{
1245 vboxUsbMonHubDevWalk(vboxUsbMonHookDrvObjWalker, NULL, VBOXUSBMONHUBWALK_F_ALL);
1246 return STATUS_SUCCESS;
1247}
1248#endif /* VBOX_USB3PORT */
1249
1250static NTSTATUS vboxUsbMonHookCheckInit()
1251{
1252 static bool fIsHookInited = false;
1253 if (fIsHookInited)
1254 {
1255 LOG(("hook inited already, success"));
1256 return STATUS_SUCCESS;
1257 }
1258#ifdef VBOX_USB3PORT
1259 return vboxUsbMonInstallAllHooks();
1260#else /* !VBOX_USB3PORT */
1261 PDRIVER_OBJECT pDrvObj = vboxUsbMonHookFindHubDrvObj();
1262 if (pDrvObj)
1263 {
1264 VBoxUsbHookInit(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDrvObj, IRP_MJ_PNP, VBoxUsbMonPnPHook);
1265 fIsHookInited = true;
1266 LOG(("SUCCESS"));
1267 return STATUS_SUCCESS;
1268 }
1269 WARN(("hub drv obj not found, fail"));
1270 return STATUS_UNSUCCESSFUL;
1271#endif /* !VBOX_USB3PORT */
1272}
1273
1274static NTSTATUS vboxUsbMonHookInstall()
1275{
1276#ifdef VBOX_USB3PORT
1277 /* Nothing to do here as we have already installed all hooks in vboxUsbMonHookCheckInit(). */
1278 return STATUS_SUCCESS;
1279#else /* !VBOX_USB3PORT */
1280#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
1281 return STATUS_SUCCESS;
1282#else
1283 if (g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed)
1284 {
1285 WARN(("trying to hook usbhub pnp after the unhook failed, do nothing & pretend success"));
1286 return STATUS_SUCCESS;
1287 }
1288 return VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
1289#endif
1290#endif /* !VBOX_USB3PORT */
1291}
1292
1293static NTSTATUS vboxUsbMonHookUninstall()
1294{
1295#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
1296 return STATUS_SUCCESS;
1297#else
1298#ifdef VBOX_USB3PORT
1299 NTSTATUS Status = STATUS_SUCCESS;
1300 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
1301 {
1302 if (g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1303 {
1304 Assert(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject == g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook.pDrvObj);
1305 LOG(("Unhooking from %p...\n", g_VBoxUsbMonGlobals.pDrivers[i].DriverObject));
1306 Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
1307 if (!NT_SUCCESS(Status))
1308 {
1309 /*
1310 * We failed to uninstall the hook, so we keep the reference to the driver
1311 * in order to prevent another driver re-using this slot because we are
1312 * going to mark this hook as fUninitFailed.
1313 */
1314 //AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
1315 LOG(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed));
1316 g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed = true;
1317 }
1318 else
1319 {
1320 /* The hook was removed successfully, now we can forget about this driver. */
1321 ObDereferenceObject(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject);
1322 g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = NULL;
1323 }
1324 }
1325 }
1326#else /* !VBOX_USB3PORT */
1327 NTSTATUS Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
1328 if (!NT_SUCCESS(Status))
1329 {
1330 AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
1331 g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed = true;
1332 }
1333#endif /* !VBOX_USB3PORT */
1334 return Status;
1335#endif
1336}
1337
1338
1339static NTSTATUS vboxUsbMonCheckTermStuff()
1340{
1341 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
1342 Executive, KernelMode,
1343 FALSE, /* BOOLEAN Alertable */
1344 NULL /* IN PLARGE_INTEGER Timeout */
1345 );
1346 AssertRelease(Status == STATUS_SUCCESS);
1347
1348 do
1349 {
1350 if (--g_VBoxUsbMonGlobals.cOpens)
1351 break;
1352
1353 Status = vboxUsbMonHookUninstall();
1354
1355 NTSTATUS tmpStatus = VBoxUsbFltTerm();
1356 if (!NT_SUCCESS(tmpStatus))
1357 {
1358 /* this means a driver state is screwed up, KeBugCheckEx here ? */
1359 AssertReleaseFailed();
1360 }
1361 } while (0);
1362
1363 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
1364
1365 return Status;
1366}
1367
1368static NTSTATUS vboxUsbMonCheckInitStuff()
1369{
1370 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
1371 Executive, KernelMode,
1372 FALSE, /* BOOLEAN Alertable */
1373 NULL /* IN PLARGE_INTEGER Timeout */
1374 );
1375 if (Status == STATUS_SUCCESS)
1376 {
1377 do
1378 {
1379 if (g_VBoxUsbMonGlobals.cOpens++)
1380 {
1381 LOG(("opens: %d, success", g_VBoxUsbMonGlobals.cOpens));
1382 break;
1383 }
1384
1385 Status = VBoxUsbFltInit();
1386 if (NT_SUCCESS(Status))
1387 {
1388 Status = vboxUsbMonHookCheckInit();
1389 if (NT_SUCCESS(Status))
1390 {
1391 Status = vboxUsbMonHookInstall();
1392 if (NT_SUCCESS(Status))
1393 {
1394 Status = STATUS_SUCCESS;
1395 LOG(("succeded!!"));
1396 break;
1397 }
1398 else
1399 {
1400 WARN(("vboxUsbMonHookInstall failed, Status (0x%x)", Status));
1401 }
1402 }
1403 else
1404 {
1405 WARN(("vboxUsbMonHookCheckInit failed, Status (0x%x)", Status));
1406 }
1407 VBoxUsbFltTerm();
1408 }
1409 else
1410 {
1411 WARN(("VBoxUsbFltInit failed, Status (0x%x)", Status));
1412 }
1413
1414 --g_VBoxUsbMonGlobals.cOpens;
1415 Assert(!g_VBoxUsbMonGlobals.cOpens);
1416 } while (0);
1417
1418 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
1419 }
1420 else
1421 {
1422 WARN(("KeWaitForSingleObject failed, Status (0x%x)", Status));
1423 }
1424 return Status;
1425}
1426
1427static NTSTATUS vboxUsbMonContextCreate(PVBOXUSBMONCTX *ppCtx)
1428{
1429 NTSTATUS Status;
1430 *ppCtx = NULL;
1431 PVBOXUSBMONCTX pFileCtx = (PVBOXUSBMONCTX)VBoxUsbMonMemAllocZ(sizeof (*pFileCtx));
1432 if (pFileCtx)
1433 {
1434 Status = vboxUsbMonCheckInitStuff();
1435 if (Status == STATUS_SUCCESS)
1436 {
1437 Status = VBoxUsbFltCreate(&pFileCtx->FltCtx);
1438 if (Status == STATUS_SUCCESS)
1439 {
1440 *ppCtx = pFileCtx;
1441 LOG(("succeeded!!"));
1442 return STATUS_SUCCESS;
1443 }
1444 else
1445 {
1446 WARN(("VBoxUsbFltCreate failed"));
1447 }
1448 vboxUsbMonCheckTermStuff();
1449 }
1450 else
1451 {
1452 WARN(("vboxUsbMonCheckInitStuff failed"));
1453 }
1454 VBoxUsbMonMemFree(pFileCtx);
1455 }
1456 else
1457 {
1458 WARN(("VBoxUsbMonMemAllocZ failed"));
1459 Status = STATUS_NO_MEMORY;
1460 }
1461
1462 return Status;
1463}
1464
1465static NTSTATUS vboxUsbMonContextClose(PVBOXUSBMONCTX pCtx)
1466{
1467 NTSTATUS Status = VBoxUsbFltClose(&pCtx->FltCtx);
1468 if (Status == STATUS_SUCCESS)
1469 {
1470 Status = vboxUsbMonCheckTermStuff();
1471 Assert(Status == STATUS_SUCCESS);
1472 /* ignore the failure */
1473 VBoxUsbMonMemFree(pCtx);
1474 }
1475
1476 return Status;
1477}
1478
1479static NTSTATUS _stdcall VBoxUsbMonClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1480{
1481 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1482 PFILE_OBJECT pFileObj = pStack->FileObject;
1483 Assert(pFileObj->FsContext);
1484 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1485
1486 LOG(("VBoxUsbMonClose"));
1487
1488 NTSTATUS Status = vboxUsbMonContextClose(pCtx);
1489 if (Status != STATUS_SUCCESS)
1490 {
1491 WARN(("vboxUsbMonContextClose failed, Status (0x%x), prefent unload", Status));
1492 if (!InterlockedExchange(&g_VBoxUsbMonGlobals.ulPreventUnloadOn, 1))
1493 {
1494 LOGREL(("ulPreventUnloadOn not set, preventing unload"));
1495 UNICODE_STRING UniName;
1496 PDEVICE_OBJECT pTmpDevObj;
1497 RtlInitUnicodeString(&UniName, USBMON_DEVICE_NAME_NT);
1498 NTSTATUS tmpStatus = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_VBoxUsbMonGlobals.pPreventUnloadFileObj, &pTmpDevObj);
1499 AssertRelease(NT_SUCCESS(tmpStatus));
1500 AssertRelease(pTmpDevObj == pDevObj);
1501 }
1502 else
1503 {
1504 WARN(("ulPreventUnloadOn already set"));
1505 }
1506 LOG(("success!!"));
1507 Status = STATUS_SUCCESS;
1508 }
1509 pFileObj->FsContext = NULL;
1510 pIrp->IoStatus.Status = Status;
1511 pIrp->IoStatus.Information = 0;
1512 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1513 return Status;
1514}
1515
1516
1517static NTSTATUS _stdcall VBoxUsbMonCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1518{
1519 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1520 PFILE_OBJECT pFileObj = pStack->FileObject;
1521 NTSTATUS Status;
1522
1523 LOG(("VBoxUSBMonCreate"));
1524
1525 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1526 {
1527 WARN(("trying to open as a directory"));
1528 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
1529 pIrp->IoStatus.Information = 0;
1530 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1531 return STATUS_NOT_A_DIRECTORY;
1532 }
1533
1534 pFileObj->FsContext = NULL;
1535 PVBOXUSBMONCTX pCtx = NULL;
1536 Status = vboxUsbMonContextCreate(&pCtx);
1537 if (Status == STATUS_SUCCESS)
1538 {
1539 Assert(pCtx);
1540 pFileObj->FsContext = pCtx;
1541 }
1542 else
1543 {
1544 WARN(("vboxUsbMonContextCreate failed Status (0x%x)", Status));
1545 }
1546
1547 pIrp->IoStatus.Status = Status;
1548 pIrp->IoStatus.Information = 0;
1549 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1550 return Status;
1551}
1552
1553static int VBoxUsbMonSetNotifyEvent(PVBOXUSBMONCTX pContext, HANDLE hEvent)
1554{
1555 int rc = VBoxUsbFltSetNotifyEvent(&pContext->FltCtx, hEvent);
1556 return rc;
1557}
1558
1559static int VBoxUsbMonFltAdd(PVBOXUSBMONCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
1560{
1561#ifdef VBOXUSBMON_DBG_NO_FILTERS
1562 static uintptr_t idDummy = 1;
1563 *pId = idDummy;
1564 ++idDummy;
1565 return VINF_SUCCESS;
1566#else
1567 int rc = VBoxUsbFltAdd(&pContext->FltCtx, pFilter, pId);
1568 return rc;
1569#endif
1570}
1571
1572static int VBoxUsbMonFltRemove(PVBOXUSBMONCTX pContext, uintptr_t uId)
1573{
1574#ifdef VBOXUSBMON_DBG_NO_FILTERS
1575 return VINF_SUCCESS;
1576#else
1577 int rc = VBoxUsbFltRemove(&pContext->FltCtx, uId);
1578 return rc;
1579#endif
1580}
1581
1582static NTSTATUS VBoxUsbMonRunFilters(PVBOXUSBMONCTX pContext)
1583{
1584 NTSTATUS Status = VBoxUsbFltFilterCheck(&pContext->FltCtx);
1585 return Status;
1586}
1587
1588static NTSTATUS VBoxUsbMonGetDevice(PVBOXUSBMONCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
1589{
1590 NTSTATUS Status = VBoxUsbFltGetDevice(&pContext->FltCtx, hDevice, pInfo);
1591 return Status;
1592}
1593
1594static NTSTATUS vboxUsbMonIoctlDispatch(PVBOXUSBMONCTX pContext, ULONG Ctl, PVOID pvBuffer, ULONG cbInBuffer, ULONG cbOutBuffer, ULONG_PTR* pInfo)
1595{
1596 NTSTATUS Status = STATUS_SUCCESS;
1597 ULONG_PTR Info = 0;
1598 switch (Ctl)
1599 {
1600 case SUPUSBFLT_IOCTL_GET_VERSION:
1601 {
1602 PUSBSUP_VERSION pOut = (PUSBSUP_VERSION)pvBuffer;
1603
1604 LOG(("SUPUSBFLT_IOCTL_GET_VERSION"));
1605 if (!pvBuffer || cbOutBuffer != sizeof(*pOut) || cbInBuffer != 0)
1606 {
1607 WARN(("SUPUSBFLT_IOCTL_GET_VERSION: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1608 cbInBuffer, 0, cbOutBuffer, sizeof (*pOut)));
1609 Status = STATUS_INVALID_PARAMETER;
1610 break;
1611 }
1612 pOut->u32Major = USBMON_MAJOR_VERSION;
1613 pOut->u32Minor = USBMON_MINOR_VERSION;
1614 Info = sizeof (*pOut);
1615 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1616 break;
1617 }
1618
1619 case SUPUSBFLT_IOCTL_ADD_FILTER:
1620 {
1621 PUSBFILTER pFilter = (PUSBFILTER)pvBuffer;
1622 PUSBSUP_FLTADDOUT pOut = (PUSBSUP_FLTADDOUT)pvBuffer;
1623 uintptr_t uId = 0;
1624 int rc;
1625 if (RT_UNLIKELY(!pvBuffer || cbInBuffer != sizeof (*pFilter) || cbOutBuffer != sizeof (*pOut)))
1626 {
1627 WARN(("SUPUSBFLT_IOCTL_ADD_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1628 cbInBuffer, sizeof (*pFilter), cbOutBuffer, sizeof (*pOut)));
1629 Status = STATUS_INVALID_PARAMETER;
1630 break;
1631 }
1632
1633 rc = VBoxUsbMonFltAdd(pContext, pFilter, &uId);
1634 pOut->rc = rc;
1635 pOut->uId = uId;
1636 Info = sizeof (*pOut);
1637 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1638 break;
1639 }
1640
1641 case SUPUSBFLT_IOCTL_REMOVE_FILTER:
1642 {
1643 uintptr_t *pIn = (uintptr_t *)pvBuffer;
1644 int *pRc = (int *)pvBuffer;
1645
1646 if (!pvBuffer || cbInBuffer != sizeof (*pIn) || (cbOutBuffer && cbOutBuffer != sizeof (*pRc)))
1647 {
1648 WARN(("SUPUSBFLT_IOCTL_REMOVE_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1649 cbInBuffer, sizeof (*pIn), cbOutBuffer, 0));
1650 Status = STATUS_INVALID_PARAMETER;
1651 break;
1652 }
1653 LOG(("SUPUSBFLT_IOCTL_REMOVE_FILTER %x", *pIn));
1654 int rc = VBoxUsbMonFltRemove(pContext, *pIn);
1655 if (cbOutBuffer)
1656 {
1657 /* we've validated that already */
1658 Assert(cbOutBuffer == *pRc);
1659 *pRc = rc;
1660 Info = sizeof (*pRc);
1661 }
1662 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1663 break;
1664 }
1665
1666 case SUPUSBFLT_IOCTL_RUN_FILTERS:
1667 {
1668 if (pvBuffer || cbInBuffer || cbOutBuffer)
1669 {
1670 WARN(("SUPUSBFLT_IOCTL_RUN_FILTERS: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1671 cbInBuffer, 0, cbOutBuffer, 0));
1672 Status = STATUS_INVALID_PARAMETER;
1673 break;
1674 }
1675 LOG(("SUPUSBFLT_IOCTL_RUN_FILTERS "));
1676 Status = VBoxUsbMonRunFilters(pContext);
1677 ASSERT_WARN(Status != STATUS_PENDING, ("status pending!"));
1678 break;
1679 }
1680
1681 case SUPUSBFLT_IOCTL_GET_DEVICE:
1682 {
1683 HVBOXUSBDEVUSR hDevice = *((HVBOXUSBDEVUSR*)pvBuffer);
1684 PUSBSUP_GETDEV_MON pOut = (PUSBSUP_GETDEV_MON)pvBuffer;
1685 if (!pvBuffer || cbInBuffer != sizeof (hDevice) || cbOutBuffer < sizeof (*pOut))
1686 {
1687 WARN(("SUPUSBFLT_IOCTL_GET_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected >= %d.",
1688 cbInBuffer, sizeof (hDevice), cbOutBuffer, sizeof (*pOut)));
1689 Status = STATUS_INVALID_PARAMETER;
1690 break;
1691 }
1692
1693 Status = VBoxUsbMonGetDevice(pContext, hDevice, pOut);
1694
1695 if (NT_SUCCESS(Status))
1696 {
1697 Info = sizeof (*pOut);
1698 }
1699 else
1700 {
1701 WARN(("VBoxUsbMonGetDevice fail 0x%x", Status));
1702 }
1703 break;
1704 }
1705
1706 case SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT:
1707 {
1708 PUSBSUP_SET_NOTIFY_EVENT pSne = (PUSBSUP_SET_NOTIFY_EVENT)pvBuffer;
1709 if (!pvBuffer || cbInBuffer != sizeof (*pSne) || cbOutBuffer != sizeof (*pSne))
1710 {
1711 WARN(("SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1712 cbInBuffer, sizeof (*pSne), cbOutBuffer, sizeof (*pSne)));
1713 Status = STATUS_INVALID_PARAMETER;
1714 break;
1715 }
1716
1717 pSne->u.rc = VBoxUsbMonSetNotifyEvent(pContext, pSne->u.hEvent);
1718 Info = sizeof (*pSne);
1719 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1720 break;
1721 }
1722
1723 default:
1724 WARN(("Unknown code 0x%x", Ctl));
1725 Status = STATUS_INVALID_PARAMETER;
1726 break;
1727 }
1728
1729 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending!"));
1730
1731 *pInfo = Info;
1732 return Status;
1733}
1734
1735static NTSTATUS _stdcall VBoxUsbMonDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1736{
1737 ULONG_PTR Info = 0;
1738 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1739 if (NT_SUCCESS(Status))
1740 {
1741 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1742 PFILE_OBJECT pFileObj = pSl->FileObject;
1743 Assert(pFileObj);
1744 Assert(pFileObj->FsContext);
1745 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1746 Assert(pCtx);
1747 Status = vboxUsbMonIoctlDispatch(pCtx,
1748 pSl->Parameters.DeviceIoControl.IoControlCode,
1749 pIrp->AssociatedIrp.SystemBuffer,
1750 pSl->Parameters.DeviceIoControl.InputBufferLength,
1751 pSl->Parameters.DeviceIoControl.OutputBufferLength,
1752 &Info);
1753 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending"));
1754
1755 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1756 }
1757 else
1758 {
1759 WARN(("IoAcquireRemoveLock failed Status (0x%x)", Status));
1760 }
1761
1762 pIrp->IoStatus.Information = Info;
1763 pIrp->IoStatus.Status = Status;
1764 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1765 return Status;
1766}
1767
1768static NTSTATUS vboxUsbMonInternalIoctlDispatch(ULONG Ctl, PVOID pvBuffer, ULONG_PTR *pInfo)
1769{
1770 NTSTATUS Status = STATUS_SUCCESS;
1771 *pInfo = 0;
1772 switch (Ctl)
1773 {
1774 case VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION:
1775 {
1776 PVBOXUSBIDC_VERSION pOut = (PVBOXUSBIDC_VERSION)pvBuffer;
1777
1778 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION"));
1779 if (!pvBuffer)
1780 {
1781 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION: Buffer is NULL"));
1782 Status = STATUS_INVALID_PARAMETER;
1783 break;
1784 }
1785 pOut->u32Major = VBOXUSBIDC_VERSION_MAJOR;
1786 pOut->u32Minor = VBOXUSBIDC_VERSION_MINOR;
1787 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1788 break;
1789 }
1790
1791 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP:
1792 {
1793 PVBOXUSBIDC_PROXY_STARTUP pOut = (PVBOXUSBIDC_PROXY_STARTUP)pvBuffer;
1794
1795 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP"));
1796 if (!pvBuffer)
1797 {
1798 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP: Buffer is NULL"));
1799 Status = STATUS_INVALID_PARAMETER;
1800 break;
1801 }
1802
1803 pOut->u.hDev = VBoxUsbFltProxyStarted(pOut->u.pPDO);
1804 ASSERT_WARN(pOut->u.hDev, ("zero hDev"));
1805 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1806 break;
1807 }
1808
1809 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN:
1810 {
1811 PVBOXUSBIDC_PROXY_TEARDOWN pOut = (PVBOXUSBIDC_PROXY_TEARDOWN)pvBuffer;
1812
1813 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN"));
1814 if (!pvBuffer)
1815 {
1816 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN: Buffer is NULL"));
1817 Status = STATUS_INVALID_PARAMETER;
1818 break;
1819 }
1820
1821 ASSERT_WARN(pOut->hDev, ("zero hDev"));
1822 VBoxUsbFltProxyStopped(pOut->hDev);
1823 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1824 break;
1825 }
1826
1827 default:
1828 {
1829 WARN(("Unknown code 0x%x", Ctl));
1830 Status = STATUS_INVALID_PARAMETER;
1831 break;
1832 }
1833 }
1834
1835 return Status;
1836}
1837
1838static NTSTATUS _stdcall VBoxUsbMonInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1839{
1840 ULONG_PTR Info = 0;
1841 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1842 if (NT_SUCCESS(Status))
1843 {
1844 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1845 Status = vboxUsbMonInternalIoctlDispatch(pSl->Parameters.DeviceIoControl.IoControlCode,
1846 pSl->Parameters.Others.Argument1,
1847 &Info);
1848 Assert(Status != STATUS_PENDING);
1849
1850 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1851 }
1852
1853 pIrp->IoStatus.Information = Info;
1854 pIrp->IoStatus.Status = Status;
1855 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1856 return Status;
1857}
1858
1859/**
1860 * Unload the driver.
1861 *
1862 * @param pDrvObj Driver object.
1863 */
1864static void _stdcall VBoxUsbMonUnload(PDRIVER_OBJECT pDrvObj)
1865{
1866 LOG(("VBoxUSBMonUnload pDrvObj (0x%p)", pDrvObj));
1867
1868 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1869
1870 Assert(!g_VBoxUsbMonGlobals.cOpens);
1871
1872 UNICODE_STRING DosName;
1873 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1874 NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
1875
1876 IoDeleteDevice(g_VBoxUsbMonGlobals.pDevObj);
1877
1878 /* cleanup the logger */
1879 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
1880 if (pLogger)
1881 {
1882 RTLogDestroy(pLogger);
1883 }
1884 pLogger = RTLogSetDefaultInstance(NULL);
1885 if (pLogger)
1886 {
1887 RTLogDestroy(pLogger);
1888 }
1889}
1890
1891RT_C_DECLS_BEGIN
1892NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
1893RT_C_DECLS_END
1894
1895/**
1896 * Driver entry point.
1897 *
1898 * @returns appropriate status code.
1899 * @param pDrvObj Pointer to driver object.
1900 * @param pRegPath Registry base path.
1901 */
1902NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1903{
1904#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1905 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
1906 RTLogDestinations(0, "debugger");
1907#endif
1908
1909 LOGREL(("Built %s %s", __DATE__, __TIME__));
1910
1911 memset (&g_VBoxUsbMonGlobals, 0, sizeof (g_VBoxUsbMonGlobals));
1912#ifdef VBOX_USB3PORT
1913 VBOX_PNPHOOKSTUB_INIT(0);
1914 VBOX_PNPHOOKSTUB_INIT(1);
1915 VBOX_PNPHOOKSTUB_INIT(2);
1916 VBOX_PNPHOOKSTUB_INIT(3);
1917 VBOX_PNPHOOKSTUB_INIT(4);
1918 AssertCompile(VBOXUSBMON_MAXDRIVERS == 5);
1919#endif /* VBOX_USB3PORT */
1920 KeInitializeEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, SynchronizationEvent, TRUE /* signaled */);
1921 IoInitializeRemoveLock(&g_VBoxUsbMonGlobals.RmLock, VBOXUSBMON_MEMTAG, 1, 100);
1922 UNICODE_STRING DevName;
1923 PDEVICE_OBJECT pDevObj;
1924 /* create the device */
1925 RtlInitUnicodeString(&DevName, USBMON_DEVICE_NAME_NT);
1926 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1927 if (NT_SUCCESS(Status))
1928 {
1929 Status = IoCreateDevice(pDrvObj, sizeof (VBOXUSBMONINS), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
1930 if (NT_SUCCESS(Status))
1931 {
1932 UNICODE_STRING DosName;
1933 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1934 Status = IoCreateSymbolicLink(&DosName, &DevName);
1935 if (NT_SUCCESS(Status))
1936 {
1937 PVBOXUSBMONINS pDevExt = (PVBOXUSBMONINS)pDevObj->DeviceExtension;
1938 memset(pDevExt, 0, sizeof(*pDevExt));
1939
1940 pDrvObj->DriverUnload = VBoxUsbMonUnload;
1941 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxUsbMonCreate;
1942 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxUsbMonClose;
1943 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxUsbMonDeviceControl;
1944 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxUsbMonInternalDeviceControl;
1945
1946 g_VBoxUsbMonGlobals.pDevObj = pDevObj;
1947 LOG(("VBoxUSBMon::DriverEntry returning STATUS_SUCCESS"));
1948 return STATUS_SUCCESS;
1949 }
1950 IoDeleteDevice(pDevObj);
1951 }
1952 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1953 }
1954
1955 return Status;
1956}
Note: See TracBrowser for help on using the repository browser.

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