VirtualBox

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

Last change on this file since 53781 was 48062, checked in by vboxsync, 11 years ago

HostDrivers/VBoxUsbMon: Hook to multiple USB drivers on Windows (USB3 port support, #6509)

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