VirtualBox

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

Last change on this file since 69250 was 69250, checked in by vboxsync, 7 years ago

HostDrivers: scm updates

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