VirtualBox

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

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

usb: fix issue with uncompleting IRP on device enumeration

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