VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/VUSBSniffer.cpp@ 58466

Last change on this file since 58466 was 57526, checked in by vboxsync, 9 years ago

VUSBSniffer: Fix small memory leak

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette