VirtualBox

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

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

rework usb

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.6 KB
Line 
1/* $Id: VBoxUsbFlt.cpp 36968 2011-05-05 08:55:16Z 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)
462{
463 if (pDevice->enmState <= VBOXUSBFLT_DEVSTATE_ADDED)
464 {
465 Assert(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING);
466 return false;
467 }
468
469 uintptr_t uId = 0;
470 bool bNeedReplug = false;
471 bool fFilter = false;
472 bool fIsOneShot = false;
473 PVBOXUSBFLTCTX pNewOwner = vboxUsbFltDevMatchLocked(pDevice, &uId,
474 false, /* do not remove a one-shot filter */
475 &fFilter, &fIsOneShot);
476 if (pDevice->pOwner && pDevice->uFltId && pNewOwner != pDevice->pOwner)
477 {
478 /* the device is owned by another context by a valid filter */
479 return false;
480 }
481
482 if (!fFilter)
483 {
484 /* the device should NOT be filtered, check the current state */
485 if (vboxUsbFltDevStateIsNotFiltered(pDevice))
486 {
487 /* no changes */
488 if (fIsOneShot)
489 {
490 /* remove a one-shot filter and keep the original filter data */
491 int tmpRc = VBoxUSBFilterRemove(pNewOwner, uId);
492 AssertRC(tmpRc);
493 }
494 else
495 {
496 vboxUsbFltDevOwnerUpdateLocked(pDevice, pNewOwner, uId, false);
497 }
498 }
499 else
500 {
501 /* the device is currently filtered, while it should not, replug needed */
502 bNeedReplug = true;
503 }
504 }
505 else
506 {
507 /* the device should NOT be filtered, check the current state */
508 Assert(uId);
509 Assert(pNewOwner);
510 if (vboxUsbFltDevStateIsFiltered(pDevice))
511 {
512 /* the device is filtered */
513 if (pNewOwner == pDevice->pOwner)
514 {
515 /* no changes */
516 if (fIsOneShot)
517 {
518 /* remove a one-shot filter and keep the original filter data */
519 int tmpRc = VBoxUSBFilterRemove(pNewOwner, uId);
520 AssertRC(tmpRc);
521 }
522 else
523 {
524 vboxUsbFltDevOwnerUpdateLocked(pDevice, pDevice->pOwner, uId, false);
525 }
526 }
527 else
528 {
529 /* the device needs to be filtered, but the owner changes, replug needed */
530 bNeedReplug = true;
531 }
532 }
533 else
534 {
535 /* the device is currently NOT filtered, while it should, replug needed */
536 bNeedReplug = true;
537 }
538 }
539
540 if (bNeedReplug)
541 {
542 vboxUsbFltDevStateMarkReplugLocked(pDevice);
543 }
544
545 return bNeedReplug;
546}
547
548static void vboxUsbFltReplugList(PLIST_ENTRY pList)
549{
550 PLIST_ENTRY pNext;
551 for (PLIST_ENTRY pEntry = pList->Flink;
552 pEntry != pList;
553 pEntry = pNext)
554 {
555 pNext = pEntry->Flink;
556 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_REPLUGGINGLE(pEntry);
557 Assert(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING
558 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_REMOVED);
559
560 vboxUsbFltPdoReplug(pDevice->Pdo);
561 ObDereferenceObject(pDevice->Pdo);
562 vboxUsbFltDevRelease(pDevice);
563 }
564}
565
566NTSTATUS VBoxUsbFltFilterCheck()
567{
568 NTSTATUS Status;
569 UNICODE_STRING szStandardControllerName[RT_ELEMENTS(lpszStandardControllerName)];
570 KIRQL Irql = KeGetCurrentIrql();
571 Assert(Irql == PASSIVE_LEVEL);
572
573 Log(("==" __FUNCTION__"\n"));
574
575 for (int i=0;i<RT_ELEMENTS(lpszStandardControllerName);i++)
576 {
577 szStandardControllerName[i].Length = 0;
578 szStandardControllerName[i].MaximumLength = 0;
579 szStandardControllerName[i].Buffer = 0;
580
581 RtlInitUnicodeString(&szStandardControllerName[i], lpszStandardControllerName[i]);
582 }
583
584 for (int i = 0; i < 16; i++)
585 {
586 char szHubName[32];
587 WCHAR szwHubName[32];
588 UNICODE_STRING UnicodeName;
589 ANSI_STRING AnsiName;
590 PDEVICE_OBJECT pHubDevObj;
591 PFILE_OBJECT pHubFileObj;
592
593 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
594
595 UnicodeName.Length = 0;
596 UnicodeName.MaximumLength = sizeof (szwHubName);
597 UnicodeName.Buffer = szwHubName;
598
599 RtlInitAnsiString(&AnsiName, szHubName);
600 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
601
602 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
603 if (Status == STATUS_SUCCESS)
604 {
605 Log(("IoGetDeviceObjectPointer for %s returned %p %p\n", szHubName, pHubDevObj, pHubFileObj));
606
607 if (pHubDevObj->DriverObject
608 && pHubDevObj->DriverObject->DriverName.Buffer
609 && pHubDevObj->DriverObject->DriverName.Length
610 )
611 {
612 for (int j = 0; j < RT_ELEMENTS(lpszStandardControllerName); ++j)
613 {
614 if (!RtlCompareUnicodeString(&szStandardControllerName[j], &pHubDevObj->DriverObject->DriverName, TRUE /* case insensitive */))
615 {
616 PDEVICE_RELATIONS pDevRelations = NULL;
617
618#ifdef DEBUG
619 Log(("Associated driver "));
620 vboxUsbDbgPrintUnicodeString(&pHubDevObj->DriverObject->DriverName);
621 Log((" -> related dev obj=0x%p\n", IoGetRelatedDeviceObject(pHubFileObj)));
622#endif
623
624 Status = VBoxUsbMonQueryBusRelations(pHubDevObj, pHubFileObj, &pDevRelations);
625 if (Status == STATUS_SUCCESS && pDevRelations)
626 {
627 ULONG cReplugPdos = pDevRelations->Count;
628 LIST_ENTRY ReplugDevList;
629 InitializeListHead(&ReplugDevList);
630 for (ULONG k = 0; k < pDevRelations->Count; ++k)
631 {
632 Log(("Found existing USB PDO %p\n", pDevRelations->Objects[k]));
633 VBOXUSBFLT_LOCK_ACQUIRE();
634 PVBOXUSBFLT_DEVICE pDevice = vboxUsbFltDevGetLocked(pDevRelations->Objects[k]);
635 if (pDevice)
636 {
637 bool bReplug = vboxUsbFltDevCheckReplugLocked(pDevice);
638 if (bReplug)
639 {
640 InsertHeadList(&ReplugDevList, &pDevice->RepluggingLe);
641 vboxUsbFltDevRetain(pDevice);
642 /* do not dereference object since we will use it later */
643 }
644 else
645 {
646 ObDereferenceObject(pDevRelations->Objects[k]);
647 }
648
649 VBOXUSBFLT_LOCK_RELEASE();
650
651 pDevRelations->Objects[k] = NULL;
652 --cReplugPdos;
653 Assert((uint32_t)cReplugPdos < UINT32_MAX/2);
654 continue;
655 }
656 VBOXUSBFLT_LOCK_RELEASE();
657
658 VBOXUSBFLT_DEVICE Device;
659 Status = vboxUsbFltDevPopulate(&Device, pDevRelations->Objects[k] /*, FALSE /* only need filter properties */);
660 if (NT_SUCCESS(Status))
661 {
662 uintptr_t uId = 0;
663 bool fFilter = false;
664 bool fIsOneShot = false;
665 VBOXUSBFLT_LOCK_ACQUIRE();
666 PVBOXUSBFLTCTX pCtx = vboxUsbFltDevMatchLocked(&Device, &uId,
667 false, /* do not remove a one-shot filter */
668 &fFilter, &fIsOneShot);
669 VBOXUSBFLT_LOCK_RELEASE();
670 if (!fFilter)
671 {
672 /* this device should not be filtered, and it's not */
673 ObDereferenceObject(pDevRelations->Objects[k]);
674 pDevRelations->Objects[k] = NULL;
675 --cReplugPdos;
676 Assert((uint32_t)cReplugPdos < UINT32_MAX/2);
677 continue;
678 }
679
680 /* this device needs to be filtered, but it's not,
681 * leave the PDO in array to issue a replug request for it
682 * later on */
683
684 }
685 }
686
687 if (cReplugPdos)
688 {
689 for (ULONG k = 0; k < pDevRelations->Count; ++k)
690 {
691 if (!pDevRelations->Objects[k])
692 continue;
693
694 Status = vboxUsbFltPdoReplug(pDevRelations->Objects[k]);
695 Assert(Status == STATUS_SUCCESS);
696 ObDereferenceObject(pDevRelations->Objects[k]);
697 if (!--cReplugPdos)
698 break;
699 }
700
701 Assert(!cReplugPdos);
702 }
703
704 vboxUsbFltReplugList(&ReplugDevList);
705
706 ExFreePool(pDevRelations);
707 }
708 }
709 }
710 }
711 ObDereferenceObject(pHubFileObj);
712 }
713 }
714
715 return STATUS_SUCCESS;
716}
717
718NTSTATUS VBoxUsbFltClose(PVBOXUSBFLTCTX pContext)
719{
720 LIST_ENTRY ReplugDevList;
721 InitializeListHead(&ReplugDevList);
722
723 Assert(pContext);
724
725 KIRQL Irql = KeGetCurrentIrql();
726 Assert(Irql == PASSIVE_LEVEL);
727
728 VBOXUSBFLT_LOCK_ACQUIRE();
729 uint32_t cActiveFilters = pContext->cActiveFilters;
730 pContext->bRemoved = TRUE;
731 if (pContext->pChangeEvent)
732 {
733 KeSetEvent(pContext->pChangeEvent,
734 0, /* increment*/
735 FALSE /* wait */);
736 ObDereferenceObject(pContext->pChangeEvent);
737 pContext->pChangeEvent = NULL;
738 }
739 RemoveEntryList(&pContext->ListEntry);
740
741 /* now re-arrange the filters */
742 /* 1. remove filters */
743 VBoxUSBFilterRemoveOwner(pContext);
744
745 /* 2. check if there are devices owned */
746 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
747 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
748 pEntry = pEntry->Flink)
749 {
750 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
751 if (pDevice->pOwner != pContext)
752 continue;
753
754 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED);
755 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED);
756
757 vboxUsbFltDevOwnerClearLocked(pDevice);
758
759 if (vboxUsbFltDevCheckReplugLocked(pDevice))
760 {
761 InsertHeadList(&ReplugDevList, &pDevice->RepluggingLe);
762 /* retain to ensure the device is not removed before we issue a replug */
763 vboxUsbFltDevRetain(pDevice);
764 /* keep the PDO alive */
765 ObReferenceObject(pDevice->Pdo);
766 }
767 }
768 VBOXUSBFLT_LOCK_RELEASE();
769
770 /* this should replug all devices that were either skipped or grabbed due to the context's */
771 vboxUsbFltReplugList(&ReplugDevList);
772
773 return STATUS_SUCCESS;
774}
775
776NTSTATUS VBoxUsbFltCreate(PVBOXUSBFLTCTX pContext)
777{
778 memset(pContext, 0, sizeof (*pContext));
779 pContext->Process = RTProcSelf();
780 VBOXUSBFLT_LOCK_ACQUIRE();
781 InsertHeadList(&g_VBoxUsbFltGlobals.ContextList, &pContext->ListEntry);
782 VBOXUSBFLT_LOCK_RELEASE();
783 return STATUS_SUCCESS;
784}
785
786int VBoxUsbFltAdd(PVBOXUSBFLTCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
787{
788 *pId = 0;
789 /* Log the filter details. */
790 Log((__FUNCTION__": %s %s %s\n",
791 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
792 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
793 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
794#ifdef DEBUG
795 Log(("VBoxUSBClient::addFilter: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
796 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
797 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
798 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
799 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
800 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
801 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
802 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
803 USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
804#endif
805
806 /* We can't get the bus/port numbers. Ignore them while matching. */
807 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false);
808 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_PORT, false);
809
810 uintptr_t uId = 0;
811 VBOXUSBFLT_LOCK_ACQUIRE();
812 /* Add the filter. */
813 int rc = VBoxUSBFilterAdd(pFilter, pContext, &uId);
814 VBOXUSBFLT_LOCK_RELEASE();
815 AssertRC(rc);
816 if (RT_SUCCESS(rc))
817 {
818 Assert(uId);
819#ifdef VBOX_USBMON_WITH_FILTER_AUTOAPPLY
820 VBoxUsbFltFilterCheck();
821#endif
822 }
823 else
824 {
825 Assert(!uId);
826 }
827
828 *pId = uId;
829 return rc;
830}
831
832int VBoxUsbFltRemove(PVBOXUSBFLTCTX pContext, uintptr_t uId)
833{
834 Assert(uId);
835
836 VBOXUSBFLT_LOCK_ACQUIRE();
837 int rc = VBoxUSBFilterRemove(pContext, uId);
838 if (!RT_SUCCESS(rc))
839 {
840 AssertFailed();
841 VBOXUSBFLT_LOCK_RELEASE();
842 return rc;
843 }
844
845 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
846 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
847 pEntry = pEntry->Flink)
848 {
849 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
850 if (pDevice->fIsFilterOneShot)
851 {
852 Assert(!pDevice->uFltId);
853 }
854
855 if (pDevice->uFltId != uId)
856 continue;
857
858 Assert(pDevice->pOwner);
859 Assert(!pDevice->fIsFilterOneShot);
860 pDevice->uFltId = 0;
861 }
862 VBOXUSBFLT_LOCK_RELEASE();
863
864 if (RT_SUCCESS(rc))
865 {
866#ifdef VBOX_USBMON_WITH_FILTER_AUTOAPPLY
867 VBoxUsbFltFilterCheck();
868#endif
869 }
870 return rc;
871}
872
873NTSTATUS VBoxUsbFltSetNotifyEvent(PVBOXUSBFLTCTX pContext, HANDLE hEvent)
874{
875 NTSTATUS Status = STATUS_SUCCESS;
876 PKEVENT pEvent = NULL;
877 PKEVENT pOldEvent = NULL;
878 if (hEvent)
879 {
880 Status = ObReferenceObjectByHandle(hEvent,
881 EVENT_MODIFY_STATE,
882 *ExEventObjectType, UserMode,
883 (PVOID*)&pEvent,
884 NULL);
885 Assert(Status == STATUS_SUCCESS);
886 if (!NT_SUCCESS(Status))
887 return Status;
888 }
889
890 VBOXUSBFLT_LOCK_ACQUIRE();
891 pOldEvent = pContext->pChangeEvent;
892 pContext->pChangeEvent = pEvent;
893 VBOXUSBFLT_LOCK_RELEASE();
894
895 if (pOldEvent)
896 {
897 ObDereferenceObject(pOldEvent);
898 }
899
900 return STATUS_SUCCESS;
901}
902
903static USBDEVICESTATE vboxUsbDevGetUserState(PVBOXUSBFLTCTX pContext, PVBOXUSBFLT_DEVICE pDevice)
904{
905 if (vboxUsbFltDevStateIsNotFiltered(pDevice))
906 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
907
908 /* the device is filtered, or replugging */
909 if (pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING)
910 {
911 Assert(!pDevice->pOwner);
912 Assert(!pDevice->uFltId);
913 AssertFailed();
914 /* no user state for this, we should not return it tu the user */
915 return USBDEVICESTATE_USED_BY_HOST;
916 }
917
918 /* the device is filtered, if owner differs from the context, return as USED_BY_HOST */
919 Assert(pDevice->pOwner);
920 /* the id can be null if a filter is removed */
921// Assert(pDevice->uFltId);
922
923 if (pDevice->pOwner != pContext)
924 return USBDEVICESTATE_USED_BY_HOST;
925
926 switch (pDevice->enmState)
927 {
928 case VBOXUSBFLT_DEVSTATE_UNCAPTURED:
929 case VBOXUSBFLT_DEVSTATE_CAPTURING:
930 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
931 case VBOXUSBFLT_DEVSTATE_CAPTURED:
932 return USBDEVICESTATE_HELD_BY_PROXY;
933 case VBOXUSBFLT_DEVSTATE_USED_BY_GUEST:
934 return USBDEVICESTATE_USED_BY_GUEST;
935 default:
936 AssertFailed();
937 return USBDEVICESTATE_UNSUPPORTED;
938 }
939}
940
941static void vboxUsbDevToUserInfo(PVBOXUSBFLTCTX pContext, PVBOXUSBFLT_DEVICE pDevice, PUSBSUP_DEVINFO pDevInfo)
942{
943#if 0
944 pDevInfo->usVendorId = pDevice->idVendor;
945 pDevInfo->usProductId = pDevice->idProduct;
946 pDevInfo->usRevision = pDevice->bcdDevice;
947 pDevInfo->enmState = vboxUsbDevGetUserState(pContext, pDevice);
948
949 strcpy(pDevInfo->szDrvKeyName, pDevice->szDrvKeyName);
950 if (pDevInfo->enmState == USBDEVICESTATE_HELD_BY_PROXY
951 || pDevInfo->enmState == USBDEVICESTATE_USED_BY_GUEST)
952 {
953 /* this is the only case where we return the obj name to the client */
954 strcpy(pDevInfo->szObjName, pDevice->szObjName);
955 }
956 pDevInfo->fHighSpeed = pDevice->fHighSpeed;
957#endif
958}
959
960NTSTATUS VBoxUsbFltGetDevice(PVBOXUSBFLTCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
961{
962 Assert(hDevice);
963
964 memset (pInfo, 0, sizeof (*pInfo));
965 VBOXUSBFLT_LOCK_ACQUIRE();
966 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
967 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
968 pEntry = pEntry->Flink)
969 {
970 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
971 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED);
972 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED);
973
974 if (pDevice != hDevice)
975 continue;
976
977 USBDEVICESTATE enmUsrState = vboxUsbDevGetUserState(pContext, pDevice);
978 pInfo->enmState = enmUsrState;
979 VBOXUSBFLT_LOCK_RELEASE();
980 return STATUS_SUCCESS;
981 }
982
983 VBOXUSBFLT_LOCK_RELEASE();
984
985 /* this should not occur */
986 AssertFailed();
987
988 return STATUS_INVALID_PARAMETER;
989}
990
991NTSTATUS VBoxUsbFltPdoAdd(PDEVICE_OBJECT pPdo, BOOLEAN *pbFiltered)
992{
993 *pbFiltered = FALSE;
994 PVBOXUSBFLT_DEVICE pDevice;
995
996 /* first check if device is in the a already */
997 VBOXUSBFLT_LOCK_ACQUIRE();
998 pDevice = vboxUsbFltDevGetLocked(pPdo);
999 if (pDevice)
1000 {
1001 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_ADDED);
1002 Assert(pDevice->enmState != VBOXUSBFLT_DEVSTATE_REMOVED);
1003 *pbFiltered = pDevice->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1004 VBOXUSBFLT_LOCK_RELEASE();
1005 return STATUS_SUCCESS;
1006 }
1007 VBOXUSBFLT_LOCK_RELEASE();
1008 pDevice = (PVBOXUSBFLT_DEVICE)VBoxUsbMonMemAllocZ(sizeof (*pDevice));
1009 if (!pDevice)
1010 {
1011 AssertFailed();
1012 return STATUS_NO_MEMORY;
1013 }
1014
1015 pDevice->enmState = VBOXUSBFLT_DEVSTATE_ADDED;
1016 pDevice->cRefs = 1;
1017 NTSTATUS Status = vboxUsbFltDevPopulate(pDevice, pPdo /* , TRUE /* need all props */);
1018 if (!NT_SUCCESS(Status))
1019 {
1020 AssertFailed();
1021 VBoxUsbMonMemFree(pDevice);
1022 return Status;
1023 }
1024
1025 uintptr_t uId;
1026 bool fFilter = false;
1027 bool fIsOneShot = false;
1028 PVBOXUSBFLTCTX pCtx;
1029 PVBOXUSBFLT_DEVICE pTmpDev;
1030 VBOXUSBFLT_LOCK_ACQUIRE();
1031 /* (paranoia) re-check the device is still not here */
1032 pTmpDev = vboxUsbFltDevGetLocked(pPdo);
1033 if (pTmpDev)
1034 {
1035 Assert(pTmpDev->enmState != VBOXUSBFLT_DEVSTATE_ADDED);
1036 Assert(pTmpDev->enmState != VBOXUSBFLT_DEVSTATE_REMOVED);
1037 *pbFiltered = pTmpDev->enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1038 VBOXUSBFLT_LOCK_RELEASE();
1039 VBoxUsbMonMemFree(pDevice);
1040 return STATUS_SUCCESS;
1041 }
1042
1043 pCtx = vboxUsbFltDevMatchLocked(pDevice, &uId,
1044 true, /* remove a one-shot filter */
1045 &fFilter, &fIsOneShot);
1046 if (fFilter)
1047 {
1048 Assert(pCtx);
1049 Assert(uId);
1050 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING;
1051 }
1052 else
1053 {
1054 Assert(!uId == !pCtx); /* either both zero or both not */
1055 pDevice->enmState = VBOXUSBFLT_DEVSTATE_UNCAPTURED;
1056 }
1057
1058 if (pCtx)
1059 vboxUsbFltDevOwnerSetLocked(pDevice, pCtx, fIsOneShot ? 0 : uId, fIsOneShot);
1060
1061 InsertHeadList(&g_VBoxUsbFltGlobals.DeviceList, &pDevice->GlobalLe);
1062
1063 /* do not need to signal anything here -
1064 * going to do that once the proxy device object starts */
1065 VBOXUSBFLT_LOCK_RELEASE();
1066
1067 *pbFiltered = fFilter;
1068
1069 return STATUS_SUCCESS;
1070}
1071
1072NTSTATUS VBoxUsbFltPdoAddCompleted(PDEVICE_OBJECT pPdo)
1073{
1074 VBOXUSBFLT_LOCK_ACQUIRE();
1075 vboxUsbFltSignalChangeLocked();
1076 VBOXUSBFLT_LOCK_RELEASE();
1077 return STATUS_SUCCESS;
1078}
1079
1080BOOLEAN VBoxUsbFltPdoIsFiltered(PDEVICE_OBJECT pPdo)
1081{
1082 VBOXUSBFLT_DEVSTATE enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1083 VBOXUSBFLT_LOCK_ACQUIRE();
1084 PVBOXUSBFLT_DEVICE pDevice = vboxUsbFltDevGetLocked(pPdo);
1085 if (pDevice)
1086 {
1087 enmState = pDevice->enmState;
1088 }
1089 VBOXUSBFLT_LOCK_RELEASE();
1090
1091 return enmState >= VBOXUSBFLT_DEVSTATE_CAPTURING;
1092}
1093
1094NTSTATUS VBoxUsbFltPdoRemove(PDEVICE_OBJECT pPdo)
1095{
1096 PVBOXUSBFLT_DEVICE pDevice;
1097 VBOXUSBFLT_DEVSTATE enmOldState;
1098
1099 VBOXUSBFLT_LOCK_ACQUIRE();
1100 pDevice = vboxUsbFltDevGetLocked(pPdo);
1101 if (pDevice)
1102 {
1103 RemoveEntryList(&pDevice->GlobalLe);
1104 enmOldState = pDevice->enmState;
1105 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1106 if (enmOldState != VBOXUSBFLT_DEVSTATE_REPLUGGING)
1107 {
1108 vboxUsbFltSignalChangeLocked();
1109 }
1110 else
1111 {
1112 /* the device *should* reappear, do signlling on re-appear only
1113 * to avoid extra signaling. still there might be a situation
1114 * when the device will not re-appear if it gets physically removed
1115 * before it re-appears
1116 * @todo: set a timer callback to do a notification from it */
1117 }
1118 }
1119 VBOXUSBFLT_LOCK_RELEASE();
1120 if (pDevice)
1121 vboxUsbFltDevRelease(pDevice);
1122 return STATUS_SUCCESS;
1123}
1124
1125HVBOXUSBFLTDEV VBoxUsbFltProxyStarted(PDEVICE_OBJECT pPdo)
1126{
1127 PVBOXUSBFLT_DEVICE pDevice;
1128 VBOXUSBFLT_LOCK_ACQUIRE();
1129 pDevice = vboxUsbFltDevGetLocked(pPdo);
1130 if (pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING)
1131 {
1132 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURED;
1133 vboxUsbFltDevRetain(pDevice);
1134 vboxUsbFltSignalChangeLocked();
1135 }
1136 else
1137 {
1138 AssertFailed();
1139 pDevice = NULL;
1140 }
1141 VBOXUSBFLT_LOCK_RELEASE();
1142 return pDevice;
1143}
1144
1145void VBoxUsbFltProxyStopped(HVBOXUSBFLTDEV hDev)
1146{
1147 PVBOXUSBFLT_DEVICE pDevice = (PVBOXUSBFLT_DEVICE)hDev;
1148 VBOXUSBFLT_LOCK_ACQUIRE();
1149 if (pDevice->enmState == VBOXUSBFLT_DEVSTATE_CAPTURED
1150 || pDevice->enmState == VBOXUSBFLT_DEVSTATE_USED_BY_GUEST)
1151 {
1152 /* this is due to devie was physically removed */
1153 Log(("The proxy notified progy stop for the captured device 0x%x\n", pDevice));
1154 pDevice->enmState = VBOXUSBFLT_DEVSTATE_CAPTURING;
1155 vboxUsbFltSignalChangeLocked();
1156 }
1157 else
1158 {
1159 Assert(pDevice->enmState == VBOXUSBFLT_DEVSTATE_REPLUGGING);
1160 }
1161 VBOXUSBFLT_LOCK_RELEASE();
1162
1163 vboxUsbFltDevRelease(pDevice);
1164}
1165
1166NTSTATUS VBoxUsbFltInit()
1167{
1168 int rc = VBoxUSBFilterInit();
1169 AssertRC(rc);
1170 if (RT_FAILURE(rc))
1171 return STATUS_UNSUCCESSFUL;
1172
1173 memset(&g_VBoxUsbFltGlobals, 0, sizeof (g_VBoxUsbFltGlobals));
1174 InitializeListHead(&g_VBoxUsbFltGlobals.DeviceList);
1175 InitializeListHead(&g_VBoxUsbFltGlobals.ContextList);
1176 VBOXUSBFLT_LOCK_INIT();
1177 return STATUS_SUCCESS;
1178}
1179
1180NTSTATUS VBoxUsbFltTerm()
1181{
1182 bool bBusy = false;
1183 VBOXUSBFLT_LOCK_ACQUIRE();
1184 do
1185 {
1186 if (!IsListEmpty(&g_VBoxUsbFltGlobals.ContextList))
1187 {
1188 AssertFailed();
1189 bBusy = true;
1190 break;
1191 }
1192
1193 PLIST_ENTRY pNext = NULL;
1194 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1195 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1196 pEntry = pNext)
1197 {
1198 pNext = pEntry->Flink;
1199 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1200 Assert(!pDevice->uFltId);
1201 Assert(!pDevice->pOwner);
1202 if (pDevice->cRefs != 1)
1203 {
1204 AssertFailed();
1205 bBusy = true;
1206 break;
1207 }
1208 }
1209 } while (0);
1210
1211 VBOXUSBFLT_LOCK_RELEASE()
1212
1213 if (bBusy)
1214 {
1215 return STATUS_DEVICE_BUSY;
1216 }
1217
1218 for (PLIST_ENTRY pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink;
1219 pEntry != &g_VBoxUsbFltGlobals.DeviceList;
1220 pEntry = g_VBoxUsbFltGlobals.DeviceList.Flink)
1221 {
1222 RemoveEntryList(pEntry);
1223 PVBOXUSBFLT_DEVICE pDevice = PVBOXUSBFLT_DEVICE_FROM_LE(pEntry);
1224 pDevice->enmState = VBOXUSBFLT_DEVSTATE_REMOVED;
1225 vboxUsbFltDevRelease(pDevice);
1226 }
1227 VBOXUSBFLT_LOCK_TERM();
1228
1229 VBoxUSBFilterTerm();
1230
1231 return STATUS_SUCCESS;
1232}
1233
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