/**
 * USBA driver election callback.
 *
 * @returns USB_SUCCESS if we want to capture the device, USB_FAILURE otherwise.
 * @param   pDevDesc        The parsed device descriptor (does not include subconfigs).
 * @param   pDevStrings     Device strings: Manufacturer, Product, Serial Number.
 * @param   pszDevicePath   The physical path of the device being attached.
 * @param   Bus             The Bus number on which the device is on.
 * @param   Port            The Port number on the bus.
 * @param   ppszDrv         The name of the driver we wish to capture the device with.
 * @param   pvReserved      Reserved for future use.
 */
int VBoxUSBMonSolarisElectDriver(usb_dev_descr_t *pDevDesc, usb_dev_str_t *pDevStrings, char *pszDevicePath, int Bus, int Port,
                                char **ppszDrv, void *pvReserved)
{
    LogFunc((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver pDevDesc=%p pDevStrings=%p pszDevicePath=%s Bus=%d Port=%d\n", pDevDesc,
            pDevStrings, pszDevicePath, Bus, Port));

    AssertPtrReturn(pDevDesc, USB_FAILURE);
    AssertPtrReturn(pDevStrings, USB_FAILURE);

    /*
     * Create a filter from the device being attached.
     */
    USBFILTER Filter;
    USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_VENDOR_ID, pDevDesc->idVendor, true);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_PRODUCT_ID, pDevDesc->idProduct, true);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_REV, pDevDesc->bcdDevice, true);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_CLASS, pDevDesc->bDeviceClass, true);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pDevDesc->bDeviceSubClass, true);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pDevDesc->bDeviceProtocol, true);
    USBFilterSetNumExact(&Filter, USBFILTERIDX_BUS, 0x0 /* Bus */, true); /* Use 0x0 as userland initFilterFromDevice function in Main: see comment on "SetMustBePresent" below */
    USBFilterSetNumExact(&Filter, USBFILTERIDX_PORT, Port, true);
    USBFilterSetStringExact(&Filter, USBFILTERIDX_MANUFACTURER_STR, pDevStrings->usb_mfg, true);
    USBFilterSetStringExact(&Filter, USBFILTERIDX_PRODUCT_STR, pDevStrings->usb_product, true);
    USBFilterSetStringExact(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR, pDevStrings->usb_serialno, true);

    /* This doesn't work like it should (USBFilterMatch fails on matching field (6) i.e. Bus despite this. Investigate later. */
    USBFilterSetMustBePresent(&Filter, USBFILTERIDX_BUS, false /* fMustBePresent */);

    Log((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
              USBFilterGetNum(&Filter, USBFILTERIDX_VENDOR_ID),
              USBFilterGetNum(&Filter, USBFILTERIDX_PRODUCT_ID),
              USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_REV),
              USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_CLASS),
              USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS),
              USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL),
              USBFilterGetNum(&Filter, USBFILTERIDX_BUS),
              USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
    Log((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver: Manufacturer=%s Product=%s Serial=%s\n",
              USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR)  ? USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR)  : "<null>",
              USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR)       ? USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR)       : "<null>",
              USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));

    /*
     * Run through user filters and try to see if it has a match.
     */
    uintptr_t uId = 0;
    RTPROCESS Owner = VBoxUSBFilterMatch(&Filter, &uId);
    USBFilterDelete(&Filter);
    if (Owner == NIL_RTPROCESS)
    {
        Log((DEVICE_NAME ":No matching filters, device %#x:%#x uninteresting.\n", pDevDesc->idVendor, pDevDesc->idProduct));
        return USB_FAILURE;
    }

    *ppszDrv = ddi_strdup(VBOXUSB_DRIVER_NAME, KM_SLEEP);
    LogRel((DEVICE_NAME ": Capturing %s %#x:%#x:%s\n", pDevStrings->usb_product ? pDevStrings->usb_product : "<Unnamed USB device>",
                    pDevDesc->idVendor, pDevDesc->idProduct, pszDevicePath));
    return USB_SUCCESS;
}
Esempio n. 2
0
int USBProxyServiceDarwin::releaseDevice(HostUSBDevice *aDevice)
{
    /*
     * Check preconditions.
     */
    AssertReturn(aDevice, VERR_GENERAL_FAILURE);
    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);

    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str()));

    Assert(aDevice->getUnistate() == kHostUSBDeviceState_ReleasingToHost);

#ifndef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
    /*
     * Fake it.
     */
    ASMAtomicWriteBool(&mFakeAsync, true);
    devLock.release();
    interruptWait();
    return VINF_SUCCESS;

#else
    /*
     * Create a one-shot ignore filter for the device
     * and trigger a re-enumeration of it.
     */
    USBFILTER Filter;
    USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_IGNORE);
    initFilterFromDevice(&Filter, aDevice);
    Log(("USBFILTERIDX_PORT=%#x\n", USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
    Log(("USBFILTERIDX_BUS=%#x\n", USBFilterGetNum(&Filter, USBFILTERIDX_BUS)));

    void *pvId = USBLibAddFilter(&Filter);
    if (!pvId)
        return VERR_GENERAL_FAILURE;

    int rc = DarwinReEnumerateUSBDevice(aDevice->mUsb);
    if (RT_SUCCESS(rc))
        aDevice->mOneShotId = pvId;
    else
    {
        USBLibRemoveFilter(pvId);
        pvId = NULL;
    }
    LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
    return rc;
#endif
}
int USBProxyServiceWindows::releaseDevice(HostUSBDevice *aDevice)
{
    /*
     * Check preconditions.
     */
    AssertReturn(aDevice, VERR_GENERAL_FAILURE);
    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);

    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
    LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str()));

    Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_ReleasingToHost);

    /*
     * Create a one-shot ignore filter for the device
     * and trigger a re-enumeration of it.
     */
    USBFILTER Filter;
    USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_IGNORE);
    initFilterFromDevice(&Filter, aDevice);
    Log(("USBFILTERIDX_PORT=%#x\n", USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
    Log(("USBFILTERIDX_BUS=%#x\n", USBFilterGetNum(&Filter, USBFILTERIDX_BUS)));

    void *pvId = USBLibAddFilter(&Filter);
    if (!pvId)
    {
        AssertMsgFailed(("Add one-shot Filter failed\n"));
        return VERR_GENERAL_FAILURE;
    }

    int rc = USBLibRunFilters();
    if (!RT_SUCCESS(rc))
    {
        AssertMsgFailed(("Run Filters failed\n"));
        USBLibRemoveFilter(pvId);
        return rc;
    }


    return VINF_SUCCESS;
}
/**
 *  Converts a USBFilter field into a string.
 *
 *  (This function is also used by HostUSBDeviceFilter.)
 *
 *  @param  aFilter     The filter.
 *  @param  aIdx        The field index.
 *  @param  aStr        The output string.
 */
static void i_usbFilterFieldToString(PCUSBFILTER aFilter, USBFILTERIDX aIdx, Utf8Str &rstrOut)
{
    const USBFILTERMATCH matchingMethod = USBFilterGetMatchingMethod(aFilter, aIdx);
    Assert(matchingMethod != USBFILTERMATCH_INVALID);

    if (USBFilterIsMethodNumeric(matchingMethod))
    {
        int value = USBFilterGetNum(aFilter, aIdx);
        Assert(value >= 0 && value <= 0xffff);

        rstrOut = Utf8StrFmt("%04RX16", (uint16_t)value);
    }
    else if (USBFilterIsMethodString(matchingMethod))
        rstrOut = USBFilterGetString(aFilter, aIdx);
    else
        rstrOut.setNull();
}
/**
 * IOCtl processor for user to kernel and kernel to kernel communication.
 *
 * @returns  VBox status code.
 *
 * @param   iFunction           The requested function.
 * @param   pvState             Opaque pointer to driver state used for getting ring-3 process (Id).
 * @param   pvData              The input/output data buffer. Can be NULL depending on the function.
 * @param   cbData              The max size of the data buffer.
 * @param   pcbDataReturned     Where to store the amount of returned data. Can be NULL.
 */
static int vboxUSBMonSolarisProcessIOCtl(int iFunction, void *pvState, void *pvData, size_t cbData, size_t *pcbReturnedData)
{
    LogFunc((DEVICE_NAME ":solarisUSBProcessIOCtl iFunction=%d pvBuf=%p cbBuf=%zu\n", iFunction, pvData, cbData));

    AssertPtrReturn(pvState, VERR_INVALID_POINTER);
    vboxusbmon_state_t *pState = (vboxusbmon_state_t *)pvState;
    int rc;

#define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
    do { \
        if (cbData < (cbMin)) \
        { \
            LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
                 cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
            return VERR_BUFFER_OVERFLOW; \
        } \
        if ((cbMin) != 0 && !VALID_PTR(pvData)) \
        { \
            LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": Invalid pointer %p\n", pvData)); \
            return VERR_INVALID_POINTER; \
        } \
    } while (0)

    switch (iFunction)
    {
        case VBOXUSBMON_IOCTL_ADD_FILTER:
        {
            CHECKRET_MIN_SIZE("ADD_FILTER", sizeof(VBOXUSBREQ_ADD_FILTER));

            VBOXUSBREQ_ADD_FILTER *pReq = (VBOXUSBREQ_ADD_FILTER *)pvData;
            PUSBFILTER pFilter = (PUSBFILTER)&pReq->Filter;

            Log(("vboxUSBMonSolarisProcessIOCtl: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
                      USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
                      USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
                      USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
                      USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
                      USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
                      USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
                      USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
                      USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
            Log(("vboxUSBMonSolarisProcessIOCtl: Manufacturer=%s Product=%s Serial=%s\n",
                      USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR)  ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR)  : "<null>",
                      USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR)       ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR)       : "<null>",
                      USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));

            rc = USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false /* fMustBePresent */);      AssertRC(rc);

            rc = VBoxUSBFilterAdd(pFilter, pState->Process, &pReq->uId);
            *pcbReturnedData = cbData;
            Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: ADD_FILTER (Process:%d) returned %d\n", pState->Process, rc));
            break;
        }

        case VBOXUSBMON_IOCTL_REMOVE_FILTER:
        {
            CHECKRET_MIN_SIZE("REMOVE_FILTER", sizeof(VBOXUSBREQ_REMOVE_FILTER));

            VBOXUSBREQ_REMOVE_FILTER *pReq = (VBOXUSBREQ_REMOVE_FILTER *)pvData;
            rc = VBoxUSBFilterRemove(pState->Process, (uintptr_t)pReq->uId);
            *pcbReturnedData = 0;
            Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: REMOVE_FILTER (Process:%d) returned %d\n", pState->Process, rc));
            break;
        }

        case VBOXUSBMON_IOCTL_RESET_DEVICE:
        {
            CHECKRET_MIN_SIZE("RESET_DEVICE", sizeof(VBOXUSBREQ_RESET_DEVICE));

            VBOXUSBREQ_RESET_DEVICE *pReq = (VBOXUSBREQ_RESET_DEVICE *)pvData;
            rc = vboxUSBMonSolarisResetDevice(pReq->szDevicePath, pReq->fReattach);
            *pcbReturnedData = 0;
            Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: RESET_DEVICE (Process:%d) returned %d\n", pState->Process, rc));
            break;
        }

        case VBOXUSBMON_IOCTL_CLIENT_INFO:
        {
            CHECKRET_MIN_SIZE("CLIENT_INFO", sizeof(VBOXUSBREQ_CLIENT_INFO));

            VBOXUSBREQ_CLIENT_INFO *pReq = (VBOXUSBREQ_CLIENT_INFO *)pvData;
            rc = vboxUSBMonSolarisClientInfo(pState, pReq);
            *pcbReturnedData = cbData;
            Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: CLIENT_INFO (Process:%d) returned %d\n", pState->Process, rc));
            break;
        }

        case VBOXUSBMON_IOCTL_GET_VERSION:
        {
            CHECKRET_MIN_SIZE("GET_VERSION", sizeof(VBOXUSBREQ_GET_VERSION));

            PVBOXUSBREQ_GET_VERSION pGetVersionReq = (PVBOXUSBREQ_GET_VERSION)pvData;
            pGetVersionReq->u32Major = VBOXUSBMON_VERSION_MAJOR;
            pGetVersionReq->u32Minor = VBOXUSBMON_VERSION_MINOR;
            *pcbReturnedData = sizeof(VBOXUSBREQ_GET_VERSION);
            rc = VINF_SUCCESS;
            Log((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: GET_VERSION returned %d\n", rc));
            break;
        }

        default:
        {
            LogRel((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: Unknown request (Process:%d) %#x\n", pState->Process, iFunction));
            rc = VERR_NOT_SUPPORTED;
            break;
        }
    }
    return rc;
}
Esempio n. 6
0
int main()
{
    unsigned cErrors = 0;
    RTR3InitExeNoArguments(0);

    /*
     * Basic property setting and simple matching.
     */
    USBFILTER Flt1;
    USBFilterInit(&Flt1, USBFILTERTYPE_CAPTURE);
    /* numbers */
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_VENDOR_ID, 0x1111, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_PRODUCT_ID, 0x2222, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_DEVICE, 0, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_DEVICE_CLASS, 0, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_DEVICE_SUB_CLASS, 0, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_DEVICE_PROTOCOL, 0xff, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_BUS, 1, true));
    TST_CHECK_RC(USBFilterSetIgnore(&Flt1, USBFILTERIDX_BUS));
    TST_CHECK_RC(USBFilterSetPresentOnly(&Flt1, USBFILTERIDX_BUS));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_BUS, 1, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_BUS, 1, false));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_PORT, 1, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_PORT, 1, false));
    TST_CHECK_RC(USBFilterSetIgnore(&Flt1, USBFILTERIDX_PORT));
    /* strings */
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR, "foobar", true, false ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR, "foobar", true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString128, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString128, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString128, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString128, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString128, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_PRODUCT_STR,       "barbar", true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_PRODUCT_STR,       g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_PRODUCT_STR,       g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_SERIAL_NUMBER_STR, g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_SERIAL_NUMBER_STR, g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_SERIAL_NUMBER_STR, g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_SERIAL_NUMBER_STR, g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_SERIAL_NUMBER_STR, g_szString64, true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_MANUFACTURER_STR,  "vendor", true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_PRODUCT_STR,       "product", true, false  ));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_SERIAL_NUMBER_STR, "serial", true, false  ));

    /* cloning */
    USBFILTER Dev;
    USBFilterClone(&Dev, &Flt1);

    TST_CHECK_EXPR(USBFilterIsIdentical(&Dev, &Flt1));
    TST_CHECK_EXPR(USBFilterMatch(&Dev, &Flt1));

    USBFilterDelete(&Flt1);
    USBFilterDelete(&Dev);

    /* make a sample device */
    USBFilterInit(&Dev, USBFILTERTYPE_CAPTURE);
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_VENDOR_ID,         0x1111, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_PRODUCT_ID,        0x2222, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_DEVICE,            0, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_DEVICE_CLASS,      0, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_DEVICE_SUB_CLASS,  0, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_DEVICE_PROTOCOL,   0xff, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_BUS,               1, true));
    TST_CHECK_RC(USBFilterSetNumExact(&Dev,     USBFILTERIDX_PORT,              2, true));
    TST_CHECK_RC(USBFilterSetStringExact(&Dev,  USBFILTERIDX_MANUFACTURER_STR,  "vendor", true, false ));
    TST_CHECK_RC(USBFilterSetStringExact(&Dev,  USBFILTERIDX_PRODUCT_STR,       "product", true, false ));
    TST_CHECK_RC(USBFilterSetStringExact(&Dev,  USBFILTERIDX_SERIAL_NUMBER_STR, "serial", true, false ));

    /* do some basic matching tests */
    USBFilterInit(&Flt1, USBFILTERTYPE_CAPTURE);
    TST_CHECK_EXPR(!USBFilterHasAnySubstatialCriteria(&Flt1));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev) /* 100% ignore filter */);

    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_PORT, 3, true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_PORT, 2, true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_BUS, 2, true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExact(&Flt1, USBFILTERIDX_BUS, 1, true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_PRODUCT_STR, "no match", true, false ));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringExact(&Flt1, USBFILTERIDX_PRODUCT_STR, "product", true, false ));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    /* string patterns */
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "p*", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "*product", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "product*", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "pro*t", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "pro*uct", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "pro*uct", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "pro*duct", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "pro*x", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "*product*", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "*oduct*", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "*produc*", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "?r??u*?t", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "?r??u*?*?*?***??t", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "?r??u*?*?*?***??", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "p*d*t", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetStringPattern(&Flt1, USBFILTERIDX_PRODUCT_STR, "p*x*t", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetIgnore(&Flt1, USBFILTERIDX_PRODUCT_STR));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    /* numeric patterns */
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x1111", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0X1111", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "4369", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "010421", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x1111-0x1111", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "4369-4369", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "010421-010421", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x1110-0x1112", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "4360-4370", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "010420-010422", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x1112-0x1110", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x0-0x1f", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0-19", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0-017", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x0-0xffff", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0-65535", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0-177777", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x0-0XABCD", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x0EF-0XABCD", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0X0ef-0Xabcd", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "42|1|0x1111", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "42|0x1111|1", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x1111|42|1", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x1112|42|1", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));

    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "39-59|0x256-0x101f|0xfffff-0xf000|0x1000-0x2000", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "0x000256-0x0101f|0xf000-0xfffff|0x000008000-0x2000|39-59", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "| | \t \t\t| 0x256 - 0x101f   | 0xf000 - 0xfeff\t| 0x1000 -\t0x6000 | 1- 0512", true));
    TST_CHECK_EXPR(USBFilterMatch(&Flt1, &Dev));
    TST_CHECK_RC(USBFilterSetNumExpression(&Flt1, USBFILTERIDX_VENDOR_ID, "| | \t \t\t| 0x256 - 0x101f   | 0xf000 - 0xfeff\t| 0x1112 -\t0x6000 | 1- 0512", true));
    TST_CHECK_EXPR(!USBFilterMatch(&Flt1, &Dev));


    USBFilterDelete(&Flt1);

    /*
     * string overflow
     */
    struct
    {
        uint64_t  u64Pre;
        USBFILTER Flt;
        uint64_t  u64Post;
    } sOf;
    sOf.u64Pre = sOf.u64Post = UINT64_C(0x1234567887654321);

    USBFilterInit(&sOf.Flt, USBFILTERTYPE_CAPTURE);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));

    AssertCompileMemberSize(USBFILTER, achStrTab, 256);
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   &g_szString256[0],  true, false  ) == VERR_BUFFER_OVERFLOW);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   &g_szString256[1],  true, false  ) == VERR_BUFFER_OVERFLOW);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   &g_szString256[2],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   &g_szString256[3],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    /* 0 + 1 */
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   "",                 true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_PRODUCT_STR,         &g_szString256[2],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_PRODUCT_STR,         &g_szString256[1],  true, false  ) == VERR_BUFFER_OVERFLOW);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    /* 0 + 2 */
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_PRODUCT_STR,         &g_szString128[2],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   &g_szString128[1],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    /* 3 */
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_SERIAL_NUMBER_STR,   &g_szString64[0],   true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_PRODUCT_STR,         &g_szString64[0],   true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_MANUFACTURER_STR,    &g_szString128[4],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_MANUFACTURER_STR,    &g_szString128[4],  true, false  ) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetStringExact(&sOf.Flt, USBFILTERIDX_MANUFACTURER_STR,    &g_szString128[3],  true, false  ) == VERR_BUFFER_OVERFLOW);
    TST_CHECK_EXPR(sOf.u64Pre == UINT64_C(0x1234567887654321)); TST_CHECK_EXPR(sOf.u64Post == UINT64_C(0x1234567887654321));

    /*
     * Check for a string replacement bug.
     */
    USBFILTER Dev2;
    USBFilterInit(&Dev2, USBFILTERTYPE_CAPTURE);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_VENDOR_ID,         0x19b6, true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_PRODUCT_ID,        0x1024, true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_DEVICE_REV,        0x0141, true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_DEVICE_CLASS,      0,      true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_DEVICE_SUB_CLASS,  0,      true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_DEVICE_PROTOCOL,   0,      true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetNumExact(&Dev2,      USBFILTERIDX_PORT,              0x1,    true) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetStringExact(&Dev2,   USBFILTERIDX_MANUFACTURER_STR, "Generic", true, false ) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetStringExact(&Dev2,   USBFILTERIDX_PRODUCT_STR, "Mass Storage Device", true, false ) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterSetStringExact(&Dev2,   USBFILTERIDX_MANUFACTURER_STR, "YBU1PPRS", true, false ) == VINF_SUCCESS);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_VENDOR_ID) == 0x19b6);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_PRODUCT_ID) == 0x1024);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_DEVICE_REV) == 0x0141);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_DEVICE_CLASS) == 0);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_DEVICE_SUB_CLASS) == 0);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_DEVICE_PROTOCOL) == 0);
    TST_CHECK_EXPR(USBFilterGetNum(&Dev2, USBFILTERIDX_PORT) == 1);


    /*
     * Summary.
     */
    if (!cErrors)
        RTPrintf(TESTCASE ": SUCCESS\n");
    else
        RTPrintf(TESTCASE ": FAILURE - %d errors\n", cErrors);
    return !!cErrors;
}