VirtualBox

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

Last change on this file since 55043 was 54568, checked in by vboxsync, 10 years ago

In case we need it later.

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