VirtualBox

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

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

USB/win: Removed unused arguments.

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