diff options
Diffstat (limited to 'src/VBox/Devices/USB/VUSBSnifferUsbMon.cpp')
-rw-r--r-- | src/VBox/Devices/USB/VUSBSnifferUsbMon.cpp | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/VBox/Devices/USB/VUSBSnifferUsbMon.cpp b/src/VBox/Devices/USB/VUSBSnifferUsbMon.cpp new file mode 100644 index 00000000..ef09fb3b --- /dev/null +++ b/src/VBox/Devices/USB/VUSBSnifferUsbMon.cpp @@ -0,0 +1,249 @@ +/* $Id: VUSBSnifferUsbMon.cpp $ */ +/** @file + * Virtual USB Sniffer facility - Linux usbmon ASCII format. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DRV_VUSB +#include <VBox/log.h> +#include <iprt/mem.h> +#include <iprt/buildconfig.h> +#include <iprt/string.h> +#include <iprt/system.h> +#include <iprt/time.h> + +#include "VUSBSnifferInternal.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ + +/** + * The internal VUSB sniffer state. + */ +typedef struct VUSBSNIFFERFMTINT +{ + /** Stream handle. */ + PVUSBSNIFFERSTRM pStrm; +} VUSBSNIFFERFMTINT; + + +/********************************************************************************************************************************* +* Static Variables * +*********************************************************************************************************************************/ + +/** + * Supported file extensions. + */ +static const char *s_apszFileExts[] = +{ + "mon", + "usbmon", + NULL +}; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ + + +/** @interface_method_impl{VUSBSNIFFERFMT,pfnInit} */ +static DECLCALLBACK(int) vusbSnifferFmtUsbMonInit(PVUSBSNIFFERFMTINT pThis, PVUSBSNIFFERSTRM pStrm) +{ + pThis->pStrm = pStrm; + return VINF_SUCCESS; +} + + +/** @interface_method_impl{VUSBSNIFFERFMT,pfnDestroy} */ +static DECLCALLBACK(void) vusbSnifferFmtUsbMonDestroy(PVUSBSNIFFERFMTINT pThis) +{ + RT_NOREF(pThis); +} + + +/** @interface_method_impl{VUSBSNIFFERFMT,pfnRecordEvent} */ +static DECLCALLBACK(int) vusbSnifferFmtUsbMonRecordEvent(PVUSBSNIFFERFMTINT pThis, PVUSBURB pUrb, VUSBSNIFFEREVENT enmEvent) +{ + char aszLineBuf[512]; + char chEvtType = 'X'; + char chDir = 'X'; + char chEptType = 'X'; + + switch (enmEvent) + { + case VUSBSNIFFEREVENT_SUBMIT: + chEvtType = 'S'; + break; + case VUSBSNIFFEREVENT_COMPLETE: + chEvtType = 'C'; + break; + case VUSBSNIFFEREVENT_ERROR_SUBMIT: + case VUSBSNIFFEREVENT_ERROR_COMPLETE: + chEvtType = 'E'; + break; + default: + AssertMsgFailed(("Invalid event type %d\n", enmEvent)); + } + + switch (pUrb->enmType) + { + case VUSBXFERTYPE_ISOC: + chEptType = 'Z'; + break; + case VUSBXFERTYPE_BULK: + chEptType = 'B'; + break; + case VUSBXFERTYPE_INTR: + chEptType = 'I'; + break; + case VUSBXFERTYPE_CTRL: + case VUSBXFERTYPE_MSG: + chEptType = 'C'; + break; + default: + AssertMsgFailed(("invalid transfer type %d\n", pUrb->enmType)); + } + + if (pUrb->enmDir == VUSBDIRECTION_IN) + chDir = 'i'; + else if (pUrb->enmDir == VUSBDIRECTION_OUT) + chDir = 'o'; + else if (pUrb->enmDir == VUSBDIRECTION_SETUP) + chDir = 'o'; + + RT_ZERO(aszLineBuf); + + /* Assemble the static part. */ + size_t cch = RTStrPrintf(&aszLineBuf[0], sizeof(aszLineBuf), "%p %llu %c %c%c:%u:%u:%u ", + pUrb, RTTimeNanoTS() / RT_NS_1US, chEvtType, chEptType, chDir, + 0, pUrb->DstAddress, pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0x00)); + int rc = pThis->pStrm->pfnWrite(pThis->pStrm, &aszLineBuf[0], cch); + if (RT_SUCCESS(rc)) + { + /* Log the setup packet for control requests, the status otherwise. */ + if ( (pUrb->enmType == VUSBXFERTYPE_CTRL || pUrb->enmType == VUSBXFERTYPE_MSG) + && enmEvent == VUSBSNIFFEREVENT_SUBMIT) + { + PVUSBSETUP pSetup = (PVUSBSETUP)pUrb->abData; + + cch = RTStrPrintf(&aszLineBuf[0], sizeof(aszLineBuf), "s %02x %02x %04x %04x %04x ", + pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, + pSetup->wIndex, pSetup->wLength); + rc = pThis->pStrm->pfnWrite(pThis->pStrm, &aszLineBuf[0], cch); + } + else + { + bool fLogAdditionalStatus = pUrb->enmType == VUSBXFERTYPE_ISOC + || pUrb->enmType == VUSBXFERTYPE_INTR; + + cch = RTStrPrintf(&aszLineBuf[0], sizeof(aszLineBuf), "%d%s", pUrb->enmStatus, + fLogAdditionalStatus ? "" : " "); + + /* There are additional fields to log for isochronous and interrupt URBs. */ + if (pUrb->enmType == VUSBXFERTYPE_ISOC) + { + if (enmEvent == VUSBSNIFFEREVENT_COMPLETE) + { + uint32_t u32ErrorCount = 0; + + for (unsigned i = 0; i < pUrb->cIsocPkts; i++) + if ( pUrb->aIsocPkts[i].enmStatus != VUSBSTATUS_OK + && pUrb->aIsocPkts[i].enmStatus != VUSBSTATUS_NOT_ACCESSED) + u32ErrorCount++; + + cch += RTStrPrintf(&aszLineBuf[cch], sizeof(aszLineBuf) - cch, ":%u:%u:%u ", + 1 /* Interval */, 0 /* Frame number */, u32ErrorCount); + } + else + cch += RTStrPrintf(&aszLineBuf[cch], sizeof(aszLineBuf) - cch, ":%u:%u ", + 1 /* Interval */, 0 /* Frame number */); + } + else if (pUrb->enmType == VUSBXFERTYPE_INTR) + cch += RTStrPrintf(&aszLineBuf[cch], sizeof(aszLineBuf) - cch, ":%u ", + 1 /* Interval */); + + rc = pThis->pStrm->pfnWrite(pThis->pStrm, &aszLineBuf[0], cch); + } + + /* Log the packet descriptors for isochronous URBs. */ + if ( RT_SUCCESS(rc) + && pUrb->enmType == VUSBXFERTYPE_ISOC) + { + cch = RTStrPrintf(&aszLineBuf[0], sizeof(aszLineBuf), "%u ", pUrb->cIsocPkts); + rc = pThis->pStrm->pfnWrite(pThis->pStrm, &aszLineBuf[0], cch); + for (unsigned i = 0; i < pUrb->cIsocPkts && RT_SUCCESS(rc); i++) + { + cch = RTStrPrintf(&aszLineBuf[0], sizeof(aszLineBuf), "%d:%u:%u ", + pUrb->aIsocPkts[i].enmStatus, pUrb->aIsocPkts[i].off, + pUrb->aIsocPkts[i].cb); + rc = pThis->pStrm->pfnWrite(pThis->pStrm, &aszLineBuf[0], cch); + } + } + + if (RT_SUCCESS(rc)) + { + /* Print data length */ + cch = RTStrPrintf(&aszLineBuf[0], sizeof(aszLineBuf), "%d n\n", pUrb->cbData); + rc = pThis->pStrm->pfnWrite(pThis->pStrm, &aszLineBuf[0], cch); + } + + /** @todo Dump the data */ + } + + return rc; +} + +/** + * VUSB sniffer format writer. + */ +const VUSBSNIFFERFMT g_VUsbSnifferFmtUsbMon = +{ + /** szName */ + "USBMON", + /** pszDesc */ + "UsbMon format writer compatible with vusb-analyzer: http://vusb-analyzer.sourceforge.net", + /** papszFileExts */ + &s_apszFileExts[0], + /** cbFmt */ + sizeof(VUSBSNIFFERFMTINT), + /** pfnInit */ + vusbSnifferFmtUsbMonInit, + /** pfnDestroy */ + vusbSnifferFmtUsbMonDestroy, + /** pfnRecordEvent */ + vusbSnifferFmtUsbMonRecordEvent +}; + |