VirtualBox

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

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

HostDrivers: warnings

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