VirtualBox

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

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

scm --update-copyright-year

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