DECLHIDDEN(int) VUSBSnifferCreate(PVUSBSNIFFER phSniffer, uint32_t fFlags, const char *pszCaptureFilename, const char *pszDesc) { int rc = VINF_SUCCESS; PVUSBSNIFFERINT pThis = NULL; pThis = (PVUSBSNIFFERINT)RTMemAllocZ(sizeof(VUSBSNIFFERINT)); if (pThis) { pThis->hFile = NIL_RTFILE; pThis->cbBlockCur = 0; pThis->cbBlockMax = 0; pThis->pbBlockData = NULL; pThis->hMtx = NIL_RTSEMFASTMUTEX; rc = RTSemFastMutexCreate(&pThis->hMtx); if (RT_SUCCESS(rc)) { rc = RTFileOpen(&pThis->hFile, pszCaptureFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ); if (RT_SUCCESS(rc)) { /* Write header and link type blocks. */ DumpFileShb Shb; Shb.Hdr.u32BlockType = DUMPFILE_SHB_BLOCK_TYPE; Shb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */ Shb.u32ByteOrderMagic = DUMPFILE_SHB_BYTE_ORDER_MAGIC; Shb.u16VersionMajor = DUMPFILE_SHB_VERSION_MAJOR; Shb.u16VersionMinor = DUMPFILE_SHB_VERSION_MINOR; Shb.u64SectionLength = UINT64_C(0xffffffffffffffff); /* -1 */ /* Write the blocks. */ rc = vusbSnifferBlockNew(pThis, &Shb.Hdr, sizeof(Shb)); if (RT_SUCCESS(rc)) { const char *pszOpt = RTBldCfgTargetDotArch(); rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_HARDWARE, pszOpt, strlen(pszOpt) + 1); } if (RT_SUCCESS(rc)) { char szTmp[512]; size_t cbTmp = sizeof(szTmp); RT_ZERO(szTmp); /* Build the OS code. */ rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, cbTmp); if (RT_SUCCESS(rc)) { size_t cb = strlen(szTmp); szTmp[cb] = ' '; rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, &szTmp[cb + 1], cbTmp - (cb + 1)); if (RT_SUCCESS(rc)) { cb = strlen(szTmp); szTmp[cb] = ' '; rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, &szTmp[cb + 1], cbTmp - (cb + 1)); } } if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_OS, szTmp, strlen(szTmp) + 1); else rc = VINF_SUCCESS; /* Skip OS code if building the string failed. */ } if (RT_SUCCESS(rc)) { /** @todo: Add product info. */ } if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); /* Write Interface descriptor block. */ if (RT_SUCCESS(rc)) { DumpFileIdb Idb; Idb.Hdr.u32BlockType = DUMPFILE_IDB_BLOCK_TYPE; Idb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */ Idb.u16LinkType = DUMPFILE_IDB_LINK_TYPE_USB_LINUX_MMAPED; Idb.u16Reserved = 0; Idb.u32SnapLen = UINT32_C(0xffffffff); rc = vusbSnifferBlockNew(pThis, &Idb.Hdr, sizeof(Idb)); if (RT_SUCCESS(rc)) { uint8_t u8TsResolution = 9; /* Nano second resolution. */ /* Add timestamp resolution option. */ rc = vusbSnifferAddOption(pThis, DUMPFILE_IDB_OPTION_TS_RESOLUTION, &u8TsResolution, sizeof(u8TsResolution)); } if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); } if (RT_SUCCESS(rc)) { *phSniffer = pThis; return VINF_SUCCESS; } RTFileClose(pThis->hFile); pThis->hFile = NIL_RTFILE; RTFileDelete(pszCaptureFilename); } RTSemFastMutexDestroy(pThis->hMtx); pThis->hMtx = NIL_RTSEMFASTMUTEX; } RTMemFree(pThis); } else rc = VERR_NO_MEMORY; return rc; }
/** * Records an VUSB event. * * @returns VBox status code. * @param hSniffer The sniffer instance. * @param pUrb The URB triggering the event. * @param enmEvent The type of event to record. */ DECLHIDDEN(int) VUSBSnifferRecordEvent(VUSBSNIFFER hSniffer, PVUSBURB pUrb, VUSBSNIFFEREVENT enmEvent) { int rc = VINF_SUCCESS; PVUSBSNIFFERINT pThis = hSniffer; DumpFileEpb Epb; DumpFileUsbHeaderLnxMmapped UsbHdr; DumpFileUsbSetup UsbSetup; RTTIMESPEC TimeNow; uint64_t u64TimestampEvent; size_t cbUrbLength = 0; uint32_t cbDataLength = 0; uint32_t cbCapturedLength = sizeof(UsbHdr); uint32_t cIsocPkts = 0; uint8_t *pbData = NULL; RTTimeNow(&TimeNow); u64TimestampEvent = RTTimeSpecGetNano(&TimeNow); /* Start with the enhanced packet block. */ Epb.Hdr.u32BlockType = DUMPFILE_EPB_BLOCK_TYPE; Epb.Hdr.u32BlockTotalLength = 0; Epb.u32InterfaceId = 0; Epb.u32TimestampHigh = (u64TimestampEvent >> 32) & UINT32_C(0xffffffff); Epb.u32TimestampLow = u64TimestampEvent & UINT32_C(0xffffffff); UsbHdr.u64Id = (uint64_t)pUrb; /** @todo: check whether the pointer is a good ID. */ switch (enmEvent) { case VUSBSNIFFEREVENT_SUBMIT: UsbHdr.u8EventType = DUMPFILE_USB_EVENT_TYPE_SUBMIT; cbUrbLength = pUrb->cbData; break; case VUSBSNIFFEREVENT_COMPLETE: UsbHdr.u8EventType = DUMPFILE_USB_EVENT_TYPE_COMPLETE; cbUrbLength = pUrb->cbData; break; case VUSBSNIFFEREVENT_ERROR_SUBMIT: case VUSBSNIFFEREVENT_ERROR_COMPLETE: UsbHdr.u8EventType = DUMPFILE_USB_EVENT_TYPE_ERROR; break; default: AssertMsgFailed(("Invalid event type %d\n", enmEvent)); } cbDataLength = cbUrbLength; pbData = &pUrb->abData[0]; switch (pUrb->enmType) { case VUSBXFERTYPE_ISOC: { int32_t i32ErrorCount = 0; UsbHdr.u8TransferType = 0; cIsocPkts = pUrb->cIsocPkts; for (unsigned i = 0; i < cIsocPkts; i++) if ( pUrb->aIsocPkts[i].enmStatus != VUSBSTATUS_OK && pUrb->aIsocPkts[i].enmStatus != VUSBSTATUS_NOT_ACCESSED) i32ErrorCount++; UsbHdr.u.IsoRec.i32ErrorCount = i32ErrorCount; UsbHdr.u.IsoRec.i32NumDesc = pUrb->cIsocPkts; cbCapturedLength += cIsocPkts * sizeof(DumpFileUsbIsoDesc); break; } case VUSBXFERTYPE_BULK: UsbHdr.u8TransferType = 3; break; case VUSBXFERTYPE_INTR: UsbHdr.u8TransferType = 1; break; case VUSBXFERTYPE_CTRL: case VUSBXFERTYPE_MSG: UsbHdr.u8TransferType = 2; break; default: AssertMsgFailed(("invalid transfer type %d\n", pUrb->enmType)); } if (pUrb->enmDir == VUSBDIRECTION_IN) { if (enmEvent == VUSBSNIFFEREVENT_SUBMIT) cbDataLength = 0; } else if (pUrb->enmDir == VUSBDIRECTION_OUT) { if ( enmEvent == VUSBSNIFFEREVENT_COMPLETE || pUrb->enmType == VUSBXFERTYPE_CTRL || pUrb->enmType == VUSBXFERTYPE_MSG) cbDataLength = 0; } else if (pUrb->enmDir == VUSBDIRECTION_SETUP) cbDataLength -= sizeof(VUSBSETUP); Epb.u32CapturedLen = cbCapturedLength + cbDataLength; Epb.u32PacketLen = cbCapturedLength + cbUrbLength; UsbHdr.u8EndpointNumber = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0x00); UsbHdr.u8DeviceAddress = pUrb->DstAddress; UsbHdr.u16BusId = 0; UsbHdr.u8DataFlag = cbDataLength ? 0 : 1; UsbHdr.u64TimestampSec = u64TimestampEvent / RT_NS_1SEC_64; UsbHdr.u32TimestampUSec = u64TimestampEvent / RT_NS_1US_64 - UsbHdr.u64TimestampSec * RT_US_1SEC; UsbHdr.i32Status = pUrb->enmStatus; UsbHdr.u32UrbLength = cbUrbLength; UsbHdr.u32DataLength = cbDataLength + cIsocPkts * sizeof(DumpFileUsbIsoDesc); UsbHdr.i32Interval = 0; UsbHdr.i32StartFrame = 0; UsbHdr.u32XferFlags = 0; UsbHdr.u32NumDesc = cIsocPkts; if ( (pUrb->enmType == VUSBXFERTYPE_MSG || pUrb->enmType == VUSBXFERTYPE_CTRL) && enmEvent == VUSBSNIFFEREVENT_SUBMIT) { PVUSBSETUP pSetup = (PVUSBSETUP)pUrb->abData; UsbHdr.u.UsbSetup.bmRequestType = pSetup->bmRequestType; UsbHdr.u.UsbSetup.bRequest = pSetup->bRequest; UsbHdr.u.UsbSetup.wValue = pSetup->wValue; UsbHdr.u.UsbSetup.wIndex = pSetup->wIndex; UsbHdr.u.UsbSetup.wLength = pSetup->wLength; UsbHdr.u8SetupFlag = 0; } else UsbHdr.u8SetupFlag = '-'; /* Follow usbmon source here. */ /* Write the packet to the capture file. */ rc = RTSemFastMutexRequest(pThis->hMtx); if (RT_SUCCESS(rc)) { rc = vusbSnifferBlockNew(pThis, &Epb.Hdr, sizeof(Epb)); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockAddData(pThis, &UsbHdr, sizeof(UsbHdr)); /* Add Isochronous descriptors now. */ for (unsigned i = 0; i < cIsocPkts && RT_SUCCESS(rc); i++) { DumpFileUsbIsoDesc IsoDesc; IsoDesc.i32Status = pUrb->aIsocPkts[i].enmStatus; IsoDesc.u32Offset = pUrb->aIsocPkts[i].off; IsoDesc.u32Len = pUrb->aIsocPkts[i].cb; rc = vusbSnifferBlockAddData(pThis, &IsoDesc, sizeof(IsoDesc)); } /* Record data. */ if ( RT_SUCCESS(rc) && cbDataLength) rc = vusbSnifferBlockAddData(pThis, pbData, cbDataLength); if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); RTSemFastMutexRelease(pThis->hMtx); } return rc; }
/** @copydoc VUSBSNIFFERFMT::pfnInit */ static DECLCALLBACK(int) vusbSnifferFmtPcanNgInit(PVUSBSNIFFERFMTINT pThis, PVUSBSNIFFERSTRM pStrm) { int rc = VINF_SUCCESS; pThis->pStrm = pStrm; pThis->cbBlockCur = 0; pThis->cbBlockMax = 0; pThis->pbBlockData = NULL; /* Write header and link type blocks. */ DumpFileShb Shb; Shb.Hdr.u32BlockType = DUMPFILE_SHB_BLOCK_TYPE; Shb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */ Shb.u32ByteOrderMagic = DUMPFILE_SHB_BYTE_ORDER_MAGIC; Shb.u16VersionMajor = DUMPFILE_SHB_VERSION_MAJOR; Shb.u16VersionMinor = DUMPFILE_SHB_VERSION_MINOR; Shb.u64SectionLength = UINT64_C(0xffffffffffffffff); /* -1 */ /* Write the blocks. */ rc = vusbSnifferBlockNew(pThis, &Shb.Hdr, sizeof(Shb)); if (RT_SUCCESS(rc)) { const char *pszOpt = RTBldCfgTargetDotArch(); rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_HARDWARE, pszOpt, strlen(pszOpt) + 1); } if (RT_SUCCESS(rc)) { char szTmp[512]; size_t cbTmp = sizeof(szTmp); RT_ZERO(szTmp); /* Build the OS code. */ rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, cbTmp); if (RT_SUCCESS(rc)) { size_t cb = strlen(szTmp); szTmp[cb] = ' '; rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, &szTmp[cb + 1], cbTmp - (cb + 1)); if (RT_SUCCESS(rc)) { cb = strlen(szTmp); szTmp[cb] = ' '; rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, &szTmp[cb + 1], cbTmp - (cb + 1)); } } if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_OS, szTmp, strlen(szTmp) + 1); else rc = VINF_SUCCESS; /* Skip OS code if building the string failed. */ } if (RT_SUCCESS(rc)) { /** @todo: Add product info. */ } if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); /* Write Interface descriptor block. */ if (RT_SUCCESS(rc)) { DumpFileIdb Idb; Idb.Hdr.u32BlockType = DUMPFILE_IDB_BLOCK_TYPE; Idb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */ Idb.u16LinkType = DUMPFILE_IDB_LINK_TYPE_USB_LINUX_MMAPED; Idb.u16Reserved = 0; Idb.u32SnapLen = UINT32_C(0xffffffff); rc = vusbSnifferBlockNew(pThis, &Idb.Hdr, sizeof(Idb)); if (RT_SUCCESS(rc)) { uint8_t u8TsResolution = 9; /* Nano second resolution. */ /* Add timestamp resolution option. */ rc = vusbSnifferAddOption(pThis, DUMPFILE_IDB_OPTION_TS_RESOLUTION, &u8TsResolution, sizeof(u8TsResolution)); } if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); } if ( RT_FAILURE(rc) && pThis->pbBlockData) RTMemFree(pThis->pbBlockData); return rc; }