VirtualBox

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

Last change on this file since 77577 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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