VirtualBox

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

Last change on this file since 37115 was 37047, checked in by vboxsync, 14 years ago

usb: filter misbehaved device dynamic black list

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