VirtualBox

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

Last change on this file since 47511 was 38513, checked in by vboxsync, 13 years ago

win-dbg build fix

  • 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 38513 2011-08-24 11:12:07Z 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_WARN(!pDevice->pOwner, ("device 0x%p has an owner(0x%p)", pDevice, 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_WARN(pDevice->pOwner, ("no owner for device 0x%p", pDevice));
264 --pDevice->pOwner->cActiveFilters;
265 ASSERT_WARN(pDevice->pOwner->cActiveFilters < UINT32_MAX/2, ("cActiveFilters (%d)", pDevice->pOwner->cActiveFilters));
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 VBOX_USB_WITH_VERBOSE_LOGGING
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_WARN( pDevice->idVendor != pDevice2->idVendor
300 || pDevice->idProduct != pDevice2->idProduct
301 || pDevice->bcdDevice != pDevice2->bcdDevice, ("duplicate devices in a list!!"));
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_WARN( 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 ("Invalid device state(%d) for device(0x%p) PDO(0x%p)", pDevice->enmState, pDevice, pDevice->Pdo));
316 if (pDevice->Pdo == pPdo)
317 return pDevice;
318 }
319 return NULL;
320}
321
322PVBOXUSBFLT_DEVICE vboxUsbFltDevGet(PDEVICE_OBJECT pPdo)
323{
324 PVBOXUSBFLT_DEVICE pDevice;
325
326 VBOXUSBFLT_LOCK_ACQUIRE();
327 pDevice = vboxUsbFltDevGetLocked(pPdo);
328 if (pDevice->enmState > VBOXUSBFLT_DEVSTATE_ADDED)
329 {
330 vboxUsbFltDevRetain(pDevice);
331 LOG(("found device (0x%p), state(%d) for PDO(0x%p)", pDevice, pDevice->enmState, pPdo));
332 }
333 else
334 {
335 LOG(("found replugging device (0x%p), state(%d) for PDO(0x%p)", pDevice, pDevice->enmState, pPdo));
336 pDevice = NULL;
337 }
338 VBOXUSBFLT_LOCK_RELEASE();
339
340 return pDevice;
341}
342
343static NTSTATUS vboxUsbFltPdoReplug(PDEVICE_OBJECT pDo)
344{
345 LOG(("Replugging PDO(0x%p)", pDo));
346 NTSTATUS Status = VBoxUsbToolIoInternalCtlSendSync(pDo, IOCTL_INTERNAL_USB_CYCLE_PORT, NULL, NULL);
347 ASSERT_WARN(Status == STATUS_SUCCESS, ("replugging PDO(0x%p) failed Status(0x%x)", pDo, Status));
348 LOG(("Replugging PDO(0x%p) done with Status(0x%x)", pDo, Status));
349 return Status;
350}
351
352static bool vboxUsbFltDevCanBeCaptured(PVBOXUSBFLT_DEVICE pDevice)
353{
354 if (pDevice->bClass == USB_DEVICE_CLASS_HUB)
355 {
356 LOG(("device (0x%p), pdo (0x%p) is a hub, can not be captured", pDevice, pDevice->Pdo));
357 return false;
358 }
359 return true;
360}
361
362static PVBOXUSBFLTCTX vboxUsbFltDevMatchLocked(PVBOXUSBFLT_DEVICE pDevice, uintptr_t *puId, bool fRemoveFltIfOneShot, bool *pfFilter, bool *pfIsOneShot)
363{
364 *puId = 0;
365 *pfFilter = false;
366 *pfIsOneShot = false;
367 if (!vboxUsbFltDevCanBeCaptured(pDevice))
368 {
369 LOG(("vboxUsbFltDevCanBeCaptured returned false"));
370 return NULL;
371 }
372
373 USBFILTER DevFlt;
374 USBFilterInit(&DevFlt, USBFILTERTYPE_CAPTURE);
375 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_VENDOR_ID, pDevice->idVendor, true);
376 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_PRODUCT_ID, pDevice->idProduct, true);
377 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_REV, pDevice->bcdDevice, true);
378 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_CLASS, pDevice->bClass, true);
379 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_SUB_CLASS, pDevice->bSubClass, true);
380 USBFilterSetNumExact(&DevFlt, USBFILTERIDX_DEVICE_PROTOCOL, pDevice->bProtocol, true);
381 USBFilterSetStringExact(&DevFlt, USBFILTERIDX_MANUFACTURER_STR, pDevice->szMfgName, true);
382 USBFilterSetStringExact(&DevFlt, USBFILTERIDX_PRODUCT_STR, pDevice->szProduct, true);
383 USBFilterSetStringExact(&DevFlt, USBFILTERIDX_SERIAL_NUMBER_STR, pDevice->szSerial, true);
384
385 /* Run filters on the thing. */
386 PVBOXUSBFLTCTX pOwner = VBoxUSBFilterMatchEx(&DevFlt, puId, fRemoveFltIfOneShot, pfFilter, pfIsOneShot);
387 USBFilterDelete(&DevFlt);
388 return pOwner;
389}
390
391static void vboxUsbFltDevStateMarkReplugLocked(PVBOXUSBFLT_DEVICE pDevice)
392{
393 vboxUsbFltDevOwnerUpdateLocked(pDevice, NULL, 0, false);
394 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REPLUGGING;
395}
396
397static bool vboxUsbFltDevStateIsNotFiltered(PVBOXUSBFLT_DEVICE pDevice)
398{
399 return pDevice->enmState == VBOXUSBFLT_DEVSTATE_UNCAPTURED;
400}
401
402static bool vboxUsbFltDevStateIsFiltered(PVBOXUSBFLT_DEVICE pDevice)
403{
404 return pDevice->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
405}
406
407#define VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS 10000
408
409static NTSTATUS vboxUsbFltDevPopulate(PVBOXUSBFLT_DEVICE pDevice, PDEVICE_OBJECT pDo /*, BOOLEAN bPopulateNonFilterProps*/)
410{
411 NTSTATUS Status;
412 PUSB_DEVICE_DESCRIPTOR pDevDr = 0;
413
414 pDevice->Pdo = pDo;
415
416 LOG(("Populating Device(0x%p) for PDO(0x%p)", pDevice, pDo));
417
418 pDevDr = (PUSB_DEVICE_DESCRIPTOR)VBoxUsbMonMemAllocZ(sizeof(*pDevDr));
419 if (pDevDr == NULL)
420 {
421 WARN(("Failed to alloc mem for urb"));
422 return STATUS_INSUFFICIENT_RESOURCES;
423 }
424
425 do
426 {
427 Status = VBoxUsbToolGetDescriptor(pDo, pDevDr, sizeof(*pDevDr), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
428 if (!NT_SUCCESS(Status))
429 {
430 WARN(("getting device descriptor failed, Status (0x%x)", Status));
431 break;
432 }
433
434 if (vboxUsbFltBlDevMatchLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice))
435 {
436 WARN(("found a known black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
437 Status = STATUS_UNSUCCESSFUL;
438 break;
439 }
440
441 LOG(("Device pid=%x vid=%x rev=%x", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
442 pDevice->idVendor = pDevDr->idVendor;
443 pDevice->idProduct = pDevDr->idProduct;
444 pDevice->bcdDevice = pDevDr->bcdDevice;
445 pDevice->bClass = pDevDr->bDeviceClass;
446 pDevice->bSubClass = pDevDr->bDeviceSubClass;
447 pDevice->bProtocol = pDevDr->bDeviceProtocol;
448 pDevice->szSerial[0] = 0;
449 pDevice->szMfgName[0] = 0;
450 pDevice->szProduct[0] = 0;
451
452 /* If there are no strings, don't even try to get any string descriptors. */
453 if (pDevDr->iSerialNumber || pDevDr->iManufacturer || pDevDr->iProduct)
454 {
455 int langId;
456
457 Status = VBoxUsbToolGetLangID(pDo, &langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
458 if (!NT_SUCCESS(Status))
459 {
460 WARN(("reading language ID failed"));
461 if (Status == STATUS_CANCELLED)
462 {
463 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
464 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
465 Status = STATUS_UNSUCCESSFUL;
466 }
467 break;
468 }
469
470 if (pDevDr->iSerialNumber)
471 {
472 Status = VBoxUsbToolGetStringDescriptorA(pDo, pDevice->szSerial, sizeof (pDevice->szSerial), pDevDr->iSerialNumber, langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
473 if (!NT_SUCCESS(Status))
474 {
475 WARN(("reading serial number failed"));
476 ASSERT_WARN(pDevice->szSerial[0] == '\0', ("serial is not zero!!"));
477 if (Status == STATUS_CANCELLED)
478 {
479 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
480 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
481 Status = STATUS_UNSUCCESSFUL;
482 break;
483 }
484 LOG(("pretending success.."));
485 Status = STATUS_SUCCESS;
486 }
487 }
488
489 if (pDevDr->iManufacturer)
490 {
491 Status = VBoxUsbToolGetStringDescriptorA(pDo, pDevice->szMfgName, sizeof (pDevice->szMfgName), pDevDr->iManufacturer, langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
492 if (!NT_SUCCESS(Status))
493 {
494 WARN(("reading manufacturer name failed"));
495 ASSERT_WARN(pDevice->szMfgName[0] == '\0', ("szMfgName is not zero!!"));
496 if (Status == STATUS_CANCELLED)
497 {
498 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
499 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
500 Status = STATUS_UNSUCCESSFUL;
501 break;
502 }
503 LOG(("pretending success.."));
504 Status = STATUS_SUCCESS;
505 }
506 }
507
508 if (pDevDr->iProduct)
509 {
510 Status = VBoxUsbToolGetStringDescriptorA(pDo, pDevice->szProduct, sizeof (pDevice->szProduct), pDevDr->iProduct, langId, VBOXUSBMON_POPULATE_REQUEST_TIMEOUT_MS);
511 if (!NT_SUCCESS(Status))
512 {
513 WARN(("reading product name failed"));
514 ASSERT_WARN(pDevice->szProduct[0] == '\0', ("szProduct is not zero!!"));
515 if (Status == STATUS_CANCELLED)
516 {
517 WARN(("found a new black list device, vid(0x%x), pid(0x%x), rev(0x%x)", pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice));
518 vboxUsbFltBlDevAddLocked(pDevDr->idVendor, pDevDr->idProduct, pDevDr->bcdDevice);
519 Status = STATUS_UNSUCCESSFUL;
520 break;
521 }
522 LOG(("pretending success.."));
523 Status = STATUS_SUCCESS;
524 }
525 }
526
527#if 0
528 if (bPopulateNonFilterProps)
529 {
530 WCHAR RegKeyBuf[512];
531 ULONG cbRegKeyBuf = sizeof (RegKeyBuf);
532 Status = IoGetDeviceProperty(pDo,
533 DevicePropertyDriverKeyName,
534 cbRegKeyBuf,
535 RegKeyBuf,
536 &cbRegKeyBuf);
537 if (!NT_SUCCESS(Status))
538 {
539 AssertMsgFailed((__FUNCTION__": IoGetDeviceProperty failed Status (0x%x)", Status));
540 break;
541 }
542
543 ANSI_STRING Ansi;
544 UNICODE_STRING Unicode;
545 Ansi.Buffer = pDevice->szDrvKeyName;
546 Ansi.Length = 0;
547 Ansi.MaximumLength = sizeof(pDevice->szDrvKeyName);
548 RtlInitUnicodeString(&Unicode, RegKeyBuf);
549
550 Status = RtlUnicodeStringToAnsiString(&Ansi, &Unicode, FALSE /* do not allocate */);
551 if (!NT_SUCCESS(Status))
552 {
553 AssertMsgFailed((__FUNCTION__": RtlUnicodeStringToAnsiString failed Status (0x%x)", Status));
554 break;
555 }
556
557 pDevice->fHighSpend = FALSE;
558 Status = VBoxUsbToolGetDeviceSpeed(pDo, &pDevice->fHighSpend);
559 if (!NT_SUCCESS(Status))
560 {
561 AssertMsgFailed((__FUNCTION__": VBoxUsbToolGetDeviceSpeed failed Status (0x%x)", Status));
562 break;
563 }
564 }
565#endif
566 LOG((": strings: '%s':'%s':'%s' (lang ID %x)",
567 pDevice->szMfgName, pDevice->szProduct, pDevice->szSerial, langId));
568 }
569
570 LOG(("Populating Device(0x%p) for PDO(0x%p) Succeeded", pDevice, pDo));
571 Status = STATUS_SUCCESS;
572 } while (0);
573
574 VBoxUsbMonMemFree(pDevDr);
575 LOG(("Populating Device(0x%p) for PDO(0x%p) Done, Status (0x%x)", pDevice, pDo, Status));
576 return Status;
577}
578
579static void vboxUsbFltSignalChangeLocked()
580{
581 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.ContextList.Flink;
582 pEntry != &g_VBoxUsbFltGlobals.ContextList;
583 pEntry = pEntry->Flink)
584 {
585 PVBOXUSBFLTCTX pCtx = PVBOXUSBFLTCTX_FROM_LE(pEntry);
586 /* the removed context can not be in a list */
587 Assert(!pCtx->bRemoved);
588 if (pCtx->pChangeEvent)
589 {
590 KeSetEvent(pCtx->pChangeEvent,
591 0, /* increment*/
592 FALSE /* wait */);
593 }
594 }
595}
596
597static bool vboxUsbFltDevCheckReplugLocked(PVBOXUSBFLT_DEVICE pDevice, PVBOXUSBFLTCTX pContext)
598{
599 ASSERT_WARN(pContext, ("context is NULL!"));
600
601 LOG(("Current context is (0x%p)", pContext));
602 LOG(("Current Device owner is (0x%p)", pDevice->pOwner));
603
604 /* check if device is already replugging */
605 if (pDevice->enmState <= VBOXUSBFLT_DEVSTATE_ADDED)
606 {
607 LOG(("Device (0x%p) is already replugging, return..", pDevice));
608 /* it is, do nothing */
609 ASSERT_WARN(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING,
610 ("Device (0x%p) state is NOT REPLUGGING (%d)", pDevice, pDevice->enmState));
611 return false;
612 }
613
614 if (pDevice->pOwner && pContext != pDevice->pOwner)
615 {
616 LOG(("Device (0x%p) is owned by another context(0x%p), current is(0x%p)", pDevice, pDevice->pOwner, pContext));
617 /* this device is owned by another context, we're not allowed to do anything */
618 return false;
619 }
620
621 uintptr_t uId = 0;
622 bool bNeedReplug = false;
623 bool fFilter = false;
624 bool fIsOneShot = false;
625 PVBOXUSBFLTCTX pNewOwner = vboxUsbFltDevMatchLocked(pDevice, &uId,
626 false, /* do not remove a one-shot filter */
627 &fFilter, &fIsOneShot);
628 LOG(("Matching Info: Filter (0x%p), NewOwner(0x%p), fFilter(%d), fIsOneShot(%d)", uId, pNewOwner, (int)fFilter, (int)fIsOneShot));
629 if (pDevice->pOwner && pNewOwner && pDevice->pOwner != pNewOwner)
630 {
631 LOG(("Matching: Device (0x%p) is requested another owner(0x%p), current is(0x%p)", pDevice, pNewOwner, pDevice->pOwner));
632 /* the device is owned by another owner, we can not change the owner here */
633 return false;
634 }
635
636 if (!fFilter)
637 {
638 LOG(("Matching: Device (0x%p) should NOT be filtered", pDevice));
639 /* the device should NOT be filtered, check the current state */
640 if (vboxUsbFltDevStateIsNotFiltered(pDevice))
641 {
642 LOG(("Device (0x%p) is NOT filtered", pDevice));
643 /* no changes */
644 if (fIsOneShot)
645 {
646 ASSERT_WARN(pNewOwner, ("no new owner"));
647 LOG(("Matching: This is a one-shot filter (0x%p), removing..", uId));
648 /* remove a one-shot filter and keep the original filter data */
649 int tmpRc = VBoxUSBFilterRemove(pNewOwner, uId);
650 ASSERT_WARN(RT_SUCCESS(tmpRc), ("remove filter failed, rc (%d)", tmpRc));
651 if (!pDevice->pOwner)
652 {
653 LOG(("Matching: updating the one-shot owner to (0x%p), fltId(0x%p)", pNewOwner, uId));
654 /* update owner for one-shot if the owner is changed (i.e. assigned) */
655 vboxUsbFltDevOwnerUpdateLocked(pDevice, pNewOwner, uId, true);
656 }
657 else
658 {
659 LOG(("Matching: device already has owner (0x%p) assigned", pDevice->pOwner));
660 }
661 }
662 else
663 {
664 LOG(("Matching: This is NOT a one-shot filter (0x%p), newOwner(0x%p)", uId, pNewOwner));
665 if (pNewOwner)
666 {
667 vboxUsbFltDevOwnerUpdateLocked(pDevice, pNewOwner, uId, false);
668 }
669 }
670 }
671 else
672 {
673 LOG(("Device (0x%p) IS filtered", pDevice));
674 /* the device is currently filtered, we should release it only if
675 * 1. device does not have an owner
676 * or
677 * 2. it should be released bue to a one-shot filter
678 * or
679 * 3. it is NOT grabbed by a one-shot filter */
680 if (!pDevice->pOwner || fIsOneShot || !pDevice->fIsFilterOneShot)
681 {
682 LOG(("Matching: Need replug"));
683 bNeedReplug = true;
684 }
685 }
686 }
687 else
688 {
689 LOG(("Matching: Device (0x%p) SHOULD be filtered", pDevice));
690 /* the device should be filtered, check the current state */
691 ASSERT_WARN(uId, ("zero uid"));
692 ASSERT_WARN(pNewOwner, ("zero pNewOwner"));
693 if (vboxUsbFltDevStateIsFiltered(pDevice))
694 {
695 LOG(("Device (0x%p) IS filtered", pDevice));
696 /* the device is filtered */
697 if (pNewOwner == pDevice->pOwner)
698 {
699 LOG(("Device owner match"));
700 /* no changes */
701 if (fIsOneShot)
702 {
703 LOG(("Matching: This is a one-shot filter (0x%p), removing..", uId));
704 /* remove a one-shot filter and keep the original filter data */
705 int tmpRc = VBoxUSBFilterRemove(pNewOwner, uId);
706 ASSERT_WARN(RT_SUCCESS(tmpRc), ("remove filter failed, rc (%d)", tmpRc));
707 }
708 else
709 {
710 LOG(("Matching: This is NOT a one-shot filter (0x%p), Owner(0x%p)", uId, pDevice->pOwner));
711 vboxUsbFltDevOwnerUpdateLocked(pDevice, pDevice->pOwner, uId, false);
712 }
713 }
714 else
715 {
716 ASSERT_WARN(!pDevice->pOwner, ("device should NOT have owner"));
717 LOG(("Matching: Need replug"));
718 /* the device needs to be filtered, but the owner changes, replug needed */
719 bNeedReplug = true;
720 }
721 }
722 else
723 {
724 /* the device is currently NOT filtered,
725 * we should replug it only if
726 * 1. device does not have an owner
727 * or
728 * 2. it should be captured due to a one-shot filter
729 * or
730 * 3. it is NOT released by a one-shot filter */
731 if (!pDevice->pOwner || fIsOneShot || !pDevice->fIsFilterOneShot)
732 {
733 bNeedReplug = true;
734 LOG(("Matching: Need replug"));
735 }
736 }
737 }
738
739 if (bNeedReplug)
740 {
741 LOG(("Matching: Device needs replugging, marking as such"));
742 vboxUsbFltDevStateMarkReplugLocked(pDevice);
743 }
744 else
745 {
746 LOG(("Matching: Device does NOT need replugging"));
747 }
748
749 return bNeedReplug;
750}
751
752static void vboxUsbFltReplugList(PLIST_ENTRY pList)
753{
754 PLIST_ENTRY pNext;
755 for (PLIST_ENTRY pEntry = pList->Flink;
756 pEntry != pList;
757 pEntry = pNext)
758 {
759 pNext = pEntry->Flink;
760 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_REPLUGGINGLE(pEntry);
761 LOG(("replugging matched PDO(0x%p), pDevice(0x%p)", pDevice->Pdo, pDevice));
762 ASSERT_WARN(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING
763 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_REMOVED,
764 ("invalid state(0x%x) for device(0x%p)", pDevice->enmState, pDevice));
765
766 vboxUsbFltPdoReplug(pDevice->Pdo);
767 ObDereferenceObject(pDevice->Pdo);
768 vboxUsbFltDevRelease(pDevice);
769 }
770}
771
772typedef struct VBOXUSBFLTCHECKWALKER
773{
774 PVBOXUSBFLTCTX pContext;
775} VBOXUSBFLTCHECKWALKER, *PVBOXUSBFLTCHECKWALKER;
776
777static DECLCALLBACK(BOOLEAN) vboxUsbFltFilterCheckWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
778{
779 PVBOXUSBFLTCHECKWALKER pData = (PVBOXUSBFLTCHECKWALKER)pvContext;
780 PVBOXUSBFLTCTX pContext = pData->pContext;
781
782 LOG(("Visiting pFile(0x%p), pTopDo(0x%p), pHubDo(0x%p), oContext(0x%p)", pFile, pTopDo, pHubDo, pContext));
783 KIRQL Irql = KeGetCurrentIrql();
784 ASSERT_WARN(Irql == PASSIVE_LEVEL, ("unexpected IRQL (%d)", Irql));
785
786 PDEVICE_RELATIONS pDevRelations = NULL;
787
788 NTSTATUS Status = VBoxUsbMonQueryBusRelations(pTopDo, pFile, &pDevRelations);
789 if (Status == STATUS_SUCCESS && pDevRelations)
790 {
791 ULONG cReplugPdos = pDevRelations->Count;
792 LIST_ENTRY ReplugDevList;
793 InitializeListHead(&ReplugDevList);
794 for (ULONG k = 0; k < pDevRelations->Count; ++k)
795 {
796 PDEVICE_OBJECT pDevObj = pDevRelations->Objects[k];
797
798 LOG(("Found existing USB PDO 0x%p", pDevObj));
799 VBOXUSBFLT_LOCK_ACQUIRE();
800 PVBOXUSBFLT_DEVICE pDevice = vboxUsbFltDevGetLocked(pDevObj);
801 if (pDevice)
802 {
803 LOG(("Found existing device info (0x%p) for PDO 0x%p", pDevice, pDevObj));
804 bool bReplug = vboxUsbFltDevCheckReplugLocked(pDevice, pContext);
805 if (bReplug)
806 {
807 LOG(("Replug needed for device (0x%p)", pDevice));
808 InsertHeadList(&ReplugDevList, &pDevice->RepluggingLe);
809 vboxUsbFltDevRetain(pDevice);
810 /* do not dereference object since we will use it later */
811 }
812 else
813 {
814 LOG(("Replug NOT needed for device (0x%p)", pDevice));
815 ObDereferenceObject(pDevObj);
816 }
817
818 VBOXUSBFLT_LOCK_RELEASE();
819
820 pDevRelations->Objects[k] = NULL;
821 --cReplugPdos;
822 ASSERT_WARN((uint32_t)cReplugPdos < UINT32_MAX/2, ("cReplugPdos(%d) state broken", cReplugPdos));
823 continue;
824 }
825 VBOXUSBFLT_LOCK_RELEASE();
826
827 LOG(("NO device info found for PDO 0x%p", pDevObj));
828 VBOXUSBFLT_DEVICE Device;
829 Status = vboxUsbFltDevPopulate(&Device, pDevObj /*, FALSE /* only need filter properties */);
830 if (NT_SUCCESS(Status))
831 {
832 uintptr_t uId = 0;
833 bool fFilter = false;
834 bool fIsOneShot = false;
835 VBOXUSBFLT_LOCK_ACQUIRE();
836 PVBOXUSBFLTCTX pCtx = vboxUsbFltDevMatchLocked(&Device, &uId,
837 false, /* do not remove a one-shot filter */
838 &fFilter, &fIsOneShot);
839 VBOXUSBFLT_LOCK_RELEASE();
840 LOG(("Matching Info: Filter (0x%p), pCtx(0x%p), fFilter(%d), fIsOneShot(%d)", uId, pCtx, (int)fFilter, (int)fIsOneShot));
841 if (fFilter)
842 {
843 LOG(("Matching: This device SHOULD be filtered"));
844 /* this device needs to be filtered, but it's not,
845 * leave the PDO in array to issue a replug request for it
846 * later on */
847 continue;
848 }
849 }
850 else
851 {
852 WARN(("vboxUsbFltDevPopulate for PDO 0x%p failed with Status 0x%x", pDevObj, Status));
853 }
854
855 LOG(("Matching: This device should NOT be filtered"));
856 /* this device should not be filtered, and it's not */
857 ObDereferenceObject(pDevObj);
858 pDevRelations->Objects[k] = NULL;
859 --cReplugPdos;
860 ASSERT_WARN((uint32_t)cReplugPdos < UINT32_MAX/2, ("cReplugPdos is %d", cReplugPdos));
861 }
862
863 LOG(("(%d) non-matched PDOs to be replugged", cReplugPdos));
864
865 if (cReplugPdos)
866 {
867 for (ULONG k = 0; k < pDevRelations->Count; ++k)
868 {
869 if (!pDevRelations->Objects[k])
870 continue;
871
872 Status = vboxUsbFltPdoReplug(pDevRelations->Objects[k]);
873 ASSERT_WARN(Status == STATUS_SUCCESS, ("vboxUsbFltPdoReplug ailed Status(0x%x)", Status));
874 ObDereferenceObject(pDevRelations->Objects[k]);
875 if (!--cReplugPdos)
876 break;
877 }
878
879 ASSERT_WARN(!cReplugPdos, ("cReplugPdosreached zero!"));
880 }
881
882 vboxUsbFltReplugList(&ReplugDevList);
883
884 ExFreePool(pDevRelations);
885 }
886 else
887 {
888 WARN(("VBoxUsbMonQueryBusRelations failed for DO(0x%p), Status(0x%x), pDevRelations(0x%p)",
889 pTopDo, Status, pDevRelations));
890 }
891
892 LOG(("Done Visiting pFile(0x%p), pTopDo(0x%p), pHubDo(0x%p), oContext(0x%p)", pFile, pTopDo, pHubDo, pContext));
893
894 return TRUE;
895}
896
897NTSTATUS VBoxUsbFltFilterCheck(PVBOXUSBFLTCTX pContext)
898{
899 KIRQL Irql = KeGetCurrentIrql();
900 ASSERT_WARN(Irql == PASSIVE_LEVEL, ("unexpected IRQL (%d)", Irql));
901
902 LOG(("Running filters, Context (0x%p)..", pContext));
903
904 VBOXUSBFLTCHECKWALKER Data;
905 Data.pContext = pContext;
906 vboxUsbMonHubDevWalk(vboxUsbFltFilterCheckWalker, &Data, VBOXUSBMONHUBWALK_F_FDO);
907
908 LOG(("DONE Running filters, Context (0x%p)", pContext));
909
910 return STATUS_SUCCESS;
911}
912
913NTSTATUS VBoxUsbFltClose(PVBOXUSBFLTCTX pContext)
914{
915 LOG(("Closing context(0x%p)", pContext));
916 LIST_ENTRY ReplugDevList;
917 InitializeListHead(&ReplugDevList);
918
919 ASSERT_WARN(pContext, ("null context"));
920
921 KIRQL Irql = KeGetCurrentIrql();
922 ASSERT_WARN(Irql == PASSIVE_LEVEL, ("irql==(%d)", Irql));
923
924 VBOXUSBFLT_LOCK_ACQUIRE();
925 uint32_t cActiveFilters = pContext->cActiveFilters;
926 pContext->bRemoved = TRUE;
927 if (pContext->pChangeEvent)
928 {
929 LOG(("seting & closing change event (0x%p)", pContext->pChangeEvent));
930 KeSetEvent(pContext->pChangeEvent,
931 0, /* increment*/
932 FALSE /* wait */);
933 ObDereferenceObject(pContext->pChangeEvent);
934 pContext->pChangeEvent = NULL;
935 }
936 else
937 {
938 LOG(("no change event"));
939 }
940 RemoveEntryList(&pContext->ListEntry);
941
942 LOG(("removing owner filters"));
943 /* now re-arrange the filters */
944 /* 1. remove filters */
945 VBoxUSBFilterRemoveOwner(pContext);
946
947 LOG(("enumerating devices.."));
948 /* 2. check if there are devices owned */
949 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
950 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
951 pEntry = pEntry->Flink)
952 {
953 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
954 if (pDevice->pOwner != pContext)
955 continue;
956
957 LOG(("found device(0x%p), pdo(0x%p), state(%d), filter id(0x%p), oneshot(%d)",
958 pDevice, pDevice->Pdo, pDevice->enmState, pDevice->uFltId, (int)pDevice->fIsFilterOneShot));
959 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED, ("VBOXUSBFLT_DEVSTATE_ADDED state for device(0x%p)", pDevice));
960 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED, ("VBOXUSBFLT_DEVSTATE_REMOVED state for device(0x%p)", pDevice));
961
962 vboxUsbFltDevOwnerClearLocked(pDevice);
963
964 if (vboxUsbFltDevCheckReplugLocked(pDevice, pContext))
965 {
966 LOG(("device needs replug"));
967 InsertHeadList(&ReplugDevList, &pDevice->RepluggingLe);
968 /* retain to ensure the device is not removed before we issue a replug */
969 vboxUsbFltDevRetain(pDevice);
970 /* keep the PDO alive */
971 ObReferenceObject(pDevice->Pdo);
972 }
973 else
974 {
975 LOG(("device does NOT need replug"));
976 }
977 }
978 VBOXUSBFLT_LOCK_RELEASE();
979
980 /* this should replug all devices that were either skipped or grabbed due to the context's */
981 vboxUsbFltReplugList(&ReplugDevList);
982
983 LOG(("SUCCESS done context(0x%p)", pContext));
984 return STATUS_SUCCESS;
985}
986
987NTSTATUS VBoxUsbFltCreate(PVBOXUSBFLTCTX pContext)
988{
989 LOG(("Creating context(0x%p)", pContext));
990 memset(pContext, 0, sizeof (*pContext));
991 pContext->Process = RTProcSelf();
992 VBOXUSBFLT_LOCK_ACQUIRE();
993 InsertHeadList(&g_VBoxUsbFltGlobals.ContextList, &pContext->ListEntry);
994 VBOXUSBFLT_LOCK_RELEASE();
995 LOG(("SUCCESS context(0x%p)", pContext));
996 return STATUS_SUCCESS;
997}
998
999int VBoxUsbFltAdd(PVBOXUSBFLTCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
1000{
1001 LOG(("adding filter, Context (0x%p)..", pContext));
1002 *pId = 0;
1003 /* LOG the filter details. */
1004 LOG((__FUNCTION__": %s %s %s",
1005 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1006 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1007 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1008#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1009 LOG(("VBoxUSBClient::addFilter: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x Type%#x",
1010 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
1011 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
1012 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
1013 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
1014 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
1015 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
1016 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
1017 USBFilterGetNum(pFilter, USBFILTERIDX_PORT),
1018 USBFilterGetFilterType(pFilter)));
1019#endif
1020
1021 /* We can't get the bus/port numbers. Ignore them while matching. */
1022 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false);
1023 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_PORT, false);
1024
1025 uintptr_t uId = 0;
1026 VBOXUSBFLT_LOCK_ACQUIRE();
1027 /* Add the filter. */
1028 int rc = VBoxUSBFilterAdd(pFilter, pContext, &uId);
1029 VBOXUSBFLT_LOCK_RELEASE();
1030 if (RT_SUCCESS(rc))
1031 {
1032 LOG(("ADDED filer id 0x%p", uId));
1033 ASSERT_WARN(uId, ("uid is NULL"));
1034#ifdef VBOX_USBMON_WITH_FILTER_AUTOAPPLY
1035 VBoxUsbFltFilterCheck();
1036#endif
1037 }
1038 else
1039 {
1040 WARN(("VBoxUSBFilterAdd failed rc (%d)", rc));
1041 ASSERT_WARN(!uId, ("uid is not NULL"));
1042 }
1043
1044 *pId = uId;
1045 return rc;
1046}
1047
1048int VBoxUsbFltRemove(PVBOXUSBFLTCTX pContext, uintptr_t uId)
1049{
1050 LOG(("removing filter id(0x%p), Context (0x%p)..", pContext, uId));
1051 Assert(uId);
1052
1053 VBOXUSBFLT_LOCK_ACQUIRE();
1054 int rc = VBoxUSBFilterRemove(pContext, uId);
1055 if (!RT_SUCCESS(rc))
1056 {
1057 WARN(("VBoxUSBFilterRemove failed rc (%d)", rc));
1058 VBOXUSBFLT_LOCK_RELEASE();
1059 return rc;
1060 }
1061
1062 LOG(("enumerating devices.."));
1063 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1064 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1065 pEntry = pEntry->Flink)
1066 {
1067 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1068 if (pDevice->fIsFilterOneShot)
1069 {
1070 ASSERT_WARN(!pDevice->uFltId, ("oneshot filter on device(0x%p): unexpected uFltId(%d)", pDevice, pDevice->uFltId));
1071 }
1072
1073 if (pDevice->uFltId != uId)
1074 continue;
1075
1076 ASSERT_WARN(pDevice->pOwner == pContext, ("Device(0x%p) owner(0x%p) not match to (0x%p)", pDevice, pDevice->pOwner, pContext));
1077 if (pDevice->pOwner != pContext)
1078 continue;
1079
1080 LOG(("found device(0x%p), pdo(0x%p), state(%d), filter id(0x%p), oneshot(%d)",
1081 pDevice, pDevice->Pdo, pDevice->enmState, pDevice->uFltId, (int)pDevice->fIsFilterOneShot));
1082 ASSERT_WARN(!pDevice->fIsFilterOneShot, ("device(0x%p) is filtered with a oneshot filter", pDevice));
1083 pDevice->uFltId = 0;
1084 /* clear the fIsFilterOneShot flag to ensure the device is replugged on the next VBoxUsbFltFilterCheck call */
1085 pDevice->fIsFilterOneShot = false;
1086 }
1087 VBOXUSBFLT_LOCK_RELEASE();
1088
1089 LOG(("done enumerating devices"));
1090
1091 if (RT_SUCCESS(rc))
1092 {
1093#ifdef VBOX_USBMON_WITH_FILTER_AUTOAPPLY
1094 VBoxUsbFltFilterCheck();
1095#endif
1096 }
1097 return rc;
1098}
1099
1100NTSTATUS VBoxUsbFltSetNotifyEvent(PVBOXUSBFLTCTX pContext, HANDLE hEvent)
1101{
1102 NTSTATUS Status = STATUS_SUCCESS;
1103 PKEVENT pEvent = NULL;
1104 PKEVENT pOldEvent = NULL;
1105 if (hEvent)
1106 {
1107 Status = ObReferenceObjectByHandle(hEvent,
1108 EVENT_MODIFY_STATE,
1109 *ExEventObjectType, UserMode,
1110 (PVOID*)&pEvent,
1111 NULL);
1112 Assert(Status == STATUS_SUCCESS);
1113 if (!NT_SUCCESS(Status))
1114 return Status;
1115 }
1116
1117 VBOXUSBFLT_LOCK_ACQUIRE();
1118 pOldEvent = pContext->pChangeEvent;
1119 pContext->pChangeEvent = pEvent;
1120 VBOXUSBFLT_LOCK_RELEASE();
1121
1122 if (pOldEvent)
1123 {
1124 ObDereferenceObject(pOldEvent);
1125 }
1126
1127 return STATUS_SUCCESS;
1128}
1129
1130static USBDEVICESTATE vboxUsbDevGetUserState(PVBOXUSBFLTCTX pContext, PVBOXUSBFLT_DEVICE pDevice)
1131{
1132 if (vboxUsbFltDevStateIsNotFiltered(pDevice))
1133 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
1134
1135 /* the device is filtered, or replugging */
1136 if (pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING)
1137 {
1138 ASSERT_WARN(!pDevice->pOwner, ("replugging device(0x%p) still has an owner(0x%p)", pDevice, pDevice->pOwner));
1139 ASSERT_WARN(!pDevice->uFltId, ("replugging device(0x%p) still has filter(0x%p)", pDevice, pDevice->uFltId));
1140 /* no user state for this, we should not return it tu the user */
1141 return USBDEVICESTATE_USED_BY_HOST;
1142 }
1143
1144 /* the device is filtered, if owner differs from the context, return as USED_BY_HOST */
1145 ASSERT_WARN(pDevice->pOwner, ("device(0x%p) has noowner", pDevice));
1146 /* the id can be null if a filter is removed */
1147// Assert(pDevice->uFltId);
1148
1149 if (pDevice->pOwner != pContext)
1150 {
1151 LOG(("Device owner differs from the current context, returning used by host"));
1152 return USBDEVICESTATE_USED_BY_HOST;
1153 }
1154
1155 switch (pDevice->enmState)
1156 {
1157 case VBOXUSBFLT_DEVSTATE_UNCAPTURED:
1158 case VBOXUSBFLT_DEVSTATE_CAPTURING:
1159 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
1160 case VBOXUSBFLT_DEVSTATE_CAPTURED:
1161 return USBDEVICESTATE_HELD_BY_PROXY;
1162 case VBOXUSBFLT_DEVSTATE_USED_BY_GUEST:
1163 return USBDEVICESTATE_USED_BY_GUEST;
1164 default:
1165 WARN(("unexpected device state(%d) for device(0x%p)", pDevice->enmState, pDevice));
1166 return USBDEVICESTATE_UNSUPPORTED;
1167 }
1168}
1169
1170static void vboxUsbDevToUserInfo(PVBOXUSBFLTCTX pContext, PVBOXUSBFLT_DEVICE pDevice, PUSBSUP_DEVINFO pDevInfo)
1171{
1172#if 0
1173 pDevInfo->usVendorId = pDevice->idVendor;
1174 pDevInfo->usProductId = pDevice->idProduct;
1175 pDevInfo->usRevision = pDevice->bcdDevice;
1176 pDevInfo->enmState = vboxUsbDevGetUserState(pContext, pDevice);
1177
1178 strcpy(pDevInfo->szDrvKeyName, pDevice->szDrvKeyName);
1179 if (pDevInfo->enmState == USBDEVICESTATE_HELD_BY_PROXY
1180 || pDevInfo->enmState == USBDEVICESTATE_USED_BY_GUEST)
1181 {
1182 /* this is the only case where we return the obj name to the client */
1183 strcpy(pDevInfo->szObjName, pDevice->szObjName);
1184 }
1185 pDevInfo->fHighSpeed = pDevice->fHighSpeed;
1186#endif
1187}
1188
1189NTSTATUS VBoxUsbFltGetDevice(PVBOXUSBFLTCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
1190{
1191 Assert(hDevice);
1192
1193 memset (pInfo, 0, sizeof (*pInfo));
1194 VBOXUSBFLT_LOCK_ACQUIRE();
1195 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1196 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1197 pEntry = pEntry->Flink)
1198 {
1199 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1200 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED);
1201 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED);
1202
1203 if (pDevice != hDevice)
1204 continue;
1205
1206 USBDEVICESTATE enmUsrState = vboxUsbDevGetUserState(pContext, pDevice);
1207 pInfo->enmState = enmUsrState;
1208 VBOXUSBFLT_LOCK_RELEASE();
1209 return STATUS_SUCCESS;
1210 }
1211
1212 VBOXUSBFLT_LOCK_RELEASE();
1213
1214 /* this should not occur */
1215 AssertFailed();
1216
1217 return STATUS_INVALID_PARAMETER;
1218}
1219
1220NTSTATUS VBoxUsbFltPdoAdd(PDEVICE_OBJECT pPdo, BOOLEAN *pbFiltered)
1221{
1222 *pbFiltered = FALSE;
1223 PVBOXUSBFLT_DEVICE pDevice;
1224
1225 /* first check if device is in the a already */
1226 VBOXUSBFLT_LOCK_ACQUIRE();
1227 pDevice = vboxUsbFltDevGetLocked(pPdo);
1228 if (pDevice)
1229 {
1230 LOG(("found device (0x%p), state(%d) for PDO(0x%p)", pDevice, pDevice->enmState, pPdo));
1231 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED, ("VBOXUSBFLT_DEVSTATE_ADDED state for device(0x%p)", pDevice));
1232 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED, ("VBOXUSBFLT_DEVSTATE_REMOVED state for device(0x%p)", pDevice));
1233 *pbFiltered = pDevice->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1234 VBOXUSBFLT_LOCK_RELEASE();
1235 return STATUS_SUCCESS;
1236 }
1237 VBOXUSBFLT_LOCK_RELEASE();
1238 pDevice = (PVBOXUSBFLT_DEVICE)VBoxUsbMonMemAllocZ(sizeof (*pDevice));
1239 if (!pDevice)
1240 {
1241 WARN(("VBoxUsbMonMemAllocZ failed"));
1242 return STATUS_NO_MEMORY;
1243 }
1244
1245 pDevice->enmState = VBOXUSBFLT_DEVSTATE_ADDED;
1246 pDevice->cRefs = 1;
1247 NTSTATUS Status = vboxUsbFltDevPopulate(pDevice, pPdo /* , TRUE /* need all props */);
1248 if (!NT_SUCCESS(Status))
1249 {
1250 WARN(("vboxUsbFltDevPopulate failed, Status 0x%x", Status));
1251 VBoxUsbMonMemFree(pDevice);
1252 return Status;
1253 }
1254
1255 uintptr_t uId;
1256 bool fFilter = false;
1257 bool fIsOneShot = false;
1258 PVBOXUSBFLTCTX pCtx;
1259 PVBOXUSBFLT_DEVICE pTmpDev;
1260 VBOXUSBFLT_LOCK_ACQUIRE();
1261 /* (paranoia) re-check the device is still not here */
1262 pTmpDev = vboxUsbFltDevGetLocked(pPdo);
1263 if (pTmpDev)
1264 {
1265 LOG(("second try: found device (0x%p), state(%d) for PDO(0x%p)", pDevice, pDevice->enmState, pPdo));
1266 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED, ("second try: VBOXUSBFLT_DEVSTATE_ADDED state for device(0x%p)", pDevice));
1267 ASSERT_WARN(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED, ("second try: VBOXUSBFLT_DEVSTATE_REMOVED state for device(0x%p)", pDevice));
1268 *pbFiltered = pTmpDev->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1269 VBOXUSBFLT_LOCK_RELEASE();
1270 VBoxUsbMonMemFree(pDevice);
1271 return STATUS_SUCCESS;
1272 }
1273
1274 LOG(("Created Device 0x%p for PDO 0x%p", pDevice, pPdo));
1275
1276 pCtx = vboxUsbFltDevMatchLocked(pDevice, &uId,
1277 true, /* remove a one-shot filter */
1278 &fFilter, &fIsOneShot);
1279 LOG(("Matching Info: Filter (0x%p), pCtx(0x%p), fFilter(%d), fIsOneShot(%d)", uId, pCtx, (int)fFilter, (int)fIsOneShot));
1280 if (fFilter)
1281 {
1282 LOG(("Created Device 0x%p should be filtered", pDevice));
1283 ASSERT_WARN(pCtx, ("zero ctx"));
1284 ASSERT_WARN(uId, ("zero uId"));
1285 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING;
1286 }
1287 else
1288 {
1289 LOG(("Created Device 0x%p should NOT be filtered", pDevice));
1290 ASSERT_WARN(!uId == !pCtx, ("invalid uid(0x%p) - ctx(0x%p) pair", uId, pCtx)); /* either both zero or both not */
1291 pDevice->enmState = VBOXUSBFLT_DEVSTATE_UNCAPTURED;
1292 }
1293
1294 if (pCtx)
1295 vboxUsbFltDevOwnerSetLocked(pDevice, pCtx, fIsOneShot ? 0 : uId, fIsOneShot);
1296
1297 InsertHeadList(&g_VBoxUsbFltGlobals.DeviceList, &pDevice->GlobalLe);
1298
1299 /* do not need to signal anything here -
1300 * going to do that once the proxy device object starts */
1301 VBOXUSBFLT_LOCK_RELEASE();
1302
1303 *pbFiltered = fFilter;
1304
1305 return STATUS_SUCCESS;
1306}
1307
1308NTSTATUS VBoxUsbFltPdoAddCompleted(PDEVICE_OBJECT pPdo)
1309{
1310 VBOXUSBFLT_LOCK_ACQUIRE();
1311 vboxUsbFltSignalChangeLocked();
1312 VBOXUSBFLT_LOCK_RELEASE();
1313 return STATUS_SUCCESS;
1314}
1315
1316BOOLEAN VBoxUsbFltPdoIsFiltered(PDEVICE_OBJECT pPdo)
1317{
1318 VBOXUSBFLT_DEVSTATE enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1319 VBOXUSBFLT_LOCK_ACQUIRE();
1320 PVBOXUSBFLT_DEVICE pDevice = vboxUsbFltDevGetLocked(pPdo);
1321 if (pDevice)
1322 {
1323 enmState = pDevice->enmState;
1324 }
1325 VBOXUSBFLT_LOCK_RELEASE();
1326
1327 return enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1328}
1329
1330NTSTATUS VBoxUsbFltPdoRemove(PDEVICE_OBJECT pPdo)
1331{
1332 PVBOXUSBFLT_DEVICE pDevice;
1333 VBOXUSBFLT_DEVSTATE enmOldState;
1334
1335 VBOXUSBFLT_LOCK_ACQUIRE();
1336 pDevice = vboxUsbFltDevGetLocked(pPdo);
1337 if (pDevice)
1338 {
1339 RemoveEntryList(&pDevice->GlobalLe);
1340 enmOldState = pDevice->enmState;
1341 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1342 if (enmOldState != VBOXUSBFLT_DEVSTATE_REPLUGGING)
1343 {
1344 vboxUsbFltSignalChangeLocked();
1345 }
1346 else
1347 {
1348 /* the device *should* reappear, do signlling on re-appear only
1349 * to avoid extra signaling. still there might be a situation
1350 * when the device will not re-appear if it gets physically removed
1351 * before it re-appears
1352 * @todo: set a timer callback to do a notification from it */
1353 }
1354 }
1355 VBOXUSBFLT_LOCK_RELEASE();
1356 if (pDevice)
1357 vboxUsbFltDevRelease(pDevice);
1358 return STATUS_SUCCESS;
1359}
1360
1361HVBOXUSBFLTDEV VBoxUsbFltProxyStarted(PDEVICE_OBJECT pPdo)
1362{
1363 PVBOXUSBFLT_DEVICE pDevice;
1364 VBOXUSBFLT_LOCK_ACQUIRE();
1365 pDevice = vboxUsbFltDevGetLocked(pPdo);
1366 if (pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING)
1367 {
1368 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURED;
1369 LOG(("The proxy notified proxy start for the captured device 0x%x", pDevice));
1370 vboxUsbFltDevRetain(pDevice);
1371 vboxUsbFltSignalChangeLocked();
1372 }
1373 else
1374 {
1375 WARN(("invalid state, %d", pDevice->enmState));
1376 pDevice = NULL;
1377 }
1378 VBOXUSBFLT_LOCK_RELEASE();
1379 return pDevice;
1380}
1381
1382void VBoxUsbFltProxyStopped(HVBOXUSBFLTDEV hDev)
1383{
1384 PVBOXUSBFLT_DEVICE pDevice = (PVBOXUSBFLT_DEVICE)hDev;
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.

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