VBoxUsbMon.cpp revision 6cb6e43f3a668826e9b9d00102f7dee1299589e7
/* $Id$ */
/** @file
* VBox USB Monitor
*/
/*
* Copyright (C) 2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "VBoxUsbMon.h"
#include "../cmn/VBoxUsbIdc.h"
#include <excpt.h>
#include <stdio.h>
/*
* Note: Must match the VID & PID in the USB driver .inf file!!
*/
/*
BusQueryDeviceID USB\Vid_80EE&Pid_CAFE
BusQueryInstanceID 2
BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE&Rev_0100
BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE
BusQueryCompatibleIDs USB\Class_ff&SubClass_00&Prot_00
BusQueryCompatibleIDs USB\Class_ff&SubClass_00
BusQueryCompatibleIDs USB\Class_ff
*/
#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
#define szBusQueryHardwareIDs L"USB\\Vid_80EE&Pid_CAFE&Rev_0100\0USB\\Vid_80EE&Pid_CAFE\0\0"
#define szBusQueryCompatibleIDs L"USB\\Class_ff&SubClass_00&Prot_00\0USB\\Class_ff&SubClass_00\0USB\\Class_ff\0\0"
#define szDeviceTextDescription L"VirtualBox USB"
typedef struct VBOXUSBMONINS
{
void * pvDummy;
typedef struct VBOXUSBMONCTX
{
typedef struct VBOXUSBHUB_PNPHOOK
{
typedef struct VBOXUSBHUB_PNPHOOK_COMPLETION
{
typedef struct VBOXUSBMONGLOBALS
{
static VBOXUSBMONGLOBALS g_VBoxUsbMonGlobals;
#define VBOXUSBMON_MEMTAG 'MUBV'
{
return pvMem;
}
{
if (pvMem)
{
}
return pvMem;
}
{
}
#define VBOXUSBDBG_STRCASE(_t) \
#define VBOXUSBDBG_STRCASE_UNKNOWN(_v) \
{
switch (uMn)
{
}
}
{
{
}
}
/**
* Send IRP_MN_QUERY_DEVICE_RELATIONS
*
* @returns NT Status
* @param pDevObj USB device pointer
* @param pFileObj Valid file object pointer
* @param pDevRelations Pointer to DEVICE_RELATIONS pointer (out)
*/
NTSTATUS VBoxUsbMonQueryBusRelations(PDEVICE_OBJECT pDevObj, PFILE_OBJECT pFileObj, PDEVICE_RELATIONS *pDevRelations)
{
*pDevRelations = NULL;
if (!pIrp)
{
AssertMsgFailed(("IoBuildDeviceIoControlRequest failed!!\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
if (Status == STATUS_PENDING)
{
Log(("IoCallDriver returned STATUS_PENDING!!\n"));
}
if (Status == STATUS_SUCCESS)
{
{
*pDevRelations = pRel;
}
else
}
return Status;
}
{
szStandardHubName.Length = 0;
szStandardHubName.Buffer = 0;
Log(("Search USB hub\n"));
for (int i = 0; i < 16; i++)
{
char szHubName[32];
UnicodeName.Length = 0;
if (Status == STATUS_SUCCESS)
{
if (Status == STATUS_SUCCESS)
{
if (pHubDevObj->DriverObject
&& !RtlCompareUnicodeString(&szStandardHubName, &pHubDevObj->DriverObject->DriverName, TRUE /* case insensitive */))
{
#if 0
Log(("Associated driver"));
#endif
break;
}
}
else
{
AssertFailed();
}
}
else
{
AssertFailed();
}
}
return pDrvObj;
}
/* NOTE: the stack location data is not the "actual" IRP stack location,
* but a copy being preserved on the IRP way down.
* See the note in VBoxUsbPnPCompletion for detail */
static NTSTATUS vboxUsbMonHandlePnPIoctl(PDEVICE_OBJECT pDevObj, PIO_STACK_LOCATION pSl, PIO_STATUS_BLOCK pIoStatus)
{
switch(pSl->MinorFunction)
{
case IRP_MN_QUERY_DEVICE_TEXT:
{
{
{
/* IRQL should be always passive here */
{
break;
case DeviceTextDescription:
{
if (!pId)
{
AssertFailed();
break;
}
}
break;
default:
break;
}
}
else
}
break;
}
case IRP_MN_QUERY_ID:
{
{
#ifdef DEBUG
#endif
{
/* IRQL should be always passive here */
{
case BusQueryInstanceID:
break;
case BusQueryDeviceID:
{
if (!pId)
{
AssertFailed();
break;
}
{
break;
}
break;
}
case BusQueryHardwareIDs:
{
#ifdef DEBUG
while(*pId) //MULTI_SZ
{
pId++;
}
#endif
if (!pId)
{
AssertFailed();
break;
}
{
break;
}
#ifdef DEBUG
while(*pTmp) //MULTI_SZ
{
pTmp++;
}
#endif
break;
}
case BusQueryCompatibleIDs:
#ifdef DEBUG
while(*pId) //MULTI_SZ
{
pId++;
}
#endif
{
if (!pId)
{
AssertFailed();
break;
}
#ifdef DEBUG
while(*pTmp) //MULTI_SZ
{
pTmp++;
}
#endif
}
break;
}
}
else
}
break;
}
#ifdef DEBUG
{
{
case BusRelations:
{
Log(("BusRelations\n"));
{
{
{
}
}
else
}
break;
}
case TargetDeviceRelation:
Log(("TargetDeviceRelation\n"));
break;
case RemovalRelations:
Log(("RemovalRelations\n"));
break;
case EjectionRelations:
Log(("EjectionRelations\n"));
break;
}
break;
}
{
{
{
}
else
}
break;
}
default:
break;
#endif
} /*switch */
}
{
/* NOTE: despite a regular IRP processing the stack location in our completion
* differs from those of the PnP hook since the hook is invoked in the "context" of the calle,
* while the completion is in the "coller" context in terms of IRP,
* so the completion stack location is one level "up" here.
*
* Moreover we CAN NOT access irp stack location in the completion because we might not have one at all
* in case the hooked driver is at the top of the irp call stack
*
* This is why we use the stack location we saved on IRP way down.
* */
/* NOTE: we can not rely on pDevObj passed in IoCompletion since it may be zero
* in case IRP was created with extra stack locations and the caller did not initialize
* the IO_STACK_LOCATION::DeviceObject */
// Assert(!pDevObj || pDevObj == pRealDevObj);
// Assert(pSl->DeviceObject == pDevObj);
switch(pSl->MinorFunction)
{
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_QUERY_ID:
#ifdef DEBUG
#endif
{
}
else
{
}
break;
case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_REMOVE_DEVICE:
{
}
else
{
AssertFailed();
}
break;
/* These two IRPs are received when the PnP subsystem has determined the id of the newly arrived device */
/* IRP_MN_START_DEVICE only arrives if it's a USB device of a known class or with a present host driver */
case IRP_MN_QUERY_RESOURCES:
{
}
else
{
AssertFailed();
}
break;
default:
break;
}
Log(("<==PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x), Sl PDO(0x%p), Compl PDO(0x%p)\n",
#ifdef DEBUG_misha
#endif
NTSTATUS Status = VBoxUsbHookRequestComplete(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp, pRequest);
#ifdef DEBUG_misha
{
}
#endif
return Status;
}
/**
* Device PnP hook
*
* @param pDevObj Device object.
* @param pIrp Request packet.
*/
{
{
}
PVBOXUSBHUB_PNPHOOK_COMPLETION pCompletion = (PVBOXUSBHUB_PNPHOOK_COMPLETION)VBoxUsbMonMemAlloc(sizeof (*pCompletion));
if (!pCompletion)
{
AssertFailed();
return STATUS_INSUFFICIENT_RESOURCES;
}
Log(("==>PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x)\n", vboxUsbDbgStrPnPMn(IoGetCurrentIrpStackLocation(pIrp)->MinorFunction), pDevObj, pIrp, pIrp->IoStatus.Status));
return VBoxUsbHookRequestPassDownHookCompletion(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
}
static NTSTATUS vboxUsbMonHookCheckInit()
{
static bool fIsHookInited = false;
if (fIsHookInited)
return STATUS_SUCCESS;
if (pDrvObj)
{
fIsHookInited = true;
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
static NTSTATUS vboxUsbMonHookInstall()
{
#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
return STATUS_SUCCESS;
#else
#endif
}
static NTSTATUS vboxUsbMonHookUninstall()
{
#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
return STATUS_SUCCESS;
#else
#endif
}
static NTSTATUS vboxUsbMonCheckTermStuff()
{
FALSE, /* BOOLEAN Alertable */
NULL /* IN PLARGE_INTEGER Timeout */
);
if (Status == STATUS_SUCCESS)
{
do
{
if (--g_VBoxUsbMonGlobals.cOpens)
break;
if (NT_SUCCESS(Status))
{
Status = VBoxUsbFltTerm();
if (NT_SUCCESS(Status))
{
break;
}
else
{
AssertFailed();
}
}
else
{
AssertFailed();
}
} while (0);
}
return Status;
}
static NTSTATUS vboxUsbMonCheckInitStuff()
{
FALSE, /* BOOLEAN Alertable */
NULL /* IN PLARGE_INTEGER Timeout */
);
if (Status == STATUS_SUCCESS)
{
do
{
if (g_VBoxUsbMonGlobals.cOpens++)
break;
Status = VBoxUsbFltInit();
if (NT_SUCCESS(Status))
{
if (NT_SUCCESS(Status))
{
break;
}
else
{
AssertFailed();
}
}
else
{
AssertFailed();
}
} while (0);
}
return Status;
}
{
if (pFileCtx)
{
if (Status == STATUS_SUCCESS)
{
if (Status == STATUS_SUCCESS)
{
return STATUS_SUCCESS;
}
else
{
AssertFailed();
}
}
else
{
AssertFailed();
}
}
else
{
AssertFailed();
}
return Status;
}
{
if (Status == STATUS_SUCCESS)
{
/* ignore the failure */
}
return Status;
}
{
return Status;
}
{
Log(("VBoxUSBMonCreate\n"));
{
return STATUS_NOT_A_DIRECTORY;
}
if (Status == STATUS_SUCCESS)
{
}
return Status;
}
{
return rc;
}
{
#ifdef VBOXUSBMON_DBG_NO_FILTERS
++idDummy;
return VINF_SUCCESS;
#else
return rc;
#endif
}
{
#ifdef VBOXUSBMON_DBG_NO_FILTERS
return VINF_SUCCESS;
#else
return rc;
#endif
}
{
return Status;
}
static NTSTATUS VBoxUsbMonGetDevice(PVBOXUSBMONCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
{
return Status;
}
static NTSTATUS vboxUsbMonIoctlDispatch(PVBOXUSBMONCTX pContext, ULONG Ctl, PVOID pvBuffer, ULONG cbInBuffer, ULONG cbOutBuffer, ULONG_PTR* pInfo)
{
switch (Ctl)
{
{
Log(("SUPUSBFLT_IOCTL_GET_VERSION\n"));
{
AssertMsgFailed(("SUPUSBFLT_IOCTL_GET_VERSION: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
break;
}
break;
}
{
int rc;
{
AssertMsgFailed(("SUPUSBFLT_IOCTL_ADD_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
break;
}
break;
}
{
{
AssertMsgFailed(("SUPUSBFLT_IOCTL_REMOVE_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
break;
}
if (cbOutBuffer)
{
/* we've validated that already */
}
break;
}
{
{
AssertMsgFailed(("SUPUSBFLT_IOCTL_RUN_FILTERS: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
cbInBuffer, 0, cbOutBuffer, 0));
break;
}
Log(("SUPUSBFLT_IOCTL_RUN_FILTERS \n"));
break;
}
{
{
AssertMsgFailed(("SUPUSBFLT_IOCTL_GET_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected >= %d.\n",
break;
}
if (NT_SUCCESS(Status))
{
}
else
{
AssertFailed();
}
break;
}
{
{
AssertMsgFailed(("SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
break;
}
break;
}
default:
break;
}
return Status;
}
{
if (NT_SUCCESS(Status))
{
&Info);
}
return Status;
}
{
*pInfo = 0;
switch (Ctl)
{
{
Log(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION\n"));
if (!pvBuffer)
{
AssertMsgFailed(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION: Buffer is NULL\n"));
break;
}
break;
}
{
Log(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP\n"));
if (!pvBuffer)
{
AssertMsgFailed(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION: Buffer is NULL\n"));
break;
}
break;
}
{
Log(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN\n"));
if (!pvBuffer)
{
AssertMsgFailed(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN: Buffer is NULL\n"));
break;
}
break;
}
default:
{
AssertFailed();
break;
}
}
return Status;
}
{
if (NT_SUCCESS(Status))
{
&Info);
}
return Status;
}
/**
* Unload the driver.
*
* @param pDrvObj Driver object.
*/
{
/* cleanup the logger */
if (pLogger)
{
}
if (pLogger)
{
}
}
/**
* Driver entry point.
*
* @returns appropriate status code.
* @param pDrvObj Pointer to driver object.
* @param pRegPath Registry base path.
*/
{
#ifdef DEBUG_misha
RTLogGroupSettings(0, "+default.e.l.f.l2.l3");;
#endif
Log(("VBoxUSBMon::DriverEntry\n"));
/* create the device */
if (NT_SUCCESS(Status))
{
Status = IoCreateDevice(pDrvObj, sizeof (VBOXUSBMONINS), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
if (NT_SUCCESS(Status))
{
if (NT_SUCCESS(Status))
{
Log(("VBoxUSBMon::DriverEntry returning STATUS_SUCCESS\n"));
return STATUS_SUCCESS;
}
}
}
return Status;
}