VirtualBox

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

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

VBoxUSBMon: Removed unused function.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette