[53014] | 1 | /* $Id: VUSBSnifferPcapNg.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[59615] | 3 | * Virtual USB Sniffer facility - PCAP-NG format writer.
|
---|
[53014] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2014-2023 Oracle and/or its affiliates.
|
---|
[53014] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[53014] | 26 | */
|
---|
| 27 |
|
---|
[57358] | 28 |
|
---|
| 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[53014] | 32 | #define LOG_GROUP LOG_GROUP_DRV_VUSB
|
---|
| 33 | #include <VBox/log.h>
|
---|
[76346] | 34 | #include <iprt/buildconfig.h>
|
---|
[76474] | 35 | #include <iprt/errcore.h>
|
---|
[53014] | 36 | #include <iprt/mem.h>
|
---|
| 37 | #include <iprt/string.h>
|
---|
| 38 | #include <iprt/system.h>
|
---|
[53072] | 39 | #include <iprt/time.h>
|
---|
[53014] | 40 |
|
---|
[59615] | 41 | #include "VUSBSnifferInternal.h"
|
---|
[53014] | 42 |
|
---|
| 43 |
|
---|
[57358] | 44 | /*********************************************************************************************************************************
|
---|
| 45 | * Defined Constants And Macros *
|
---|
| 46 | *********************************************************************************************************************************/
|
---|
| 47 |
|
---|
[53014] | 48 | /** DumpFile Section Header Block type. */
|
---|
| 49 | #define DUMPFILE_SHB_BLOCK_TYPE UINT32_C(0x0a0d0d0a)
|
---|
| 50 | /** The byte order magic value. */
|
---|
| 51 | #define DUMPFILE_SHB_BYTE_ORDER_MAGIC UINT32_C(0x1a2b3c4d)
|
---|
| 52 | /** Current major version. */
|
---|
| 53 | #define DUMPFILE_SHB_VERSION_MAJOR UINT16_C(1)
|
---|
| 54 | /** Current minor version. */
|
---|
| 55 | #define DUMPFILE_SHB_VERSION_MINOR UINT16_C(0)
|
---|
| 56 |
|
---|
| 57 | /** Block type for the interface descriptor block. */
|
---|
| 58 | #define DUMPFILE_IDB_BLOCK_TYPE UINT32_C(0x00000001)
|
---|
| 59 | /** USB link type. */
|
---|
[54568] | 60 | #define DUMPFILE_IDB_LINK_TYPE_USB_LINUX UINT16_C(189)
|
---|
[53014] | 61 | #define DUMPFILE_IDB_LINK_TYPE_USB_LINUX_MMAPED UINT16_C(220)
|
---|
| 62 |
|
---|
| 63 | /** Block type for an enhanced packet block. */
|
---|
| 64 | #define DUMPFILE_EPB_BLOCK_TYPE UINT32_C(0x00000006)
|
---|
| 65 |
|
---|
| 66 | /** USB packet event types. */
|
---|
| 67 | #define DUMPFILE_USB_EVENT_TYPE_SUBMIT ('S')
|
---|
| 68 | #define DUMPFILE_USB_EVENT_TYPE_COMPLETE ('C')
|
---|
| 69 | #define DUMPFILE_USB_EVENT_TYPE_ERROR ('E')
|
---|
| 70 |
|
---|
| 71 | #define DUMPFILE_OPTION_CODE_END UINT16_C(0)
|
---|
| 72 | #define DUMPFILE_OPTION_CODE_COMMENT UINT16_C(1)
|
---|
| 73 |
|
---|
| 74 | #define DUMPFILE_OPTION_CODE_HARDWARE UINT16_C(2)
|
---|
| 75 | #define DUMPFILE_OPTION_CODE_OS UINT16_C(3)
|
---|
| 76 | #define DUMPFILE_OPTION_CODE_USERAPP UINT16_C(4)
|
---|
| 77 |
|
---|
| 78 | #define DUMPFILE_IDB_OPTION_TS_RESOLUTION UINT16_C(9)
|
---|
| 79 |
|
---|
| 80 |
|
---|
[57358] | 81 | /*********************************************************************************************************************************
|
---|
| 82 | * DumpFile format structures *
|
---|
| 83 | *********************************************************************************************************************************/
|
---|
| 84 |
|
---|
[53014] | 85 | /**
|
---|
| 86 | * DumpFile Block header.
|
---|
| 87 | */
|
---|
| 88 | typedef struct DumpFileBlockHdr
|
---|
| 89 | {
|
---|
| 90 | /** Block type. */
|
---|
| 91 | uint32_t u32BlockType;
|
---|
| 92 | /** Block total length. */
|
---|
| 93 | uint32_t u32BlockTotalLength;
|
---|
| 94 | } DumpFileBlockHdr;
|
---|
| 95 | /** Pointer to a block header. */
|
---|
| 96 | typedef DumpFileBlockHdr *PDumpFileBlockHdr;
|
---|
| 97 |
|
---|
| 98 | /**
|
---|
| 99 | * DumpFile Option header.
|
---|
| 100 | */
|
---|
| 101 | typedef struct DumpFileOptionHdr
|
---|
| 102 | {
|
---|
| 103 | /** Option code. */
|
---|
| 104 | uint16_t u16OptionCode;
|
---|
| 105 | /** Block total length. */
|
---|
| 106 | uint16_t u16OptionLength;
|
---|
| 107 | } DumpFileOptionHdr;
|
---|
| 108 | /** Pointer to a option header. */
|
---|
| 109 | typedef DumpFileOptionHdr *PDumpFileOptionHdr;
|
---|
| 110 |
|
---|
| 111 | /**
|
---|
| 112 | * DumpFile Section Header Block.
|
---|
| 113 | */
|
---|
| 114 | typedef struct DumpFileShb
|
---|
| 115 | {
|
---|
| 116 | /** Block header. */
|
---|
| 117 | DumpFileBlockHdr Hdr;
|
---|
| 118 | /** Byte order magic. */
|
---|
| 119 | uint32_t u32ByteOrderMagic;
|
---|
| 120 | /** Major version. */
|
---|
| 121 | uint16_t u16VersionMajor;
|
---|
| 122 | /** Minor version. */
|
---|
| 123 | uint16_t u16VersionMinor;
|
---|
| 124 | /** Section length. */
|
---|
| 125 | uint64_t u64SectionLength;
|
---|
| 126 | } DumpFileShb;
|
---|
| 127 | /** Pointer to a Section Header Block. */
|
---|
| 128 | typedef DumpFileShb *PDumpFileShb;
|
---|
| 129 |
|
---|
| 130 | /**
|
---|
| 131 | * DumpFile Interface description block.
|
---|
| 132 | */
|
---|
| 133 | typedef struct DumpFileIdb
|
---|
| 134 | {
|
---|
| 135 | /** Block header. */
|
---|
| 136 | DumpFileBlockHdr Hdr;
|
---|
| 137 | /** Link type. */
|
---|
| 138 | uint16_t u16LinkType;
|
---|
| 139 | /** Reserved. */
|
---|
| 140 | uint16_t u16Reserved;
|
---|
| 141 | /** Maximum number of bytes dumped from each packet. */
|
---|
| 142 | uint32_t u32SnapLen;
|
---|
| 143 | } DumpFileIdb;
|
---|
| 144 | /** Pointer to an Interface description block. */
|
---|
| 145 | typedef DumpFileIdb *PDumpFileIdb;
|
---|
| 146 |
|
---|
| 147 | /**
|
---|
| 148 | * DumpFile Enhanced packet block.
|
---|
| 149 | */
|
---|
| 150 | typedef struct DumpFileEpb
|
---|
| 151 | {
|
---|
| 152 | /** Block header. */
|
---|
| 153 | DumpFileBlockHdr Hdr;
|
---|
| 154 | /** Interface ID. */
|
---|
| 155 | uint32_t u32InterfaceId;
|
---|
| 156 | /** Timestamp (high). */
|
---|
| 157 | uint32_t u32TimestampHigh;
|
---|
| 158 | /** Timestamp (low). */
|
---|
| 159 | uint32_t u32TimestampLow;
|
---|
| 160 | /** Captured packet length. */
|
---|
| 161 | uint32_t u32CapturedLen;
|
---|
| 162 | /** Original packet length. */
|
---|
| 163 | uint32_t u32PacketLen;
|
---|
| 164 | } DumpFileEpb;
|
---|
| 165 | /** Pointer to an Enhanced packet block. */
|
---|
| 166 | typedef DumpFileEpb *PDumpFileEpb;
|
---|
| 167 |
|
---|
| 168 | /**
|
---|
| 169 | * USB setup URB data.
|
---|
| 170 | */
|
---|
| 171 | typedef struct DumpFileUsbSetup
|
---|
| 172 | {
|
---|
| 173 | uint8_t bmRequestType;
|
---|
| 174 | uint8_t bRequest;
|
---|
| 175 | uint16_t wValue;
|
---|
| 176 | uint16_t wIndex;
|
---|
| 177 | uint16_t wLength;
|
---|
| 178 | } DumpFileUsbSetup;
|
---|
| 179 | typedef DumpFileUsbSetup *PDumpFileUsbSetup;
|
---|
| 180 |
|
---|
| 181 | /**
|
---|
| 182 | * USB Isochronous data.
|
---|
| 183 | */
|
---|
| 184 | typedef struct DumpFileIsoRec
|
---|
| 185 | {
|
---|
| 186 | int32_t i32ErrorCount;
|
---|
| 187 | int32_t i32NumDesc;
|
---|
| 188 | } DumpFileIsoRec;
|
---|
| 189 | typedef DumpFileIsoRec *PDumpFileIsoRec;
|
---|
| 190 |
|
---|
| 191 | /**
|
---|
| 192 | * USB packet header (Linux mmapped variant).
|
---|
| 193 | */
|
---|
| 194 | typedef struct DumpFileUsbHeaderLnxMmapped
|
---|
| 195 | {
|
---|
| 196 | /** Packet Id. */
|
---|
| 197 | uint64_t u64Id;
|
---|
| 198 | /** Event type. */
|
---|
| 199 | uint8_t u8EventType;
|
---|
| 200 | /** Transfer type. */
|
---|
| 201 | uint8_t u8TransferType;
|
---|
| 202 | /** Endpoint number. */
|
---|
| 203 | uint8_t u8EndpointNumber;
|
---|
| 204 | /** Device address. */
|
---|
| 205 | uint8_t u8DeviceAddress;
|
---|
| 206 | /** Bus id. */
|
---|
| 207 | uint16_t u16BusId;
|
---|
| 208 | /** Setup flag != 0 if the URB setup header is not present. */
|
---|
| 209 | uint8_t u8SetupFlag;
|
---|
| 210 | /** Data present flag != 0 if the URB data is not present. */
|
---|
| 211 | uint8_t u8DataFlag;
|
---|
| 212 | /** Timestamp (second part). */
|
---|
| 213 | uint64_t u64TimestampSec;
|
---|
| 214 | /** Timestamp (us part). */
|
---|
| 215 | uint32_t u32TimestampUSec;
|
---|
| 216 | /** Status. */
|
---|
| 217 | int32_t i32Status;
|
---|
| 218 | /** URB length. */
|
---|
| 219 | uint32_t u32UrbLength;
|
---|
| 220 | /** Recorded data length. */
|
---|
| 221 | uint32_t u32DataLength;
|
---|
| 222 | /** Union of data for different URB types. */
|
---|
| 223 | union
|
---|
| 224 | {
|
---|
| 225 | DumpFileUsbSetup UsbSetup;
|
---|
| 226 | DumpFileIsoRec IsoRec;
|
---|
| 227 | } u;
|
---|
| 228 | int32_t i32Interval;
|
---|
| 229 | int32_t i32StartFrame;
|
---|
| 230 | /** Copy of transfer flags. */
|
---|
| 231 | uint32_t u32XferFlags;
|
---|
| 232 | /** Number of isochronous descriptors. */
|
---|
| 233 | uint32_t u32NumDesc;
|
---|
| 234 | } DumpFileUsbHeaderLnxMmapped;
|
---|
| 235 | /** Pointer to a USB packet header. */
|
---|
| 236 | typedef DumpFileUsbHeaderLnxMmapped *PDumpFileUsbHeaderLnxMmapped;
|
---|
| 237 |
|
---|
[53060] | 238 | AssertCompileSize(DumpFileUsbHeaderLnxMmapped, 64);
|
---|
| 239 |
|
---|
[53014] | 240 | /**
|
---|
| 241 | * USB packet isochronous descriptor.
|
---|
| 242 | */
|
---|
| 243 | typedef struct DumpFileUsbIsoDesc
|
---|
| 244 | {
|
---|
| 245 | int32_t i32Status;
|
---|
| 246 | uint32_t u32Offset;
|
---|
| 247 | uint32_t u32Len;
|
---|
| 248 | uint8_t au8Padding[4];
|
---|
| 249 | } DumpFileUsbIsoDesc;
|
---|
| 250 | typedef DumpFileUsbIsoDesc *PDumpFileUsbIsoDesc;
|
---|
| 251 |
|
---|
| 252 |
|
---|
[57358] | 253 | /*********************************************************************************************************************************
|
---|
| 254 | * Structures and Typedefs *
|
---|
| 255 | *********************************************************************************************************************************/
|
---|
| 256 |
|
---|
[53014] | 257 | /**
|
---|
| 258 | * The internal VUSB sniffer state.
|
---|
| 259 | */
|
---|
[59615] | 260 | typedef struct VUSBSNIFFERFMTINT
|
---|
[53014] | 261 | {
|
---|
[59615] | 262 | /** Stream handle. */
|
---|
| 263 | PVUSBSNIFFERSTRM pStrm;
|
---|
[53014] | 264 | /** Current size of the block being written. */
|
---|
| 265 | uint32_t cbBlockCur;
|
---|
| 266 | /** Maximum size allocated for the block. */
|
---|
| 267 | uint32_t cbBlockMax;
|
---|
| 268 | /** Current block header. */
|
---|
| 269 | PDumpFileBlockHdr pBlockHdr;
|
---|
| 270 | /** Pointer to the block data which will be written on commit. */
|
---|
| 271 | uint8_t *pbBlockData;
|
---|
[59615] | 272 | } VUSBSNIFFERFMTINT;
|
---|
[53014] | 273 |
|
---|
[59615] | 274 |
|
---|
| 275 | /*********************************************************************************************************************************
|
---|
| 276 | * Static Variables *
|
---|
| 277 | *********************************************************************************************************************************/
|
---|
| 278 |
|
---|
[53014] | 279 | /**
|
---|
[59615] | 280 | * Supported file extensions.
|
---|
| 281 | */
|
---|
| 282 | static const char *s_apszFileExts[] =
|
---|
| 283 | {
|
---|
| 284 | "pcap",
|
---|
| 285 | "pcapng",
|
---|
| 286 | NULL
|
---|
| 287 | };
|
---|
| 288 |
|
---|
| 289 |
|
---|
| 290 | /*********************************************************************************************************************************
|
---|
| 291 | * Internal Functions *
|
---|
| 292 | *********************************************************************************************************************************/
|
---|
| 293 |
|
---|
| 294 | /**
|
---|
[53014] | 295 | * Allocates additional space for the block.
|
---|
| 296 | *
|
---|
| 297 | * @returns Pointer to the new unused space or NULL if out of memory.
|
---|
| 298 | * @param pThis The VUSB sniffer instance.
|
---|
| 299 | * @param cbAdditional The additional memory requested.
|
---|
| 300 | */
|
---|
[59615] | 301 | static void *vusbSnifferBlockAllocSpace(PVUSBSNIFFERFMTINT pThis, uint32_t cbAdditional)
|
---|
[53014] | 302 | {
|
---|
| 303 | /* Fast path where we have enough memory allocated. */
|
---|
| 304 | if (pThis->cbBlockCur + cbAdditional <= pThis->cbBlockMax)
|
---|
| 305 | {
|
---|
| 306 | void *pv = pThis->pbBlockData + pThis->cbBlockCur;
|
---|
| 307 | pThis->cbBlockCur += cbAdditional;
|
---|
| 308 | return pv;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | /* Allocate additional memory. */
|
---|
| 312 | uint32_t cbNew = pThis->cbBlockCur + cbAdditional;
|
---|
| 313 | uint8_t *pbDataNew = (uint8_t *)RTMemRealloc(pThis->pbBlockData, cbNew);
|
---|
| 314 | if (pbDataNew)
|
---|
| 315 | {
|
---|
| 316 | pThis->pbBlockData = pbDataNew;
|
---|
| 317 | pThis->pBlockHdr = (PDumpFileBlockHdr)pbDataNew;
|
---|
| 318 |
|
---|
| 319 | void *pv = pThis->pbBlockData + pThis->cbBlockCur;
|
---|
| 320 | pThis->cbBlockCur = cbNew;
|
---|
| 321 | pThis->cbBlockMax = cbNew;
|
---|
| 322 | return pv;
|
---|
| 323 | }
|
---|
| 324 |
|
---|
| 325 | return NULL;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /**
|
---|
[53060] | 329 | * Adds new data to the current block.
|
---|
| 330 | *
|
---|
| 331 | * @returns VBox status code.
|
---|
| 332 | * @param pThis The VUSB sniffer instance.
|
---|
| 333 | * @param pvData The data to add.
|
---|
| 334 | * @param cbData Amount of data to add.
|
---|
| 335 | */
|
---|
[59615] | 336 | static int vusbSnifferBlockAddData(PVUSBSNIFFERFMTINT pThis, const void *pvData, uint32_t cbData)
|
---|
[53060] | 337 | {
|
---|
| 338 | int rc = VINF_SUCCESS;
|
---|
| 339 |
|
---|
| 340 | Assert(pThis->cbBlockCur);
|
---|
| 341 | AssertPtr(pThis->pBlockHdr);
|
---|
| 342 |
|
---|
| 343 | void *pv = vusbSnifferBlockAllocSpace(pThis, cbData);
|
---|
| 344 | if (pv)
|
---|
| 345 | memcpy(pv, pvData, cbData);
|
---|
| 346 | else
|
---|
| 347 | rc = VERR_NO_MEMORY;
|
---|
| 348 |
|
---|
| 349 | return rc;
|
---|
| 350 | }
|
---|
| 351 |
|
---|
| 352 | /**
|
---|
[53072] | 353 | * Aligns the current block data to a 32bit boundary.
|
---|
[53014] | 354 | *
|
---|
| 355 | * @returns VBox status code.
|
---|
| 356 | * @param pThis The VUSB sniffer instance.
|
---|
| 357 | */
|
---|
[59615] | 358 | static int vusbSnifferBlockAlign(PVUSBSNIFFERFMTINT pThis)
|
---|
[53014] | 359 | {
|
---|
| 360 | int rc = VINF_SUCCESS;
|
---|
| 361 |
|
---|
[53072] | 362 | Assert(pThis->cbBlockCur);
|
---|
[53014] | 363 |
|
---|
[53060] | 364 | /* Pad to 32bits. */
|
---|
| 365 | uint8_t abPad[3] = { 0 };
|
---|
| 366 | uint32_t cbPad = RT_ALIGN_32(pThis->cbBlockCur, 4) - pThis->cbBlockCur;
|
---|
| 367 |
|
---|
| 368 | Assert(cbPad <= 3);
|
---|
| 369 | if (cbPad)
|
---|
| 370 | rc = vusbSnifferBlockAddData(pThis, abPad, cbPad);
|
---|
| 371 |
|
---|
[53072] | 372 | return rc;
|
---|
| 373 | }
|
---|
| 374 |
|
---|
| 375 | /**
|
---|
| 376 | * Commits the current block to the capture file.
|
---|
| 377 | *
|
---|
| 378 | * @returns VBox status code.
|
---|
| 379 | * @param pThis The VUSB sniffer instance.
|
---|
| 380 | */
|
---|
[59615] | 381 | static int vusbSnifferBlockCommit(PVUSBSNIFFERFMTINT pThis)
|
---|
[53072] | 382 | {
|
---|
| 383 | int rc = VINF_SUCCESS;
|
---|
| 384 |
|
---|
| 385 | AssertPtr(pThis->pBlockHdr);
|
---|
| 386 |
|
---|
| 387 | rc = vusbSnifferBlockAlign(pThis);
|
---|
[53060] | 388 | if (RT_SUCCESS(rc))
|
---|
[53014] | 389 | {
|
---|
[53060] | 390 | /* Update the block total length field. */
|
---|
| 391 | uint32_t *pcbTotalLength = (uint32_t *)vusbSnifferBlockAllocSpace(pThis, 4);
|
---|
| 392 | if (pcbTotalLength)
|
---|
| 393 | {
|
---|
| 394 | *pcbTotalLength = pThis->cbBlockCur;
|
---|
| 395 | pThis->pBlockHdr->u32BlockTotalLength = pThis->cbBlockCur;
|
---|
[53014] | 396 |
|
---|
[53060] | 397 | /* Write the data. */
|
---|
[59615] | 398 | rc = pThis->pStrm->pfnWrite(pThis->pStrm, pThis->pbBlockData, pThis->cbBlockCur);
|
---|
[53060] | 399 | pThis->cbBlockCur = 0;
|
---|
| 400 | pThis->pBlockHdr = NULL;
|
---|
| 401 | }
|
---|
| 402 | else
|
---|
| 403 | rc = VERR_NO_MEMORY;
|
---|
[53014] | 404 | }
|
---|
| 405 |
|
---|
| 406 | return rc;
|
---|
| 407 | }
|
---|
| 408 |
|
---|
| 409 | /**
|
---|
| 410 | * Starts a new block for capturing.
|
---|
| 411 | *
|
---|
| 412 | * @returns VBox status code.
|
---|
| 413 | * @param pThis The VUSB sniffer instance.
|
---|
| 414 | * @param pBlockHdr Pointer to the block header for the new block.
|
---|
| 415 | * @param cbData Amount of data added with this block.
|
---|
| 416 | */
|
---|
[59615] | 417 | static int vusbSnifferBlockNew(PVUSBSNIFFERFMTINT pThis, PDumpFileBlockHdr pBlockHdr, uint32_t cbData)
|
---|
[53014] | 418 | {
|
---|
| 419 | int rc = VINF_SUCCESS;
|
---|
| 420 |
|
---|
| 421 | /* Validate we don't get called while another block is active. */
|
---|
| 422 | Assert(!pThis->cbBlockCur);
|
---|
| 423 | Assert(!pThis->pBlockHdr);
|
---|
| 424 | pThis->pBlockHdr = (PDumpFileBlockHdr)vusbSnifferBlockAllocSpace(pThis, cbData);
|
---|
| 425 | if (pThis->pBlockHdr)
|
---|
| 426 | memcpy(pThis->pBlockHdr, pBlockHdr, cbData);
|
---|
| 427 | else
|
---|
| 428 | rc = VERR_NO_MEMORY;
|
---|
| 429 |
|
---|
| 430 | return rc;
|
---|
| 431 | }
|
---|
| 432 |
|
---|
| 433 | /**
|
---|
| 434 | * Add a new option to the current block.
|
---|
| 435 | *
|
---|
| 436 | * @returns VBox status code.
|
---|
| 437 | * @param pThis The VUSB sniffer instance.
|
---|
| 438 | * @param u16OptionCode The option code identifying the type of option.
|
---|
| 439 | * @param pvOption Raw data for the option.
|
---|
| 440 | * @param cbOption Size of the optiob data.
|
---|
| 441 | */
|
---|
[62959] | 442 | static int vusbSnifferAddOption(PVUSBSNIFFERFMTINT pThis, uint16_t u16OptionCode, const void *pvOption, size_t cbOption)
|
---|
[53014] | 443 | {
|
---|
[62959] | 444 | AssertStmt((uint16_t)cbOption == cbOption, cbOption = UINT16_MAX);
|
---|
[53014] | 445 | DumpFileOptionHdr OptHdr;
|
---|
| 446 | OptHdr.u16OptionCode = u16OptionCode;
|
---|
[62959] | 447 | OptHdr.u16OptionLength = (uint16_t)cbOption;
|
---|
| 448 | int rc = vusbSnifferBlockAddData(pThis, &OptHdr, sizeof(OptHdr));
|
---|
[53014] | 449 | if ( RT_SUCCESS(rc)
|
---|
| 450 | && u16OptionCode != DUMPFILE_OPTION_CODE_END
|
---|
| 451 | && cbOption != 0)
|
---|
| 452 | {
|
---|
[62959] | 453 | rc = vusbSnifferBlockAddData(pThis, pvOption, (uint16_t)cbOption);
|
---|
[53014] | 454 | if (RT_SUCCESS(rc))
|
---|
[53072] | 455 | rc = vusbSnifferBlockAlign(pThis);
|
---|
[53014] | 456 | }
|
---|
| 457 |
|
---|
| 458 | return rc;
|
---|
| 459 | }
|
---|
| 460 |
|
---|
[59615] | 461 |
|
---|
[62956] | 462 | /** @interface_method_impl{VUSBSNIFFERFMT,pfnInit} */
|
---|
[65895] | 463 | static DECLCALLBACK(int) vusbSnifferFmtPcapNgInit(PVUSBSNIFFERFMTINT pThis, PVUSBSNIFFERSTRM pStrm)
|
---|
[53014] | 464 | {
|
---|
[59615] | 465 | pThis->pStrm = pStrm;
|
---|
| 466 | pThis->cbBlockCur = 0;
|
---|
| 467 | pThis->cbBlockMax = 0;
|
---|
| 468 | pThis->pbBlockData = NULL;
|
---|
[53014] | 469 |
|
---|
[59615] | 470 | /* Write header and link type blocks. */
|
---|
| 471 | DumpFileShb Shb;
|
---|
[53014] | 472 |
|
---|
[59615] | 473 | Shb.Hdr.u32BlockType = DUMPFILE_SHB_BLOCK_TYPE;
|
---|
| 474 | Shb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */
|
---|
| 475 | Shb.u32ByteOrderMagic = DUMPFILE_SHB_BYTE_ORDER_MAGIC;
|
---|
| 476 | Shb.u16VersionMajor = DUMPFILE_SHB_VERSION_MAJOR;
|
---|
| 477 | Shb.u16VersionMinor = DUMPFILE_SHB_VERSION_MINOR;
|
---|
| 478 | Shb.u64SectionLength = UINT64_C(0xffffffffffffffff); /* -1 */
|
---|
[53014] | 479 |
|
---|
[59615] | 480 | /* Write the blocks. */
|
---|
[62960] | 481 | int rc = vusbSnifferBlockNew(pThis, &Shb.Hdr, sizeof(Shb));
|
---|
[59615] | 482 | if (RT_SUCCESS(rc))
|
---|
| 483 | {
|
---|
| 484 | const char *pszOpt = RTBldCfgTargetDotArch();
|
---|
| 485 | rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_HARDWARE, pszOpt, strlen(pszOpt) + 1);
|
---|
| 486 | }
|
---|
[53014] | 487 |
|
---|
[59615] | 488 | if (RT_SUCCESS(rc))
|
---|
| 489 | {
|
---|
| 490 | char szTmp[512];
|
---|
| 491 | size_t cbTmp = sizeof(szTmp);
|
---|
[53014] | 492 |
|
---|
[59615] | 493 | RT_ZERO(szTmp);
|
---|
[53071] | 494 |
|
---|
[59615] | 495 | /* Build the OS code. */
|
---|
| 496 | rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, cbTmp);
|
---|
| 497 | if (RT_SUCCESS(rc))
|
---|
| 498 | {
|
---|
| 499 | size_t cb = strlen(szTmp);
|
---|
[53071] | 500 |
|
---|
[59615] | 501 | szTmp[cb] = ' ';
|
---|
| 502 | rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, &szTmp[cb + 1], cbTmp - (cb + 1));
|
---|
| 503 | if (RT_SUCCESS(rc))
|
---|
| 504 | {
|
---|
| 505 | cb = strlen(szTmp);
|
---|
| 506 | szTmp[cb] = ' ';
|
---|
| 507 | rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, &szTmp[cb + 1], cbTmp - (cb + 1));
|
---|
| 508 | }
|
---|
| 509 | }
|
---|
[53071] | 510 |
|
---|
[59615] | 511 | if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
|
---|
| 512 | rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_OS, szTmp, strlen(szTmp) + 1);
|
---|
| 513 | else
|
---|
| 514 | rc = VINF_SUCCESS; /* Skip OS code if building the string failed. */
|
---|
| 515 | }
|
---|
[53014] | 516 |
|
---|
[59615] | 517 | if (RT_SUCCESS(rc))
|
---|
| 518 | {
|
---|
[63562] | 519 | /** @todo Add product info. */
|
---|
[59615] | 520 | }
|
---|
[53014] | 521 |
|
---|
[59615] | 522 | if (RT_SUCCESS(rc))
|
---|
| 523 | rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0);
|
---|
| 524 | if (RT_SUCCESS(rc))
|
---|
| 525 | rc = vusbSnifferBlockCommit(pThis);
|
---|
[53014] | 526 |
|
---|
[59615] | 527 | /* Write Interface descriptor block. */
|
---|
| 528 | if (RT_SUCCESS(rc))
|
---|
| 529 | {
|
---|
| 530 | DumpFileIdb Idb;
|
---|
[53014] | 531 |
|
---|
[59615] | 532 | Idb.Hdr.u32BlockType = DUMPFILE_IDB_BLOCK_TYPE;
|
---|
| 533 | Idb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */
|
---|
| 534 | Idb.u16LinkType = DUMPFILE_IDB_LINK_TYPE_USB_LINUX_MMAPED;
|
---|
| 535 | Idb.u16Reserved = 0;
|
---|
| 536 | Idb.u32SnapLen = UINT32_C(0xffffffff);
|
---|
[53014] | 537 |
|
---|
[59615] | 538 | rc = vusbSnifferBlockNew(pThis, &Idb.Hdr, sizeof(Idb));
|
---|
| 539 | if (RT_SUCCESS(rc))
|
---|
| 540 | {
|
---|
| 541 | uint8_t u8TsResolution = 9; /* Nano second resolution. */
|
---|
| 542 | /* Add timestamp resolution option. */
|
---|
| 543 | rc = vusbSnifferAddOption(pThis, DUMPFILE_IDB_OPTION_TS_RESOLUTION,
|
---|
| 544 | &u8TsResolution, sizeof(u8TsResolution));
|
---|
[53014] | 545 | }
|
---|
[59615] | 546 | if (RT_SUCCESS(rc))
|
---|
| 547 | rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0);
|
---|
| 548 | if (RT_SUCCESS(rc))
|
---|
| 549 | rc = vusbSnifferBlockCommit(pThis);
|
---|
[53014] | 550 | }
|
---|
| 551 |
|
---|
[59615] | 552 | if ( RT_FAILURE(rc)
|
---|
| 553 | && pThis->pbBlockData)
|
---|
| 554 | RTMemFree(pThis->pbBlockData);
|
---|
| 555 |
|
---|
[53014] | 556 | return rc;
|
---|
| 557 | }
|
---|
| 558 |
|
---|
[59615] | 559 |
|
---|
[62956] | 560 | /** @interface_method_impl{VUSBSNIFFERFMT,pfnDestroy} */
|
---|
[65895] | 561 | static DECLCALLBACK(void) vusbSnifferFmtPcapNgDestroy(PVUSBSNIFFERFMTINT pThis)
|
---|
[53014] | 562 | {
|
---|
| 563 | if (pThis->pbBlockData)
|
---|
| 564 | RTMemFree(pThis->pbBlockData);
|
---|
| 565 | }
|
---|
| 566 |
|
---|
[59615] | 567 |
|
---|
[62956] | 568 | /** @interface_method_impl{VUSBSNIFFERFMT,pfnRecordEvent} */
|
---|
[65895] | 569 | static DECLCALLBACK(int) vusbSnifferFmtPcapNgRecordEvent(PVUSBSNIFFERFMTINT pThis, PVUSBURB pUrb, VUSBSNIFFEREVENT enmEvent)
|
---|
[53014] | 570 | {
|
---|
| 571 | DumpFileEpb Epb;
|
---|
| 572 | DumpFileUsbHeaderLnxMmapped UsbHdr;
|
---|
[53146] | 573 | uint32_t cbCapturedLength = sizeof(UsbHdr);
|
---|
[53168] | 574 | uint8_t *pbData = NULL;
|
---|
[53014] | 575 |
|
---|
[62959] | 576 | RTTIMESPEC TimeNow;
|
---|
[53072] | 577 | RTTimeNow(&TimeNow);
|
---|
[62959] | 578 | uint64_t u64TimestampEvent = RTTimeSpecGetNano(&TimeNow);
|
---|
[53072] | 579 |
|
---|
[53014] | 580 | /* Start with the enhanced packet block. */
|
---|
| 581 | Epb.Hdr.u32BlockType = DUMPFILE_EPB_BLOCK_TYPE;
|
---|
| 582 | Epb.Hdr.u32BlockTotalLength = 0;
|
---|
| 583 | Epb.u32InterfaceId = 0;
|
---|
| 584 | Epb.u32TimestampHigh = (u64TimestampEvent >> 32) & UINT32_C(0xffffffff);
|
---|
| 585 | Epb.u32TimestampLow = u64TimestampEvent & UINT32_C(0xffffffff);
|
---|
| 586 |
|
---|
[63562] | 587 | UsbHdr.u64Id = (uintptr_t)pUrb; /** @todo check whether the pointer is a good ID. */
|
---|
[62959] | 588 | uint32_t cbUrbLength;
|
---|
[53014] | 589 | switch (enmEvent)
|
---|
| 590 | {
|
---|
| 591 | case VUSBSNIFFEREVENT_SUBMIT:
|
---|
| 592 | UsbHdr.u8EventType = DUMPFILE_USB_EVENT_TYPE_SUBMIT;
|
---|
[53146] | 593 | cbUrbLength = pUrb->cbData;
|
---|
[53014] | 594 | break;
|
---|
| 595 | case VUSBSNIFFEREVENT_COMPLETE:
|
---|
| 596 | UsbHdr.u8EventType = DUMPFILE_USB_EVENT_TYPE_COMPLETE;
|
---|
[53146] | 597 | cbUrbLength = pUrb->cbData;
|
---|
[53014] | 598 | break;
|
---|
| 599 | case VUSBSNIFFEREVENT_ERROR_SUBMIT:
|
---|
| 600 | case VUSBSNIFFEREVENT_ERROR_COMPLETE:
|
---|
| 601 | UsbHdr.u8EventType = DUMPFILE_USB_EVENT_TYPE_ERROR;
|
---|
[62959] | 602 | cbUrbLength = 0;
|
---|
[53014] | 603 | break;
|
---|
| 604 | default:
|
---|
| 605 | AssertMsgFailed(("Invalid event type %d\n", enmEvent));
|
---|
[62959] | 606 | cbUrbLength = 0;
|
---|
[53014] | 607 | }
|
---|
[62959] | 608 | uint32_t cbDataLength = cbUrbLength;
|
---|
[53168] | 609 | pbData = &pUrb->abData[0];
|
---|
[53146] | 610 |
|
---|
[62959] | 611 | uint32_t cIsocPkts = 0;
|
---|
[53014] | 612 | switch (pUrb->enmType)
|
---|
| 613 | {
|
---|
| 614 | case VUSBXFERTYPE_ISOC:
|
---|
[53146] | 615 | {
|
---|
[62959] | 616 | int32_t cErrors = 0;
|
---|
[53146] | 617 |
|
---|
[59615] | 618 | UsbHdr.u8TransferType = 0;
|
---|
| 619 | cIsocPkts = pUrb->cIsocPkts;
|
---|
| 620 | for (unsigned i = 0; i < cIsocPkts; i++)
|
---|
| 621 | if ( pUrb->aIsocPkts[i].enmStatus != VUSBSTATUS_OK
|
---|
| 622 | && pUrb->aIsocPkts[i].enmStatus != VUSBSTATUS_NOT_ACCESSED)
|
---|
[62959] | 623 | cErrors++;
|
---|
[53146] | 624 |
|
---|
[62959] | 625 | UsbHdr.u.IsoRec.i32ErrorCount = cErrors;
|
---|
[59615] | 626 | UsbHdr.u.IsoRec.i32NumDesc = pUrb->cIsocPkts;
|
---|
| 627 | cbCapturedLength += cIsocPkts * sizeof(DumpFileUsbIsoDesc);
|
---|
| 628 | break;
|
---|
[53146] | 629 | }
|
---|
[53014] | 630 | case VUSBXFERTYPE_BULK:
|
---|
[62959] | 631 | UsbHdr.u8TransferType = 3;
|
---|
| 632 | break;
|
---|
[53014] | 633 | case VUSBXFERTYPE_INTR:
|
---|
[62959] | 634 | UsbHdr.u8TransferType = 1;
|
---|
| 635 | break;
|
---|
[53014] | 636 | case VUSBXFERTYPE_CTRL:
|
---|
| 637 | case VUSBXFERTYPE_MSG:
|
---|
[62959] | 638 | UsbHdr.u8TransferType = 2;
|
---|
| 639 | break;
|
---|
[53014] | 640 | default:
|
---|
| 641 | AssertMsgFailed(("invalid transfer type %d\n", pUrb->enmType));
|
---|
| 642 | }
|
---|
| 643 |
|
---|
[53146] | 644 | if (pUrb->enmDir == VUSBDIRECTION_IN)
|
---|
[53060] | 645 | {
|
---|
[53146] | 646 | if (enmEvent == VUSBSNIFFEREVENT_SUBMIT)
|
---|
| 647 | cbDataLength = 0;
|
---|
[53060] | 648 | }
|
---|
[53161] | 649 | else if (pUrb->enmDir == VUSBDIRECTION_OUT)
|
---|
[53060] | 650 | {
|
---|
[53146] | 651 | if ( enmEvent == VUSBSNIFFEREVENT_COMPLETE
|
---|
| 652 | || pUrb->enmType == VUSBXFERTYPE_CTRL
|
---|
| 653 | || pUrb->enmType == VUSBXFERTYPE_MSG)
|
---|
| 654 | cbDataLength = 0;
|
---|
[53060] | 655 | }
|
---|
[65895] | 656 | else if ( pUrb->enmDir == VUSBDIRECTION_SETUP
|
---|
| 657 | && cbDataLength >= sizeof(VUSBSETUP))
|
---|
[53168] | 658 | cbDataLength -= sizeof(VUSBSETUP);
|
---|
[53060] | 659 |
|
---|
[53146] | 660 | Epb.u32CapturedLen = cbCapturedLength + cbDataLength;
|
---|
| 661 | Epb.u32PacketLen = cbCapturedLength + cbUrbLength;
|
---|
[53072] | 662 |
|
---|
[53060] | 663 | UsbHdr.u8EndpointNumber = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0x00);
|
---|
[53014] | 664 | UsbHdr.u8DeviceAddress = pUrb->DstAddress;
|
---|
| 665 | UsbHdr.u16BusId = 0;
|
---|
[53146] | 666 | UsbHdr.u8DataFlag = cbDataLength ? 0 : 1;
|
---|
[53161] | 667 | UsbHdr.u64TimestampSec = u64TimestampEvent / RT_NS_1SEC_64;
|
---|
[53014] | 668 | UsbHdr.u32TimestampUSec = u64TimestampEvent / RT_NS_1US_64 - UsbHdr.u64TimestampSec * RT_US_1SEC;
|
---|
| 669 | UsbHdr.i32Status = pUrb->enmStatus;
|
---|
[53060] | 670 | UsbHdr.u32UrbLength = cbUrbLength;
|
---|
[53146] | 671 | UsbHdr.u32DataLength = cbDataLength + cIsocPkts * sizeof(DumpFileUsbIsoDesc);
|
---|
[53014] | 672 | UsbHdr.i32Interval = 0;
|
---|
| 673 | UsbHdr.i32StartFrame = 0;
|
---|
| 674 | UsbHdr.u32XferFlags = 0;
|
---|
[53146] | 675 | UsbHdr.u32NumDesc = cIsocPkts;
|
---|
[53014] | 676 |
|
---|
[53060] | 677 | if ( (pUrb->enmType == VUSBXFERTYPE_MSG || pUrb->enmType == VUSBXFERTYPE_CTRL)
|
---|
| 678 | && enmEvent == VUSBSNIFFEREVENT_SUBMIT)
|
---|
[53014] | 679 | {
|
---|
| 680 | PVUSBSETUP pSetup = (PVUSBSETUP)pUrb->abData;
|
---|
| 681 |
|
---|
| 682 | UsbHdr.u.UsbSetup.bmRequestType = pSetup->bmRequestType;
|
---|
| 683 | UsbHdr.u.UsbSetup.bRequest = pSetup->bRequest;
|
---|
| 684 | UsbHdr.u.UsbSetup.wValue = pSetup->wValue;
|
---|
| 685 | UsbHdr.u.UsbSetup.wIndex = pSetup->wIndex;
|
---|
| 686 | UsbHdr.u.UsbSetup.wLength = pSetup->wLength;
|
---|
[53060] | 687 | UsbHdr.u8SetupFlag = 0;
|
---|
[53014] | 688 | }
|
---|
[53060] | 689 | else
|
---|
| 690 | UsbHdr.u8SetupFlag = '-'; /* Follow usbmon source here. */
|
---|
[53014] | 691 |
|
---|
[53071] | 692 | /* Write the packet to the capture file. */
|
---|
[62959] | 693 | int rc = vusbSnifferBlockNew(pThis, &Epb.Hdr, sizeof(Epb));
|
---|
[53014] | 694 | if (RT_SUCCESS(rc))
|
---|
[59615] | 695 | rc = vusbSnifferBlockAddData(pThis, &UsbHdr, sizeof(UsbHdr));
|
---|
| 696 |
|
---|
| 697 | /* Add Isochronous descriptors now. */
|
---|
| 698 | for (unsigned i = 0; i < cIsocPkts && RT_SUCCESS(rc); i++)
|
---|
[53071] | 699 | {
|
---|
[59615] | 700 | DumpFileUsbIsoDesc IsoDesc;
|
---|
| 701 | IsoDesc.i32Status = pUrb->aIsocPkts[i].enmStatus;
|
---|
| 702 | IsoDesc.u32Offset = pUrb->aIsocPkts[i].off;
|
---|
| 703 | IsoDesc.u32Len = pUrb->aIsocPkts[i].cb;
|
---|
| 704 | rc = vusbSnifferBlockAddData(pThis, &IsoDesc, sizeof(IsoDesc));
|
---|
| 705 | }
|
---|
[53014] | 706 |
|
---|
[59615] | 707 | /* Record data. */
|
---|
| 708 | if ( RT_SUCCESS(rc)
|
---|
| 709 | && cbDataLength)
|
---|
| 710 | rc = vusbSnifferBlockAddData(pThis, pbData, cbDataLength);
|
---|
[53014] | 711 |
|
---|
[59615] | 712 | if (RT_SUCCESS(rc))
|
---|
| 713 | rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0);
|
---|
[53014] | 714 |
|
---|
[59615] | 715 | if (RT_SUCCESS(rc))
|
---|
| 716 | rc = vusbSnifferBlockCommit(pThis);
|
---|
[53060] | 717 |
|
---|
[53014] | 718 | return rc;
|
---|
| 719 | }
|
---|
| 720 |
|
---|
[59615] | 721 | /**
|
---|
| 722 | * VUSB sniffer format writer.
|
---|
| 723 | */
|
---|
| 724 | const VUSBSNIFFERFMT g_VUsbSnifferFmtPcapNg =
|
---|
| 725 | {
|
---|
| 726 | /** szName */
|
---|
| 727 | "PCAPNG",
|
---|
| 728 | /** pszDesc */
|
---|
| 729 | "PCAP-NG format writer compatible with WireShark",
|
---|
| 730 | /** papszFileExts */
|
---|
| 731 | &s_apszFileExts[0],
|
---|
| 732 | /** cbFmt */
|
---|
| 733 | sizeof(VUSBSNIFFERFMTINT),
|
---|
| 734 | /** pfnInit */
|
---|
[65895] | 735 | vusbSnifferFmtPcapNgInit,
|
---|
[59615] | 736 | /** pfnDestroy */
|
---|
[65895] | 737 | vusbSnifferFmtPcapNgDestroy,
|
---|
[59615] | 738 | /** pfnRecordEvent */
|
---|
[65895] | 739 | vusbSnifferFmtPcapNgRecordEvent
|
---|
[59615] | 740 | };
|
---|
| 741 |
|
---|