VirtualBox

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

Last change on this file since 79846 was 79399, checked in by vboxsync, 6 years ago

Removed stray text.

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