VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbFlt.cpp@ 80978

Last change on this file since 80978 was 80978, checked in by vboxsync, 5 years ago

USB/win: Make USB device class/subclass/protocol matching optional since VBoxUSBMon may not be able to read them and reconstruct the values (see bugref:9479).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.1 KB
Line 
1/* $Id: VBoxUsbFlt.cpp 80978 2019-09-24 14:24:18Z vboxsync $ */
2/** @file
3 * VBox USB Monitor Device Filtering functionality
4 */
5/*
6 * Copyright (C) 2011-2019 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 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26
27/*********************************************************************************************************************************
28* Header Files *
29*********************************************************************************************************************************/
30#include "VBoxUsbMon.h"
31#include "../cmn/VBoxUsbTool.h"
32
33#include <VBox/cdefs.h>
34#include <VBox/types.h>
35#include <iprt/process.h>
36#include <iprt/assert.h>
37#include <iprt/errcore.h>
38
39#include <iprt/assert.h>
40
41#pragma warning(disable : 4200)
42#include "usbdi.h"
43#pragma warning(default : 4200)
44#include "usbdlib.h"
45#include "VBoxUSBFilterMgr.h"
46#include <VBox/usblib.h>
47#include <devguid.h>
48
49
50/*
51 * state transitions:
52 *
53 * (we are not filtering this device )
54 * ADDED --> UNCAPTURED ------------------------------->-
55 * | |
56 * | (we are filtering this device, | (the device is being
57 * | waiting for our device driver | re-plugged to perform
58 * | to pick it up) | capture-uncapture transition)
59 * |-> CAPTURING -------------------------------->|---> REPLUGGING -----
60 * ^ | (device driver picked | |
61 * | | up the device) | (remove cased | (device is removed
62 * | ->---> CAPTURED ---------------------->| by "real" removal | the device info is removed form the list)
63 * | | |------------------->->--> REMOVED
64 * | | |
65 * |-----------<->---> USED_BY_GUEST ------->|
66 * | |
67 * |------------------------<-
68 *
69 * NOTE: the order of enums DOES MATTER!!
70 * Do not blindly modify!! as the code assumes the state is ordered this way.
71 */
72typedef enum
73{
74 VBOXUSBFLT_DEVSTATE_UNKNOWN = 0,
75 VBOXUSBFLT_DEVSTATE_REMOVED,
76 VBOXUSBFLT_DEVSTATE_REPLUGGING,
77 VBOXUSBFLT_DEVSTATE_ADDED,
78 VBOXUSBFLT_DEVSTATE_UNCAPTURED,
79 VBOXUSBFLT_DEVSTATE_CAPTURING,
80 VBOXUSBFLT_DEVSTATE_CAPTURED,
81 VBOXUSBFLT_DEVSTATE_USED_BY_GUEST,
82 VBOXUSBFLT_DEVSTATE_32BIT_HACK = 0x7fffffff
83} VBOXUSBFLT_DEVSTATE;
84
85typedef struct VBOXUSBFLT_DEVICE
86{
87 LIST_ENTRY GlobalLe;
88 /* auxiliary list to be used for gathering devices to be re-plugged
89 * only thread that puts the device to the REPLUGGING state can use this list */
90 LIST_ENTRY RepluggingLe;
91 /* Owning session. Each matched device has an owning session. */
92 struct VBOXUSBFLTCTX *pOwner;
93 /* filter id - if NULL AND device has an owner - the filter is destroyed */
94 uintptr_t uFltId;
95 /* true iff device is filtered with a one-shot filter */
96 bool fIsFilterOneShot;
97 /* true if descriptors could not be read and only inferred from PnP Manager data */
98 bool fInferredDesc;
99 /* The device state. If the non-owner session is requesting the state while the device is grabbed,
100 * the USBDEVICESTATE_USED_BY_HOST is returned. */
101 VBOXUSBFLT_DEVSTATE enmState;
102 volatile uint32_t cRefs;
103 PDEVICE_OBJECT Pdo;
104 uint16_t idVendor;
105 uint16_t idProduct;
106 uint16_t bcdDevice;
107 uint8_t bClass;
108 uint8_t bSubClass;
109 uint8_t bProtocol;
110 char szSerial[MAX_USB_SERIAL_STRING];
111 char szMfgName[MAX_USB_SERIAL_STRING];
112 char szProduct[MAX_USB_SERIAL_STRING];
113#if 0
114 char szDrvKeyName[512];
115 BOOLEAN fHighSpeed;
116#endif
117} VBOXUSBFLT_DEVICE, *PVBOXUSBFLT_DEVICE;
118
119#define PVBOXUSBFLT_DEVICE_FROM_LE(_pLe) ( (PVBOXUSBFLT_DEVICE)( ((uint8_t*)(_pLe)) - RT_OFFSETOF(VBOXUSBFLT_DEVICE, GlobalLe) ) )
120#define PVBOXUSBFLT_DEVICE_FROM_REPLUGGINGLE(_pLe) ( (PVBOXUSBFLT_DEVICE)( ((uint8_t*)(_pLe)) - RT_OFFSETOF(VBOXUSBFLT_DEVICE, RepluggingLe) ) )
121#define PVBOXUSBFLTCTX_FROM_LE(_pLe) ( (PVBOXUSBFLTCTX)( ((uint8_t*)(_pLe)) - RT_OFFSETOF(VBOXUSBFLTCTX, ListEntry) ) )
122
123typedef struct VBOXUSBFLT_LOCK
124{
125 KSPIN_LOCK Lock;
126 KIRQL OldIrql;
127} VBOXUSBFLT_LOCK, *PVBOXUSBFLT_LOCK;
128
129#define VBOXUSBFLT_LOCK_INIT() \
130 KeInitializeSpinLock(&g_VBoxUsbFltGlobals.Lock.Lock)
131#define VBOXUSBFLT_LOCK_TERM() do { } while (0)
132#define VBOXUSBFLT_LOCK_ACQUIRE() \
133 KeAcquireSpinLock(&g_VBoxUsbFltGlobals.Lock.Lock, &g_VBoxUsbFltGlobals.Lock.OldIrql);
134#define VBOXUSBFLT_LOCK_RELEASE() \
135 KeReleaseSpinLock(&g_VBoxUsbFltGlobals.Lock.Lock, g_VBoxUsbFltGlobals.Lock.OldIrql);
136
137
138typedef struct VBOXUSBFLT_BLDEV
139{
140 LIST_ENTRY ListEntry;
141 uint16_t idVendor;
142 uint16_t idProduct;
143 uint16_t bcdDevice;
144} VBOXUSBFLT_BLDEV, *PVBOXUSBFLT_BLDEV;
145
146#define PVBOXUSBFLT_BLDEV_FROM_LE(_pLe) ( (PVBOXUSBFLT_BLDEV)( ((uint8_t*)(_pLe)) - RT_OFFSETOF(VBOXUSBFLT_BLDEV, ListEntry) ) )
147
148typedef struct VBOXUSBFLTGLOBALS
149{
150 LIST_ENTRY DeviceList;
151 LIST_ENTRY ContextList;
152 /* devices known to misbehave */
153 LIST_ENTRY BlackDeviceList;
154 VBOXUSBFLT_LOCK Lock;
155 /** Flag whether to force replugging a device we can't query descirptors from.
156 * Short term workaround for @bugref{9479}. */
157 ULONG dwForceReplugWhenDevPopulateFails;
158} VBOXUSBFLTGLOBALS, *PVBOXUSBFLTGLOBALS;
159static VBOXUSBFLTGLOBALS g_VBoxUsbFltGlobals;
160
161static bool vboxUsbFltBlDevMatchLocked(uint16_t idVendor, uint16_t idProduct, uint16_t bcdDevice)
162{
163 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.BlackDeviceList.Flink;
164 pEntry != &g_VBoxUsbFltGlobals.BlackDeviceList;
165 pEntry = pEntry->Flink)
166 {
167 PVBOXUSBFLT_BLDEV pDev = PVBOXUSBFLT_BLDEV_FROM_LE(pEntry);
168 if (pDev->idVendor != idVendor)
169 continue;
170 if (pDev->idProduct != idProduct)
171 continue;
172 if (pDev->bcdDevice != bcdDevice)
173 continue;
174
175 return true;
176 }
177 return false;
178}
179
180static NTSTATUS vboxUsbFltBlDevAddLocked(uint16_t idVendor, uint16_t idProduct, uint16_t bcdDevice)
181{
182 if (vboxUsbFltBlDevMatchLocked(idVendor, idProduct, bcdDevice))
183 return STATUS_SUCCESS;
184 PVBOXUSBFLT_BLDEV pDev = (PVBOXUSBFLT_BLDEV)VBoxUsbMonMemAllocZ(sizeof (*pDev));
185 if (!pDev)
186 {
187 AssertFailed();
188 return STATUS_INSUFFICIENT_RESOURCES;
189 }
190
191 pDev->idVendor = idVendor;
192 pDev->idProduct = idProduct;
193 pDev->bcdDevice = bcdDevice;
194 InsertHeadList(&g_VBoxUsbFltGlobals.BlackDeviceList, &pDev->ListEntry);
195 return STATUS_SUCCESS;
196}
197
198static void vboxUsbFltBlDevClearLocked()
199{
200 PLIST_ENTRY pNext;
201 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.BlackDeviceList.Flink;
202 pEntry != &g_VBoxUsbFltGlobals.BlackDeviceList;
203 pEntry = pNext)
204 {
205 pNext = pEntry->Flink;
206 VBoxUsbMonMemFree(pEntry);
207 }
208}
209
210static void vboxUsbFltBlDevPopulateWithKnownLocked()
211{
212 /* this one halts when trying to get string descriptors from it */
213 vboxUsbFltBlDevAddLocked(0x5ac, 0x921c, 0x115);
214}
215
216
217DECLINLINE(void) vboxUsbFltDevRetain(PVBOXUSBFLT_DEVICE pDevice)
218{
219 Assert(pDevice->cRefs);
220 ASMAtomicIncU32(&pDevice->cRefs);
221}
222
223static void vboxUsbFltDevDestroy(PVBOXUSBFLT_DEVICE pDevice)
224{
225 Assert(!pDevice->cRefs);
226 Assert(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REMOVED);
227 VBoxUsbMonMemFree(pDevice);
228}
229
230DECLINLINE(void) vboxUsbFltDevRelease(PVBOXUSBFLT_DEVICE pDevice)
231{
232 uint32_t cRefs = ASMAtomicDecU32(&pDevice->cRefs);
233 Assert(cRefs < UINT32_MAX/2);
234 if (!cRefs)
235 {
236 vboxUsbFltDevDestroy(pDevice);
237 }
238}
239
240static void vboxUsbFltDevOwnerSetLocked(PVBOXUSBFLT_DEVICE pDevice, PVBOXUSBFLTCTX pContext, uintptr_t uFltId, bool fIsOneShot)
241{
242 ASSERT_WARN(!pDevice->pOwner, ("device 0x%p has an owner(0x%p)", pDevice, pDevice->pOwner));
243 ++pContext->cActiveFilters;
244 pDevice->pOwner = pContext;
245 pDevice->uFltId = uFltId;
246 pDevice->fIsFilterOneShot = fIsOneShot;
247}
248
249static void vboxUsbFltDevOwnerClearLocked(PVBOXUSBFLT_DEVICE pDevice)
250{
251 ASSERT_WARN(pDevice->pOwner, ("no owner for device 0x%p", pDevice));
252 --pDevice->pOwner->cActiveFilters;
253 ASSERT_WARN(pDevice->pOwner->cActiveFilters < UINT32_MAX/2, ("cActiveFilters (%d)", pDevice->pOwner->cActiveFilters));
254 pDevice->pOwner = NULL;
255 pDevice->uFltId = 0;
256}
257
258static void vboxUsbFltDevOwnerUpdateLocked(PVBOXUSBFLT_DEVICE pDevice, PVBOXUSBFLTCTX pContext, uintptr_t uFltId, bool fIsOneShot)
259{
260 if (pDevice->pOwner != pContext)
261 {
262 if (pDevice->pOwner)
263 vboxUsbFltDevOwnerClearLocked(pDevice);
264 if (pContext)
265 vboxUsbFltDevOwnerSetLocked(pDevice, pContext, uFltId, fIsOneShot);
266 }
267 else if (pContext)
268 {
269 pDevice->uFltId = uFltId;
270 pDevice->fIsFilterOneShot = fIsOneShot;
271 }
272}
273
274static PVBOXUSBFLT_DEVICE vboxUsbFltDevGetLocked(PDEVICE_OBJECT pPdo)
275{
276#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
277 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
278 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
279 pEntry = pEntry->Flink)
280 {
281 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
282 for (PLIST_ENTRY pEntry2 = pEntry->Flink;
283 pEntry2 != &g_VBoxUsbFltGlobals.DeviceList;
284 pEntry2 = pEntry2->Flink)
285 {
286 PVBOXUSBFLT_DEVICE pDevice2 = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry2);
287 ASSERT_WARN( pDevice->idVendor != pDevice2->idVendor
288 || pDevice->idProduct != pDevice2->idProduct
289 || pDevice->bcdDevice != pDevice2->bcdDevice, ("duplicate devices in a list!!"));
290 }
291 }
292#endif
293 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
294 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
295 pEntry = pEntry->Flink)
296 {
297 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
298 ASSERT_WARN( pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING
299 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_UNCAPTURED
300 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_CAPTURING
301 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_CAPTURED
302 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_USED_BY_GUEST,
303 ("Invalid device state(%d) for device(0x%p) PDO(0x%p)", pDevice->enmState, pDevice, pDevice->Pdo));
304 if (pDevice->Pdo == pPdo)
305 return pDevice;
306 }
307 return NULL;
308}
309
310static NTSTATUS vboxUsbFltPdoReplug(PDEVICE_OBJECT pDo)
311{
312 LOG(("Replugging PDO(0x%p)", pDo));
313 NTSTATUS Status = VBoxUsbToolIoInternalCtlSendSync(pDo, IOCTL_INTERNAL_USB_CYCLE_PORT, NULL, NULL);
314 ASSERT_WARN(Status == STATUS_SUCCESS, ("replugging PDO(0x%p) failed Status(0x%x)", pDo, Status));
315 LOG(("Replugging PDO(0x%p) done with Status(0x%x)", pDo, Status));
316 return Status;
317}
318
319static bool vboxUsbFltDevCanBeCaptured(PVBOXUSBFLT_DEVICE pDevice)
320{
321 if (pDevice->bClass == USB_DEVICE_CLASS_HUB)
322 {
323 LOG(("device (0x%p), pdo (0x%p) is a hub, can not be captured", pDevice, pDevice->Pdo));
324 return false;
325 }
326 return true;
327}
328
329static PVBOXUSBFLTCTX vboxUsbFltDevMatchLocked(PVBOXUSBFLT_DEVICE pDevice, uintptr_t *puId, bool fRemoveFltIfOneShot, bool *pfFilter, bool *pfIsOneShot)
330{
331 *puId = 0;
332 *pfFilter = false;
333 *pfIsOneShot = false;
334 if (!vboxUsbFltDevCanBeCaptured(pDevice))
335 {
336 LOG(("vboxUsbFltDevCanBeCaptured returned false"));
337 return NULL;
338 }
339
340 USBFILTER DevFlt;
341 USBFilterInit(&DevFlt, USBFILTERTYPE_CAPTURE);
342 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_VENDOR_ID, pDevice->idVendor, true);
343 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_PRODUCT_ID, pDevice->idProduct, true);
344 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_REV, pDevice->bcdDevice, true);
345 USBFilterSetStringExact(&DevFlt, USBFILTERIDX_MANUFACTURER_STR, pDevice->szMfgName, true /*fMustBePresent*/, true /*fPurge*/);
346 USBFilterSetStringExact(&DevFlt, USBFILTERIDX_PRODUCT_STR, pDevice->szProduct, true /*fMustBePresent*/, true /*fPurge*/);
347 USBFilterSetStringExact(&DevFlt, USBFILTERIDX_SERIAL_NUMBER_STR, pDevice->szSerial, true /*fMustBePresent*/, true /*fPurge*/);
348
349 /* If device descriptor had to be inferred from PnP Manager data, the class/subclass/protocol may be wrong.
350 * When Windows reports CompatibleIDs 'USB\Class_03&SubClass_00&Prot_00', the device descriptor might be
351 * reporting class 3 (HID), *or* the device descriptor might be reporting class 0 (specified by interface)
352 * and the device's interface reporting class 3. Ignore the class/subclass/protocol in such case, since
353 * we are more or less guaranteed to rely on VID/PID anyway.
354 * See @bugref{9479}.
355 */
356 if (pDevice->fInferredDesc)
357 {
358 LOG(("Device descriptor was not read, only inferred; ignoring class/subclass/protocol!"));
359 }
360 else
361 {
362 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_CLASS, pDevice->bClass, true);
363 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_SUB_CLASS, pDevice->bSubClass, true);
364 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_PROTOCOL, pDevice->bProtocol, true);
365 }
366
367 /* Run filters on the thing. */
368 PVBOXUSBFLTCTX pOwner = VBoxUSBFilterMatchEx(&DevFlt, puId, fRemoveFltIfOneShot, pfFilter, pfIsOneShot);
369 USBFilterDelete(&DevFlt);
370 return pOwner;
371}
372
373static void vboxUsbFltDevStateMarkReplugLocked(PVBOXUSBFLT_DEVICE pDevice)
374{
375 vboxUsbFltDevOwnerUpdateLocked(pDevice, NULL, 0, false);
376 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REPLUGGING;
377}
378
379static bool vboxUsbFltDevStateIsNotFiltered(PVBOXUSBFLT_DEVICE pDevice)
380{
381 return pDevice->enmState == VBOXUSBFLT_DEVSTATE_UNCAPTURED;
382}
383
384static bool vboxUsbFltDevStateIsFiltered(PVBOXUSBFLT_DEVICE pDevice)
385{
386 return pDevice->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
387}
388
389static uint16_t vboxUsbParseHexNumU16(WCHAR **ppStr)
390{
391 WCHAR *pStr = *ppStr;
392 WCHAR wc;
393 uint16_t num = 0;
394 unsigned u;
395
396 for (int i = 0; i < 4; ++i)
397 {
398 if (!*pStr) /* Just in case the string is too short. */
399 break;
400
401 wc = *pStr;
402 u = wc >= 'A' ? wc - 'A' + 10 : wc - '0'; /* Hex digit to number. */
403 num |= u << (12 - 4 * i);
404 pStr++;
405 }
406 *ppStr = pStr;
407
408 return num;
409}
410
411static uint8_t vboxUsbParseHexNumU8(WCHAR **ppStr)
412{
413 WCHAR *pStr = *ppStr;
414 WCHAR wc;
415 uint16_t num = 0;
416 unsigned u;
417
418 for (int i = 0; i < 2; ++i)
419 {
420 if (!*pStr) /* Just in case the string is too short. */
421 break;
422
423 wc = *pStr;
424 u = wc >= 'A' ? wc - 'A' + 10 : wc - '0'; /* Hex digit to number. */
425 num |= u << (4 - 4 * i);
426 pStr++;
427 }
428 *ppStr = pStr;
429
430 return num;
431}
432
433static bool vboxUsbParseHardwareID(WCHAR *pchIdStr, uint16_t *pVid, uint16_t *pPid, uint16_t *pRev)
434{
435#define VID_PREFIX L"USB\\VID_"
436#define PID_PREFIX L"&PID_"
437#define REV_PREFIX L"&REV_"
438
439 *pVid = *pPid = *pRev = 0xFFFF;
440
441 /* The Hardware ID is in the format USB\VID_xxxx&PID_xxxx&REV_xxxx, with 'xxxx'
442 * being 16-bit hexadecimal numbers. The string is coming from the
443 * Windows PnP manager so OEMs should have no opportunity to mess it up.
444 */
445
446 if (wcsncmp(pchIdStr, VID_PREFIX, wcslen(VID_PREFIX)))
447 return false;
448 /* Point to the start of the vendor ID number and parse it. */
449 pchIdStr += wcslen(VID_PREFIX);
450 *pVid = vboxUsbParseHexNumU16(&pchIdStr);
451
452 if (wcsncmp(pchIdStr, PID_PREFIX, wcslen(PID_PREFIX)))
453 return false;
454 /* Point to the start of the product ID number and parse it. */
455 pchIdStr += wcslen(PID_PREFIX);
456 *pPid = vboxUsbParseHexNumU16(&pchIdStr);
457
458 /* The revision might not be there; the Windows documentation is not
459 * entirely clear if it will be always present for USB devices or not.
460 * If it's not there, still consider this a success. */
461 if (wcsncmp(pchIdStr, REV_PREFIX, wcslen(REV_PREFIX)))
462 return true;
463
464 /* Point to the start of the revision number and parse it. */
465 pchIdStr += wcslen(REV_PREFIX);
466 *pRev = vboxUsbParseHexNumU16(&pchIdStr);
467
468 return true;
469#undef VID_PREFIX
470#undef PID_PREFIX
471#undef REV_PREFIX
472}
473
474static bool vboxUsbParseCompatibleIDs(WCHAR *pchIdStr, uint8_t *pClass, uint8_t *pSubClass, uint8_t *pProt)
475{
476#define CLS_PREFIX L"USB\\Class_"
477#define SUB_PREFIX L"&SubClass_"
478#define PRO_PREFIX L"&Prot_"
479
480 *pClass = *pSubClass = *pProt = 0xFF;
481
482 /* The Compatible IDs string is in the format USB\Class_xx&SubClass_xx&Prot_xx,
483 * with 'xx' being 8-bit hexadecimal numbers. Since this string is provided by the
484 * PnP manager and USB devices always report these as part of the basic USB device
485 * descriptor, we assume all three must be present.
486 */
487
488 if (wcsncmp(pchIdStr, CLS_PREFIX, wcslen(CLS_PREFIX)))
489 return false;
490 /* Point to the start of the device class and parse it. */
491 pchIdStr += wcslen(CLS_PREFIX);
492 *pClass = vboxUsbParseHexNumU8(&pchIdStr);
493
494 if (wcsncmp(pchIdStr, SUB_PREFIX, wcslen(SUB_PREFIX)))
495 return false;
496
497 /* Point to the start of the subclass and parse it. */
498 pchIdStr += wcslen(SUB_PREFIX);
499 *pSubClass = vboxUsbParseHexNumU8(&pchIdStr);
500
501 if (wcsncmp(pchIdStr, PRO_PREFIX, wcslen(PRO_PREFIX)))
502 return false;
503
504 /* Point to the start of the protocol and parse it. */
505 pchIdStr += wcslen(PRO_PREFIX);
506 *pProt = vboxUsbParseHexNumU8(&pchIdStr);
507
508 return true;
509#undef CLS_PREFIX
510#undef SUB_PREFIX
511#undef PRO_PREFIX
512}
513
514#define VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS 10000
515
516static NTSTATUS vboxUsbFltDevPopulate(PVBOXUSBFLT_DEVICE pDevice, PDEVICE_OBJECT pDo /*, BOOLEAN bPopulateNonFilterProps*/)
517{
518 NTSTATUS Status;
519 PUSB_DEVICE_DESCRIPTOR pDevDr = 0;
520
521 pDevice->Pdo = pDo;
522
523 LOG(("Populating Device(0x%p) for PDO(0x%p)", pDevice, pDo));
524
525 pDevDr = (PUSB_DEVICE_DESCRIPTOR)VBoxUsbMonMemAllocZ(sizeof(*pDevDr));
526 if (pDevDr == NULL)
527 {
528 WARN(("Failed to alloc mem for urb"));
529 return STATUS_INSUFFICIENT_RESOURCES;
530 }
531
532 do
533 {
534 pDevice->fInferredDesc = false;
535 Status = VBoxUsbToolGetDescriptor(pDo, pDevDr, sizeof(*pDevDr), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
536 if (!NT_SUCCESS(Status))
537 {
538 WCHAR wchPropBuf[256];
539 ULONG ulResultLen;
540 bool rc;
541 uint16_t vid, pid, rev;
542 uint8_t cls, sub, prt;
543
544 WARN(("getting device descriptor failed, Status (0x%x); falling back to IoGetDeviceProperty", Status));
545
546 /* Try falling back to IoGetDeviceProperty. */
547 Status = IoGetDeviceProperty(pDo, DevicePropertyHardwareID, sizeof(wchPropBuf), wchPropBuf, &ulResultLen);
548 if (!NT_SUCCESS(Status))
549 {
550 /* This just isn't our day. We have no idea what the device is. */
551 WARN(("IoGetDeviceProperty failed for DevicePropertyHardwareID, Status (0x%x)", Status));
552 break;
553 }
554 rc = vboxUsbParseHardwareID(wchPropBuf, &vid, &pid, &rev);
555 if (!rc)
556 {
557 /* This *really* should not happen. */
558 WARN(("Failed to parse Hardware ID"));
559 break;
560 }
561
562 /* Now grab the Compatible IDs to get the class/subclass/protocol. */
563 Status = IoGetDeviceProperty(pDo, DevicePropertyCompatibleIDs, sizeof(wchPropBuf), wchPropBuf, &ulResultLen);
564 if (!NT_SUCCESS(Status))
565 {
566 /* We really kind of need these. */
567 WARN(("IoGetDeviceProperty failed for DevicePropertyCompatibleIDs, Status (0x%x)", Status));
568 break;
569 }
570 rc = vboxUsbParseCompatibleIDs(wchPropBuf, &cls, &sub, &prt);
571 if (!rc)
572 {
573 /* This *really* should not happen. */
574 WARN(("Failed to parse Hardware ID"));
575 break;
576 }
577
578 LOG(("Parsed HardwareID: vid=%04X, pid=%04X, rev=%04X, class=%02X, subcls=%02X, prot=%02X", vid, pid, rev, cls, sub, prt));
579 if (vid == 0xFFFF || pid == 0xFFFF)
580 break;
581
582 LOG(("Successfully fell back to IoGetDeviceProperty result"));
583 pDevDr->idVendor = vid;
584 pDevDr->idProduct = pid;
585 pDevDr->bcdDevice = rev;
586 pDevDr->bDeviceClass = cls;
587 pDevDr->bDeviceSubClass = sub;
588 pDevDr->bDeviceProtocol = prt;
589
590 /* The USB device class/subclass/protocol may not be accurate. We have to be careful when comparing
591 * and not take mismatches too seriously.
592 */
593 pDevice->fInferredDesc = true;
594 }
595
596 if (vboxUsbFltBlDevMatchLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice))
597 {
598 WARN(("found a known black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
599 Status = STATUS_UNSUCCESSFUL;
600 break;
601 }
602
603 LOG(("Device pid=%x vid=%x rev=%x", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
604 pDevice->idVendor = pDevDr->idVendor;
605 pDevice->idProduct = pDevDr->idProduct;
606 pDevice->bcdDevice = pDevDr->bcdDevice;
607 pDevice->bClass = pDevDr->bDeviceClass;
608 pDevice->bSubClass = pDevDr->bDeviceSubClass;
609 pDevice->bProtocol = pDevDr->bDeviceProtocol;
610 pDevice->szSerial[0] = 0;
611 pDevice->szMfgName[0] = 0;
612 pDevice->szProduct[0] = 0;
613
614 /* If there are no strings, don't even try to get any string descriptors. */
615 if (pDevDr->iSerialNumber || pDevDr->iManufacturer || pDevDr->iProduct)
616 {
617 int langId;
618
619 Status = VBoxUsbToolGetLangID(pDo, &langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
620 if (!NT_SUCCESS(Status))
621 {
622 WARN(("reading language ID failed"));
623 if (Status == STATUS_CANCELLED)
624 {
625 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
626 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
627 Status = STATUS_UNSUCCESSFUL;
628 }
629 break;
630 }
631
632 if (pDevDr->iSerialNumber)
633 {
634 Status = VBoxUsbToolGetStringDescriptor(pDo, pDevice->szSerial, sizeof (pDevice->szSerial), pDevDr->iSerialNumber, langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
635 if (!NT_SUCCESS(Status))
636 {
637 WARN(("reading serial number failed"));
638 ASSERT_WARN(pDevice->szSerial[0] == '\0', ("serial is not zero!!"));
639 if (Status == STATUS_CANCELLED)
640 {
641 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
642 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
643 Status = STATUS_UNSUCCESSFUL;
644 break;
645 }
646 LOG(("pretending success.."));
647 Status = STATUS_SUCCESS;
648 }
649 }
650
651 if (pDevDr->iManufacturer)
652 {
653 Status = VBoxUsbToolGetStringDescriptor(pDo, pDevice->szMfgName, sizeof (pDevice->szMfgName), pDevDr->iManufacturer, langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
654 if (!NT_SUCCESS(Status))
655 {
656 WARN(("reading manufacturer name failed"));
657 ASSERT_WARN(pDevice->szMfgName[0] == '\0', ("szMfgName is not zero!!"));
658 if (Status == STATUS_CANCELLED)
659 {
660 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
661 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
662 Status = STATUS_UNSUCCESSFUL;
663 break;
664 }
665 LOG(("pretending success.."));
666 Status = STATUS_SUCCESS;
667 }
668 }
669
670 if (pDevDr->iProduct)
671 {
672 Status = VBoxUsbToolGetStringDescriptor(pDo, pDevice->szProduct, sizeof (pDevice->szProduct), pDevDr->iProduct, langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
673 if (!NT_SUCCESS(Status))
674 {
675 WARN(("reading product name failed"));
676 ASSERT_WARN(pDevice->szProduct[0] == '\0', ("szProduct is not zero!!"));
677 if (Status == STATUS_CANCELLED)
678 {
679 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
680 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
681 Status = STATUS_UNSUCCESSFUL;
682 break;
683 }
684 LOG(("pretending success.."));
685 Status = STATUS_SUCCESS;
686 }
687 }
688
689 LOG((": strings: '%s':'%s':'%s' (lang ID %x)",
690 pDevice->szMfgName, pDevice->szProduct, pDevice->szSerial, langId));
691 }
692
693 LOG(("Populating Device(0x%p) for PDO(0x%p) Succeeded", pDevice, pDo));
694 Status = STATUS_SUCCESS;
695 } while (0);
696
697 VBoxUsbMonMemFree(pDevDr);
698 LOG(("Populating Device(0x%p) for PDO(0x%p) Done, Status (0x%x)", pDevice, pDo, Status));
699 return Status;
700}
701
702static bool vboxUsbFltDevCheckReplugLocked(PVBOXUSBFLT_DEVICE pDevice, PVBOXUSBFLTCTX pContext)
703{
704 ASSERT_WARN(pContext, ("context is NULL!"));
705
706 LOG(("Current context is (0x%p)", pContext));
707 LOG(("Current Device owner is (0x%p)", pDevice->pOwner));
708
709 /* check if device is already replugging */
710 if (pDevice->enmState <= VBOXUSBFLT_DEVSTATE_ADDED)
711 {
712 LOG(("Device (0x%p) is already replugging, return..", pDevice));
713 /* it is, do nothing */
714 ASSERT_WARN(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING,
715 ("Device (0x%p) state is NOT REPLUGGING (%d)", pDevice, pDevice->enmState));
716 return false;
717 }
718
719 if (pDevice->pOwner && pContext != pDevice->pOwner)
720 {
721 LOG(("Device (0x%p) is owned by another context(0x%p), current is(0x%p)", pDevice, pDevice->pOwner, pContext));
722 /* this device is owned by another context, we're not allowed to do anything */
723 return false;
724 }
725
726 uintptr_t uId = 0;
727 bool bNeedReplug = false;
728 bool fFilter = false;
729 bool fIsOneShot = false;
730 PVBOXUSBFLTCTX pNewOwner = vboxUsbFltDevMatchLocked(pDevice, &uId,
731 false, /* do not remove a one-shot filter */
732 &fFilter, &fIsOneShot);
733 LOG(("Matching Info: Filter (0x%p), NewOwner(0x%p), fFilter(%d), fIsOneShot(%d)", uId, pNewOwner, (int)fFilter, (int)fIsOneShot));
734 if (pDevice->pOwner && pNewOwner && pDevice->pOwner != pNewOwner)
735 {
736 LOG(("Matching: Device (0x%p) is requested another owner(0x%p), current is(0x%p)", pDevice, pNewOwner, pDevice->pOwner));
737 /* the device is owned by another owner, we can not change the owner here */
738 return false;
739 }
740
741 if (!fFilter)
742 {
743 LOG(("Matching: Device (0x%p) should NOT be filtered", pDevice));
744 /* the device should NOT be filtered, check the current state */
745 if (vboxUsbFltDevStateIsNotFiltered(pDevice))
746 {
747 LOG(("Device (0x%p) is NOT filtered", pDevice));
748 /* no changes */
749 if (fIsOneShot)
750 {
751 ASSERT_WARN(pNewOwner, ("no new owner"));
752 LOG(("Matching: This is a one-shot filter (0x%p), removing..", uId));
753 /* remove a one-shot filter and keep the original filter data */
754 int tmpRc = VBoxUSBFilterRemove(pNewOwner, uId);
755 ASSERT_WARN(RT_SUCCESS(tmpRc), ("remove filter failed, rc (%d)", tmpRc));
756 if (!pDevice->pOwner)
757 {
758 LOG(("Matching: updating the one-shot owner to (0x%p), fltId(0x%p)", pNewOwner, uId));
759 /* update owner for one-shot if the owner is changed (i.e. assigned) */
760 vboxUsbFltDevOwnerUpdateLocked(pDevice, pNewOwner, uId, true);
761 }
762 else
763 {
764 LOG(("Matching: device already has owner (0x%p) assigned", pDevice->pOwner));
765 }
766 }
767 else
768 {
769 LOG(("Matching: This is NOT a one-shot filter (0x%p), newOwner(0x%p)", uId, pNewOwner));
770 if (pNewOwner)
771 {
772 vboxUsbFltDevOwnerUpdateLocked(pDevice, pNewOwner, uId, false);
773 }
774 }
775 }
776 else
777 {
778 LOG(("Device (0x%p) IS filtered", pDevice));
779 /* the device is currently filtered, we should release it only if
780 * 1. device does not have an owner
781 * or
782 * 2. it should be released bue to a one-shot filter
783 * or
784 * 3. it is NOT grabbed by a one-shot filter */
785 if (!pDevice->pOwner || fIsOneShot || !pDevice->fIsFilterOneShot)
786 {
787 LOG(("Matching: Need replug"));
788 bNeedReplug = true;
789 }
790 }
791 }
792 else
793 {
794 LOG(("Matching: Device (0x%p) SHOULD be filtered", pDevice));
795 /* the device should be filtered, check the current state */
796 ASSERT_WARN(uId, ("zero uid"));
797 ASSERT_WARN(pNewOwner, ("zero pNewOwner"));
798 if (vboxUsbFltDevStateIsFiltered(pDevice))
799 {
800 LOG(("Device (0x%p) IS filtered", pDevice));
801 /* the device is filtered */
802 if (pNewOwner == pDevice->pOwner)
803 {
804 LOG(("Device owner match"));
805 /* no changes */
806 if (fIsOneShot)
807 {
808 LOG(("Matching: This is a one-shot filter (0x%p), removing..", uId));
809 /* remove a one-shot filter and keep the original filter data */
810 int tmpRc = VBoxUSBFilterRemove(pNewOwner, uId);
811 ASSERT_WARN(RT_SUCCESS(tmpRc), ("remove filter failed, rc (%d)", tmpRc));
812 }
813 else
814 {
815 LOG(("Matching: This is NOT a one-shot filter (0x%p), Owner(0x%p)", uId, pDevice->pOwner));
816 vboxUsbFltDevOwnerUpdateLocked(pDevice, pDevice->pOwner, uId, false);
817 }
818 }
819 else
820 {
821 ASSERT_WARN(!pDevice->pOwner, ("device should NOT have owner"));
822 LOG(("Matching: Need replug"));
823 /* the device needs to be filtered, but the owner changes, replug needed */
824 bNeedReplug = true;
825 }
826 }
827 else
828 {
829 /* the device is currently NOT filtered,
830 * we should replug it only if
831 * 1. device does not have an owner
832 * or
833 * 2. it should be captured due to a one-shot filter
834 * or
835 * 3. it is NOT released by a one-shot filter */
836 if (!pDevice->pOwner || fIsOneShot || !pDevice->fIsFilterOneShot)
837 {
838 bNeedReplug = true;
839 LOG(("Matching: Need replug"));
840 }
841 }
842 }
843
844 if (bNeedReplug)
845 {
846 LOG(("Matching: Device needs replugging, marking as such"));
847 vboxUsbFltDevStateMarkReplugLocked(pDevice);
848 }
849 else
850 {
851 LOG(("Matching: Device does NOT need replugging"));
852 }
853
854 return bNeedReplug;
855}
856
857static void vboxUsbFltReplugList(PLIST_ENTRY pList)
858{
859 PLIST_ENTRY pNext;
860 for (PLIST_ENTRY pEntry = pList->Flink;
861 pEntry != pList;
862 pEntry = pNext)
863 {
864 pNext = pEntry->Flink;
865 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_REPLUGGINGLE(pEntry);
866 LOG(("replugging matched PDO(0x%p), pDevice(0x%p)", pDevice->Pdo, pDevice));
867 ASSERT_WARN(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING
868 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_REMOVED,
869 ("invalid state(0x%x) for device(0x%p)", pDevice->enmState, pDevice));
870
871 vboxUsbFltPdoReplug(pDevice->Pdo);
872 ObDereferenceObject(pDevice->Pdo);
873 vboxUsbFltDevRelease(pDevice);
874 }
875}
876
877typedef struct VBOXUSBFLTCHECKWALKER
878{
879 PVBOXUSBFLTCTX pContext;
880} VBOXUSBFLTCHECKWALKER, *PVBOXUSBFLTCHECKWALKER;
881
882static DECLCALLBACK(BOOLEAN) vboxUsbFltFilterCheckWalker(PFILE_OBJECT pHubFile,
883 PDEVICE_OBJECT pHubDo, PVOID pvContext)
884{
885 PVBOXUSBFLTCHECKWALKER pData = (PVBOXUSBFLTCHECKWALKER)pvContext;
886 PVBOXUSBFLTCTX pContext = pData->pContext;
887
888 LOG(("Visiting pHubFile(0x%p), pHubDo(0x%p), oContext(0x%p)", pHubFile, pHubDo, pContext));
889 KIRQL Irql = KeGetCurrentIrql();
890 ASSERT_WARN(Irql == PASSIVE_LEVEL, ("unexpected IRQL (%d)", Irql));
891
892 PDEVICE_RELATIONS pDevRelations = NULL;
893
894 NTSTATUS Status = VBoxUsbMonQueryBusRelations(pHubDo, pHubFile, &pDevRelations);
895 if (Status == STATUS_SUCCESS && pDevRelations)
896 {
897 ULONG cReplugPdos = pDevRelations->Count;
898 LIST_ENTRY ReplugDevList;
899 InitializeListHead(&ReplugDevList);
900 for (ULONG k = 0; k < pDevRelations->Count; ++k)
901 {
902 PDEVICE_OBJECT pDevObj = pDevRelations->Objects[k];
903
904 LOG(("Found existing USB PDO 0x%p", pDevObj));
905 VBOXUSBFLT_LOCK_ACQUIRE();
906 PVBOXUSBFLT_DEVICE pDevice = vboxUsbFltDevGetLocked(pDevObj);
907 if (pDevice)
908 {
909 LOG(("Found existing device info (0x%p) for PDO 0x%p", pDevice, pDevObj));
910 bool bReplug = vboxUsbFltDevCheckReplugLocked(pDevice, pContext);
911 if (bReplug)
912 {
913 LOG(("Replug needed for device (0x%p)", pDevice));
914 InsertHeadList(&ReplugDevList, &pDevice->RepluggingLe);
915 vboxUsbFltDevRetain(pDevice);
916 /* do not dereference object since we will use it later */
917 }
918 else
919 {
920 LOG(("Replug NOT needed for device (0x%p)", pDevice));
921 ObDereferenceObject(pDevObj);
922 }
923
924 VBOXUSBFLT_LOCK_RELEASE();
925
926 pDevRelations->Objects[k] = NULL;
927 --cReplugPdos;
928 ASSERT_WARN((uint32_t)cReplugPdos < UINT32_MAX/2, ("cReplugPdos(%d) state broken", cReplugPdos));
929 continue;
930 }
931 VBOXUSBFLT_LOCK_RELEASE();
932
933 LOG(("NO device info found for PDO 0x%p", pDevObj));
934 VBOXUSBFLT_DEVICE Device;
935 Status = vboxUsbFltDevPopulate(&Device, pDevObj /*, FALSE /* only need filter properties */);
936 if (NT_SUCCESS(Status))
937 {
938 uintptr_t uId = 0;
939 bool fFilter = false;
940 bool fIsOneShot = false;
941 VBOXUSBFLT_LOCK_ACQUIRE();
942 PVBOXUSBFLTCTX pCtx = vboxUsbFltDevMatchLocked(&Device, &uId,
943 false, /* do not remove a one-shot filter */
944 &fFilter, &fIsOneShot);
945 VBOXUSBFLT_LOCK_RELEASE();
946 NOREF(pCtx);
947 LOG(("Matching Info: Filter (0x%p), pCtx(0x%p), fFilter(%d), fIsOneShot(%d)", uId, pCtx, (int)fFilter, (int)fIsOneShot));
948 if (fFilter)
949 {
950 LOG(("Matching: This device SHOULD be filtered"));
951 /* this device needs to be filtered, but it's not,
952 * leave the PDO in array to issue a replug request for it
953 * later on */
954 continue;
955 }
956 }
957 else
958 {
959 WARN(("vboxUsbFltDevPopulate for PDO 0x%p failed with Status 0x%x", pDevObj, Status));
960 if ( Status == STATUS_CANCELLED
961 && g_VBoxUsbFltGlobals.dwForceReplugWhenDevPopulateFails)
962 {
963 /*
964 * This can happen if the device got suspended and is in D3 state where we can't query any strings.
965 * There is no known way to set the power state of the device, especially if there is no driver attached yet.
966 * The sledgehammer approach is to just replug the device to force it out of suspend, see bugref @{9479}.
967 */
968 continue;
969 }
970 }
971
972 LOG(("Matching: This device should NOT be filtered"));
973 /* this device should not be filtered, and it's not */
974 ObDereferenceObject(pDevObj);
975 pDevRelations->Objects[k] = NULL;
976 --cReplugPdos;
977 ASSERT_WARN((uint32_t)cReplugPdos < UINT32_MAX/2, ("cReplugPdos is %d", cReplugPdos));
978 }
979
980 LOG(("(%d) non-matched PDOs to be replugged", cReplugPdos));
981
982 if (cReplugPdos)
983 {
984 for (ULONG k = 0; k < pDevRelations->Count; ++k)
985 {
986 if (!pDevRelations->Objects[k])
987 continue;
988
989 Status = vboxUsbFltPdoReplug(pDevRelations->Objects[k]);
990 ASSERT_WARN(Status == STATUS_SUCCESS, ("vboxUsbFltPdoReplug failed! Status(0x%x)", Status));
991 ObDereferenceObject(pDevRelations->Objects[k]);
992 if (!--cReplugPdos)
993 break;
994 }
995
996 ASSERT_WARN(!cReplugPdos, ("cReplugPdos reached zero!"));
997 }
998
999 vboxUsbFltReplugList(&ReplugDevList);
1000
1001 ExFreePool(pDevRelations);
1002 }
1003 else
1004 {
1005 WARN(("VBoxUsbMonQueryBusRelations failed for hub DO(0x%p), Status(0x%x), pDevRelations(0x%p)",
1006 pHubDo, Status, pDevRelations));
1007 }
1008
1009 LOG(("Done Visiting pHubFile(0x%p), pHubDo(0x%p), oContext(0x%p)", pHubFile, pHubDo, pContext));
1010
1011 return TRUE;
1012}
1013
1014NTSTATUS VBoxUsbFltFilterCheck(PVBOXUSBFLTCTX pContext)
1015{
1016 KIRQL Irql = KeGetCurrentIrql();
1017 ASSERT_WARN(Irql == PASSIVE_LEVEL, ("unexpected IRQL (%d)", Irql));
1018
1019 LOG(("Running filters, Context (0x%p)..", pContext));
1020
1021 VBOXUSBFLTCHECKWALKER Data;
1022 Data.pContext = pContext;
1023 vboxUsbMonHubDevWalk(vboxUsbFltFilterCheckWalker, &Data);
1024
1025 LOG(("DONE Running filters, Context (0x%p)", pContext));
1026
1027 return STATUS_SUCCESS;
1028}
1029
1030NTSTATUS VBoxUsbFltClose(PVBOXUSBFLTCTX pContext)
1031{
1032 LOG(("Closing context(0x%p)", pContext));
1033 LIST_ENTRY ReplugDevList;
1034 InitializeListHead(&ReplugDevList);
1035
1036 ASSERT_WARN(pContext, ("null context"));
1037
1038 KIRQL Irql = KeGetCurrentIrql();
1039 ASSERT_WARN(Irql == PASSIVE_LEVEL, ("irql==(%d)", Irql));
1040
1041 VBOXUSBFLT_LOCK_ACQUIRE();
1042
1043 pContext->bRemoved = TRUE;
1044 RemoveEntryList(&pContext->ListEntry);
1045
1046 LOG(("removing owner filters"));
1047 /* now re-arrange the filters */
1048 /* 1. remove filters */
1049 VBoxUSBFilterRemoveOwner(pContext);
1050
1051 LOG(("enumerating devices.."));
1052 /* 2. check if there are devices owned */
1053 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1054 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1055 pEntry = pEntry->Flink)
1056 {
1057 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1058 if (pDevice->pOwner != pContext)
1059 continue;
1060
1061 LOG(("found device(0x%p), pdo(0x%p), state(%d), filter id(0x%p), oneshot(%d)",
1062 pDevice, pDevice->Pdo, pDevice->enmState, pDevice->uFltId, (int)pDevice->fIsFilterOneShot));
1063 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED, ("VBOXUSBFLT_DEVSTATE_ADDED state for device(0x%p)", pDevice));
1064 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED, ("VBOXUSBFLT_DEVSTATE_REMOVED state for device(0x%p)", pDevice));
1065
1066 vboxUsbFltDevOwnerClearLocked(pDevice);
1067
1068 if (vboxUsbFltDevCheckReplugLocked(pDevice, pContext))
1069 {
1070 LOG(("device needs replug"));
1071 InsertHeadList(&ReplugDevList, &pDevice->RepluggingLe);
1072 /* retain to ensure the device is not removed before we issue a replug */
1073 vboxUsbFltDevRetain(pDevice);
1074 /* keep the PDO alive */
1075 ObReferenceObject(pDevice->Pdo);
1076 }
1077 else
1078 {
1079 LOG(("device does NOT need replug"));
1080 }
1081 }
1082
1083 VBOXUSBFLT_LOCK_RELEASE();
1084
1085 /* this should replug all devices that were either skipped or grabbed due to the context's */
1086 vboxUsbFltReplugList(&ReplugDevList);
1087
1088 LOG(("SUCCESS done context(0x%p)", pContext));
1089 return STATUS_SUCCESS;
1090}
1091
1092NTSTATUS VBoxUsbFltCreate(PVBOXUSBFLTCTX pContext)
1093{
1094 LOG(("Creating context(0x%p)", pContext));
1095 memset(pContext, 0, sizeof (*pContext));
1096 pContext->Process = RTProcSelf();
1097 VBOXUSBFLT_LOCK_ACQUIRE();
1098 InsertHeadList(&g_VBoxUsbFltGlobals.ContextList, &pContext->ListEntry);
1099 VBOXUSBFLT_LOCK_RELEASE();
1100 LOG(("SUCCESS context(0x%p)", pContext));
1101 return STATUS_SUCCESS;
1102}
1103
1104int VBoxUsbFltAdd(PVBOXUSBFLTCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
1105{
1106 LOG(("adding filter, Context (0x%p)..", pContext));
1107 *pId = 0;
1108 /* LOG the filter details. */
1109 LOG((__FUNCTION__": %s %s %s",
1110 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1111 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1112 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1113#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1114 LOG(("VBoxUSBClient::addFilter: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x Type%#x",
1115 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
1116 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
1117 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
1118 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
1119 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
1120 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
1121 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
1122 USBFilterGetNum(pFilter, USBFILTERIDX_PORT),
1123 USBFilterGetFilterType(pFilter)));
1124#endif
1125
1126 /* We can't get the bus/port numbers. Ignore them while matching. */
1127 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false);
1128 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_PORT, false);
1129
1130 /* We may not be able to reconstruct the class/subclass/protocol if we aren't able to
1131 * read the device descriptor. Don't require these to be present. See also the fInferredDesc flag.
1132 */
1133 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_DEVICE_CLASS, false);
1134 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS, false);
1135 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_DEVICE_PROTOCOL, false);
1136
1137 uintptr_t uId = 0;
1138 VBOXUSBFLT_LOCK_ACQUIRE();
1139 /* Add the filter. */
1140 int rc = VBoxUSBFilterAdd(pFilter, pContext, &uId);
1141 VBOXUSBFLT_LOCK_RELEASE();
1142 if (RT_SUCCESS(rc))
1143 {
1144 LOG(("ADDED filter id 0x%p", uId));
1145 ASSERT_WARN(uId, ("uid is NULL"));
1146#ifdef VBOX_USBMON_WITH_FILTER_AUTOAPPLY
1147 VBoxUsbFltFilterCheck();
1148#endif
1149 }
1150 else
1151 {
1152 WARN(("VBoxUSBFilterAdd failed rc (%d)", rc));
1153 ASSERT_WARN(!uId, ("uid is not NULL"));
1154 }
1155
1156 *pId = uId;
1157 return rc;
1158}
1159
1160int VBoxUsbFltRemove(PVBOXUSBFLTCTX pContext, uintptr_t uId)
1161{
1162 LOG(("removing filter id(0x%p), Context (0x%p)..", pContext, uId));
1163 Assert(uId);
1164
1165 VBOXUSBFLT_LOCK_ACQUIRE();
1166 int rc = VBoxUSBFilterRemove(pContext, uId);
1167 if (!RT_SUCCESS(rc))
1168 {
1169 WARN(("VBoxUSBFilterRemove failed rc (%d)", rc));
1170 VBOXUSBFLT_LOCK_RELEASE();
1171 return rc;
1172 }
1173
1174 LOG(("enumerating devices.."));
1175 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1176 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1177 pEntry = pEntry->Flink)
1178 {
1179 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1180 if (pDevice->fIsFilterOneShot)
1181 {
1182 ASSERT_WARN(!pDevice->uFltId, ("oneshot filter on device(0x%p): unexpected uFltId(%d)", pDevice, pDevice->uFltId));
1183 }
1184
1185 if (pDevice->uFltId != uId)
1186 continue;
1187
1188 ASSERT_WARN(pDevice->pOwner == pContext, ("Device(0x%p) owner(0x%p) not match to (0x%p)", pDevice, pDevice->pOwner, pContext));
1189 if (pDevice->pOwner != pContext)
1190 continue;
1191
1192 LOG(("found device(0x%p), pdo(0x%p), state(%d), filter id(0x%p), oneshot(%d)",
1193 pDevice, pDevice->Pdo, pDevice->enmState, pDevice->uFltId, (int)pDevice->fIsFilterOneShot));
1194 ASSERT_WARN(!pDevice->fIsFilterOneShot, ("device(0x%p) is filtered with a oneshot filter", pDevice));
1195 pDevice->uFltId = 0;
1196 /* clear the fIsFilterOneShot flag to ensure the device is replugged on the next VBoxUsbFltFilterCheck call */
1197 pDevice->fIsFilterOneShot = false;
1198 }
1199 VBOXUSBFLT_LOCK_RELEASE();
1200
1201 LOG(("done enumerating devices"));
1202
1203 if (RT_SUCCESS(rc))
1204 {
1205#ifdef VBOX_USBMON_WITH_FILTER_AUTOAPPLY
1206 VBoxUsbFltFilterCheck();
1207#endif
1208 }
1209 return rc;
1210}
1211
1212static USBDEVICESTATE vboxUsbDevGetUserState(PVBOXUSBFLTCTX pContext, PVBOXUSBFLT_DEVICE pDevice)
1213{
1214 if (vboxUsbFltDevStateIsNotFiltered(pDevice))
1215 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
1216
1217 /* the device is filtered, or replugging */
1218 if (pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING)
1219 {
1220 ASSERT_WARN(!pDevice->pOwner, ("replugging device(0x%p) still has an owner(0x%p)", pDevice, pDevice->pOwner));
1221 ASSERT_WARN(!pDevice->uFltId, ("replugging device(0x%p) still has filter(0x%p)", pDevice, pDevice->uFltId));
1222 /* no user state for this, we should not return it tu the user */
1223 return USBDEVICESTATE_USED_BY_HOST;
1224 }
1225
1226 /* the device is filtered, if owner differs from the context, return as USED_BY_HOST */
1227 ASSERT_WARN(pDevice->pOwner, ("device(0x%p) has noowner", pDevice));
1228 /* the id can be null if a filter is removed */
1229// Assert(pDevice->uFltId);
1230
1231 if (pDevice->pOwner != pContext)
1232 {
1233 LOG(("Device owner differs from the current context, returning used by host"));
1234 return USBDEVICESTATE_USED_BY_HOST;
1235 }
1236
1237 switch (pDevice->enmState)
1238 {
1239 case VBOXUSBFLT_DEVSTATE_UNCAPTURED:
1240 case VBOXUSBFLT_DEVSTATE_CAPTURING:
1241 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
1242 case VBOXUSBFLT_DEVSTATE_CAPTURED:
1243 return USBDEVICESTATE_HELD_BY_PROXY;
1244 case VBOXUSBFLT_DEVSTATE_USED_BY_GUEST:
1245 return USBDEVICESTATE_USED_BY_GUEST;
1246 default:
1247 WARN(("unexpected device state(%d) for device(0x%p)", pDevice->enmState, pDevice));
1248 return USBDEVICESTATE_UNSUPPORTED;
1249 }
1250}
1251
1252NTSTATUS VBoxUsbFltGetDevice(PVBOXUSBFLTCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
1253{
1254 if (!hDevice)
1255 return STATUS_INVALID_PARAMETER;
1256
1257 memset (pInfo, 0, sizeof (*pInfo));
1258 VBOXUSBFLT_LOCK_ACQUIRE();
1259 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1260 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1261 pEntry = pEntry->Flink)
1262 {
1263 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1264 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED);
1265 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED);
1266
1267 if (pDevice != hDevice)
1268 continue;
1269
1270 USBDEVICESTATE enmUsrState = vboxUsbDevGetUserState(pContext, pDevice);
1271 pInfo->enmState = enmUsrState;
1272 VBOXUSBFLT_LOCK_RELEASE();
1273 return STATUS_SUCCESS;
1274 }
1275
1276 VBOXUSBFLT_LOCK_RELEASE();
1277
1278 /* We should not get this far with valid input. */
1279 return STATUS_INVALID_PARAMETER;
1280}
1281
1282NTSTATUS VBoxUsbFltPdoAdd(PDEVICE_OBJECT pPdo, BOOLEAN *pbFiltered)
1283{
1284 *pbFiltered = FALSE;
1285 PVBOXUSBFLT_DEVICE pDevice;
1286
1287 /* first check if device is in the a already */
1288 VBOXUSBFLT_LOCK_ACQUIRE();
1289 pDevice = vboxUsbFltDevGetLocked(pPdo);
1290 if (pDevice)
1291 {
1292 LOG(("found device (0x%p), state(%d) for PDO(0x%p)", pDevice, pDevice->enmState, pPdo));
1293 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED, ("VBOXUSBFLT_DEVSTATE_ADDED state for device(0x%p)", pDevice));
1294 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED, ("VBOXUSBFLT_DEVSTATE_REMOVED state for device(0x%p)", pDevice));
1295 *pbFiltered = pDevice->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1296 VBOXUSBFLT_LOCK_RELEASE();
1297 return STATUS_SUCCESS;
1298 }
1299 VBOXUSBFLT_LOCK_RELEASE();
1300 pDevice = (PVBOXUSBFLT_DEVICE)VBoxUsbMonMemAllocZ(sizeof (*pDevice));
1301 if (!pDevice)
1302 {
1303 WARN(("VBoxUsbMonMemAllocZ failed"));
1304 return STATUS_NO_MEMORY;
1305 }
1306
1307 pDevice->enmState = VBOXUSBFLT_DEVSTATE_ADDED;
1308 pDevice->cRefs = 1;
1309 NTSTATUS Status = vboxUsbFltDevPopulate(pDevice, pPdo /* , TRUE /* need all props */);
1310 if (!NT_SUCCESS(Status))
1311 {
1312 WARN(("vboxUsbFltDevPopulate failed, Status 0x%x", Status));
1313 VBoxUsbMonMemFree(pDevice);
1314 return Status;
1315 }
1316
1317 uintptr_t uId;
1318 bool fFilter = false;
1319 bool fIsOneShot = false;
1320 PVBOXUSBFLTCTX pCtx;
1321 PVBOXUSBFLT_DEVICE pTmpDev;
1322 VBOXUSBFLT_LOCK_ACQUIRE();
1323 /* (paranoia) re-check the device is still not here */
1324 pTmpDev = vboxUsbFltDevGetLocked(pPdo);
1325 if (pTmpDev)
1326 {
1327 LOG(("second try: found device (0x%p), state(%d) for PDO(0x%p)", pDevice, pDevice->enmState, pPdo));
1328 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED, ("second try: VBOXUSBFLT_DEVSTATE_ADDED state for device(0x%p)", pDevice));
1329 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED, ("second try: VBOXUSBFLT_DEVSTATE_REMOVED state for device(0x%p)", pDevice));
1330 *pbFiltered = pTmpDev->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1331 VBOXUSBFLT_LOCK_RELEASE();
1332 VBoxUsbMonMemFree(pDevice);
1333 return STATUS_SUCCESS;
1334 }
1335
1336 LOG(("Created Device 0x%p for PDO 0x%p", pDevice, pPdo));
1337
1338 pCtx = vboxUsbFltDevMatchLocked(pDevice, &uId,
1339 true, /* remove a one-shot filter */
1340 &fFilter, &fIsOneShot);
1341 LOG(("Matching Info: Filter (0x%p), pCtx(0x%p), fFilter(%d), fIsOneShot(%d)", uId, pCtx, (int)fFilter, (int)fIsOneShot));
1342 if (fFilter)
1343 {
1344 LOG(("Created Device 0x%p should be filtered", pDevice));
1345 ASSERT_WARN(pCtx, ("zero ctx"));
1346 ASSERT_WARN(uId, ("zero uId"));
1347 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING;
1348 }
1349 else
1350 {
1351 LOG(("Created Device 0x%p should NOT be filtered", pDevice));
1352 ASSERT_WARN(!uId == !pCtx, ("invalid uid(0x%p) - ctx(0x%p) pair", uId, pCtx)); /* either both zero or both not */
1353 pDevice->enmState = VBOXUSBFLT_DEVSTATE_UNCAPTURED;
1354 }
1355
1356 if (pCtx)
1357 vboxUsbFltDevOwnerSetLocked(pDevice, pCtx, fIsOneShot ? 0 : uId, fIsOneShot);
1358
1359 InsertHeadList(&g_VBoxUsbFltGlobals.DeviceList, &pDevice->GlobalLe);
1360
1361 /* do not need to signal anything here -
1362 * going to do that once the proxy device object starts */
1363 VBOXUSBFLT_LOCK_RELEASE();
1364
1365 *pbFiltered = fFilter;
1366
1367 return STATUS_SUCCESS;
1368}
1369
1370BOOLEAN VBoxUsbFltPdoIsFiltered(PDEVICE_OBJECT pPdo)
1371{
1372 VBOXUSBFLT_DEVSTATE enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1373 VBOXUSBFLT_LOCK_ACQUIRE();
1374
1375 PVBOXUSBFLT_DEVICE pDevice = vboxUsbFltDevGetLocked(pPdo);
1376 if (pDevice)
1377 enmState = pDevice->enmState;
1378
1379 VBOXUSBFLT_LOCK_RELEASE();
1380
1381 return enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1382}
1383
1384NTSTATUS VBoxUsbFltPdoRemove(PDEVICE_OBJECT pPdo)
1385{
1386 PVBOXUSBFLT_DEVICE pDevice;
1387 VBOXUSBFLT_DEVSTATE enmOldState;
1388
1389 VBOXUSBFLT_LOCK_ACQUIRE();
1390 pDevice = vboxUsbFltDevGetLocked(pPdo);
1391 if (pDevice)
1392 {
1393 RemoveEntryList(&pDevice->GlobalLe);
1394 enmOldState = pDevice->enmState;
1395 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1396 }
1397 VBOXUSBFLT_LOCK_RELEASE();
1398 if (pDevice)
1399 vboxUsbFltDevRelease(pDevice);
1400 return STATUS_SUCCESS;
1401}
1402
1403HVBOXUSBFLTDEV VBoxUsbFltProxyStarted(PDEVICE_OBJECT pPdo)
1404{
1405 PVBOXUSBFLT_DEVICE pDevice;
1406 VBOXUSBFLT_LOCK_ACQUIRE();
1407 pDevice = vboxUsbFltDevGetLocked(pPdo);
1408 /*
1409 * Prevent a host crash when vboxUsbFltDevGetLocked fails to locate the matching PDO
1410 * in g_VBoxUsbFltGlobals.DeviceList (see @bugref{6509}).
1411 */
1412 if (pDevice == NULL)
1413 {
1414 WARN(("failed to get device for PDO(0x%p)", pPdo));
1415 }
1416 else if (pDevice->enmState == VBOXUSBFLT_DEVSTATE_CAPTURING)
1417 {
1418 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURED;
1419 LOG(("The proxy notified proxy start for the captured device 0x%x", pDevice));
1420 vboxUsbFltDevRetain(pDevice);
1421 }
1422 else
1423 {
1424 WARN(("invalid state, %d", pDevice->enmState));
1425 pDevice = NULL;
1426 }
1427 VBOXUSBFLT_LOCK_RELEASE();
1428 return pDevice;
1429}
1430
1431void VBoxUsbFltProxyStopped(HVBOXUSBFLTDEV hDev)
1432{
1433 PVBOXUSBFLT_DEVICE pDevice = (PVBOXUSBFLT_DEVICE)hDev;
1434 /*
1435 * Prevent a host crash when VBoxUsbFltProxyStarted fails, returning NULL.
1436 * See @bugref{6509}.
1437 */
1438 if (pDevice == NULL)
1439 {
1440 WARN(("VBoxUsbFltProxyStopped called with NULL device pointer"));
1441 return;
1442 }
1443 VBOXUSBFLT_LOCK_ACQUIRE();
1444 if (pDevice->enmState == VBOXUSBFLT_DEVSTATE_CAPTURED
1445 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_USED_BY_GUEST)
1446 {
1447 /* this is due to devie was physically removed */
1448 LOG(("The proxy notified proxy stop for the captured device 0x%x, current state %d", pDevice, pDevice->enmState));
1449 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING;
1450 }
1451 else
1452 {
1453 if (pDevice->enmState != VBOXUSBFLT_DEVSTATE_REPLUGGING)
1454 {
1455 WARN(("invalid state, %d", pDevice->enmState));
1456 }
1457 }
1458 VBOXUSBFLT_LOCK_RELEASE();
1459
1460 vboxUsbFltDevRelease(pDevice);
1461}
1462
1463
1464static NTSTATUS vboxUsbFltRegKeyQuery(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
1465{
1466 NTSTATUS Status = STATUS_SUCCESS;
1467
1468 RT_NOREF(ValueName, Context);
1469 if ( ValueType == REG_DWORD
1470 && ValueLength == sizeof(ULONG))
1471 *(ULONG *)EntryContext = *(ULONG *)ValueData;
1472 else
1473 Status = STATUS_OBJECT_TYPE_MISMATCH;
1474
1475 return Status;
1476}
1477
1478
1479NTSTATUS VBoxUsbFltInit()
1480{
1481 int rc = VBoxUSBFilterInit();
1482 if (RT_FAILURE(rc))
1483 {
1484 WARN(("VBoxUSBFilterInit failed, rc (%d)", rc));
1485 return STATUS_UNSUCCESSFUL;
1486 }
1487
1488 memset(&g_VBoxUsbFltGlobals, 0, sizeof (g_VBoxUsbFltGlobals));
1489 InitializeListHead(&g_VBoxUsbFltGlobals.DeviceList);
1490 InitializeListHead(&g_VBoxUsbFltGlobals.ContextList);
1491 InitializeListHead(&g_VBoxUsbFltGlobals.BlackDeviceList);
1492 vboxUsbFltBlDevPopulateWithKnownLocked();
1493 VBOXUSBFLT_LOCK_INIT();
1494
1495 /*
1496 * Check whether the setting to force replugging USB devices when
1497 * querying string descriptors fail is set in the registry,
1498 * see @bugref{9479}.
1499 */
1500 RTL_QUERY_REGISTRY_TABLE aParams[] =
1501 {
1502 {vboxUsbFltRegKeyQuery, 0, L"ForceReplugWhenDevPopulateFails", &g_VBoxUsbFltGlobals.dwForceReplugWhenDevPopulateFails, REG_DWORD, &g_VBoxUsbFltGlobals.dwForceReplugWhenDevPopulateFails, sizeof(ULONG) },
1503 { NULL, 0, NULL, NULL, 0, 0, 0 }
1504 };
1505 UNICODE_STRING UnicodePath = RTL_CONSTANT_STRING(L"\\VBoxUSB");
1506
1507 NTSTATUS Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, UnicodePath.Buffer, &aParams[0], NULL, NULL);
1508 if (Status == STATUS_SUCCESS)
1509 {
1510 if (g_VBoxUsbFltGlobals.dwForceReplugWhenDevPopulateFails)
1511 LOG(("Forcing replug of USB devices where querying the descriptors fail\n"));
1512 }
1513 else
1514 LOG(("RtlQueryRegistryValues() -> %#x, assuming defaults\n", Status));
1515
1516 return STATUS_SUCCESS;
1517}
1518
1519NTSTATUS VBoxUsbFltTerm()
1520{
1521 bool bBusy = false;
1522 VBOXUSBFLT_LOCK_ACQUIRE();
1523 do
1524 {
1525 if (!IsListEmpty(&g_VBoxUsbFltGlobals.ContextList))
1526 {
1527 AssertFailed();
1528 bBusy = true;
1529 break;
1530 }
1531
1532 PLIST_ENTRY pNext = NULL;
1533 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1534 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1535 pEntry = pNext)
1536 {
1537 pNext = pEntry->Flink;
1538 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1539 Assert(!pDevice->uFltId);
1540 Assert(!pDevice->pOwner);
1541 if (pDevice->cRefs != 1)
1542 {
1543 AssertFailed();
1544 bBusy = true;
1545 break;
1546 }
1547 }
1548 } while (0);
1549
1550 VBOXUSBFLT_LOCK_RELEASE()
1551
1552 if (bBusy)
1553 {
1554 return STATUS_DEVICE_BUSY;
1555 }
1556
1557 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1558 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1559 pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink)
1560 {
1561 RemoveEntryList(pEntry);
1562 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1563 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1564 vboxUsbFltDevRelease(pDevice);
1565 }
1566
1567 vboxUsbFltBlDevClearLocked();
1568
1569 VBOXUSBFLT_LOCK_TERM();
1570
1571 VBoxUSBFilterTerm();
1572
1573 return STATUS_SUCCESS;
1574}
1575
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