VirtualBox

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

Last change on this file since 70283 was 70283, checked in by vboxsync, 7 years ago

Removed unused code.

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

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