xref: /freebsd/contrib/tcpdump/print-usb.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
127df3f5dSRui Paulo /*
227df3f5dSRui Paulo  * Copyright 2009 Bert Vermeulen <bert@biot.com>
327df3f5dSRui Paulo  *
427df3f5dSRui Paulo  * Redistribution and use in source and binary forms, with or without
527df3f5dSRui Paulo  * modification, are permitted provided that: (1) source code distributions
627df3f5dSRui Paulo  * retain the above copyright notice and this paragraph in its entirety, (2)
727df3f5dSRui Paulo  * distributions including binary code include the above copyright notice and
827df3f5dSRui Paulo  * this paragraph in its entirety in the documentation or other materials
927df3f5dSRui Paulo  * provided with the distribution, and (3) all advertising materials mentioning
1027df3f5dSRui Paulo  * features or use of this software display the following acknowledgement:
1127df3f5dSRui Paulo  * ``This product includes software developed by Paolo Abeni.''
1227df3f5dSRui Paulo  * The name of author may not be used to endorse or promote products derived
1327df3f5dSRui Paulo  * from this software without specific prior written permission.
1427df3f5dSRui Paulo  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1527df3f5dSRui Paulo  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1627df3f5dSRui Paulo  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1727df3f5dSRui Paulo  *
1827df3f5dSRui Paulo  * Support for USB packets
1927df3f5dSRui Paulo  *
2027df3f5dSRui Paulo  */
2127df3f5dSRui Paulo 
223340d773SGleb Smirnoff /* \summary: USB printer */
233340d773SGleb Smirnoff 
24ee67461eSJoseph Mingrone #include <config.h>
2527df3f5dSRui Paulo 
26ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
2727df3f5dSRui Paulo 
28ee67461eSJoseph Mingrone #define ND_LONGJMP_FROM_TCHECK
293340d773SGleb Smirnoff #include "netdissect.h"
30ee67461eSJoseph Mingrone #include "extract.h"
3127df3f5dSRui Paulo 
32ee67461eSJoseph Mingrone #ifdef DLT_USB_LINUX
33ee67461eSJoseph Mingrone /*
34ee67461eSJoseph Mingrone  * possible transfer mode
35ee67461eSJoseph Mingrone  */
36ee67461eSJoseph Mingrone #define URB_TRANSFER_IN   0x80
37ee67461eSJoseph Mingrone #define URB_ISOCHRONOUS   0x0
38ee67461eSJoseph Mingrone #define URB_INTERRUPT     0x1
39ee67461eSJoseph Mingrone #define URB_CONTROL       0x2
40ee67461eSJoseph Mingrone #define URB_BULK          0x3
4127df3f5dSRui Paulo 
42ee67461eSJoseph Mingrone /*
43ee67461eSJoseph Mingrone  * possible event type
44ee67461eSJoseph Mingrone  */
45ee67461eSJoseph Mingrone #define URB_SUBMIT        'S'
46ee67461eSJoseph Mingrone #define URB_COMPLETE      'C'
47ee67461eSJoseph Mingrone #define URB_ERROR         'E'
4827df3f5dSRui Paulo 
49ee67461eSJoseph Mingrone /*
50ee67461eSJoseph Mingrone  * USB setup header as defined in USB specification.
51ee67461eSJoseph Mingrone  * Appears at the front of each Control S-type packet in DLT_USB captures.
52ee67461eSJoseph Mingrone  */
53ee67461eSJoseph Mingrone typedef struct _usb_setup {
54ee67461eSJoseph Mingrone 	nd_uint8_t bmRequestType;
55ee67461eSJoseph Mingrone 	nd_uint8_t bRequest;
56ee67461eSJoseph Mingrone 	nd_uint16_t wValue;
57ee67461eSJoseph Mingrone 	nd_uint16_t wIndex;
58ee67461eSJoseph Mingrone 	nd_uint16_t wLength;
59ee67461eSJoseph Mingrone } pcap_usb_setup;
60ee67461eSJoseph Mingrone 
61ee67461eSJoseph Mingrone /*
62ee67461eSJoseph Mingrone  * Information from the URB for Isochronous transfers.
63ee67461eSJoseph Mingrone  */
64ee67461eSJoseph Mingrone typedef struct _iso_rec {
65ee67461eSJoseph Mingrone 	nd_int32_t	error_count;
66ee67461eSJoseph Mingrone 	nd_int32_t	numdesc;
67ee67461eSJoseph Mingrone } iso_rec;
68ee67461eSJoseph Mingrone 
69ee67461eSJoseph Mingrone /*
70ee67461eSJoseph Mingrone  * Header prepended by linux kernel to each event.
71ee67461eSJoseph Mingrone  * Appears at the front of each packet in DLT_USB_LINUX captures.
72ee67461eSJoseph Mingrone  */
73ee67461eSJoseph Mingrone typedef struct _usb_header {
74ee67461eSJoseph Mingrone 	nd_uint64_t id;
75ee67461eSJoseph Mingrone 	nd_uint8_t event_type;
76ee67461eSJoseph Mingrone 	nd_uint8_t transfer_type;
77ee67461eSJoseph Mingrone 	nd_uint8_t endpoint_number;
78ee67461eSJoseph Mingrone 	nd_uint8_t device_address;
79ee67461eSJoseph Mingrone 	nd_uint16_t bus_id;
80ee67461eSJoseph Mingrone 	nd_uint8_t setup_flag;/*if !=0 the urb setup header is not present*/
81ee67461eSJoseph Mingrone 	nd_uint8_t data_flag; /*if !=0 no urb data is present*/
82ee67461eSJoseph Mingrone 	nd_int64_t ts_sec;
83ee67461eSJoseph Mingrone 	nd_int32_t ts_usec;
84ee67461eSJoseph Mingrone 	nd_int32_t status;
85ee67461eSJoseph Mingrone 	nd_uint32_t urb_len;
86ee67461eSJoseph Mingrone 	nd_uint32_t data_len; /* amount of urb data really present in this event*/
87ee67461eSJoseph Mingrone 	pcap_usb_setup setup;
88ee67461eSJoseph Mingrone } pcap_usb_header;
89ee67461eSJoseph Mingrone 
90ee67461eSJoseph Mingrone /*
91ee67461eSJoseph Mingrone  * Header prepended by linux kernel to each event for the 2.6.31
92ee67461eSJoseph Mingrone  * and later kernels; for the 2.6.21 through 2.6.30 kernels, the
93ee67461eSJoseph Mingrone  * "iso_rec" information, and the fields starting with "interval"
94ee67461eSJoseph Mingrone  * are zeroed-out padding fields.
95ee67461eSJoseph Mingrone  *
96ee67461eSJoseph Mingrone  * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures.
97ee67461eSJoseph Mingrone  */
98ee67461eSJoseph Mingrone typedef struct _usb_header_mmapped {
99ee67461eSJoseph Mingrone 	nd_uint64_t id;
100ee67461eSJoseph Mingrone 	nd_uint8_t event_type;
101ee67461eSJoseph Mingrone 	nd_uint8_t transfer_type;
102ee67461eSJoseph Mingrone 	nd_uint8_t endpoint_number;
103ee67461eSJoseph Mingrone 	nd_uint8_t device_address;
104ee67461eSJoseph Mingrone 	nd_uint16_t bus_id;
105ee67461eSJoseph Mingrone 	nd_uint8_t setup_flag;/*if !=0 the urb setup header is not present*/
106ee67461eSJoseph Mingrone 	nd_uint8_t data_flag; /*if !=0 no urb data is present*/
107ee67461eSJoseph Mingrone 	nd_int64_t ts_sec;
108ee67461eSJoseph Mingrone 	nd_int32_t ts_usec;
109ee67461eSJoseph Mingrone 	nd_int32_t status;
110ee67461eSJoseph Mingrone 	nd_uint32_t urb_len;
111ee67461eSJoseph Mingrone 	nd_uint32_t data_len; /* amount of urb data really present in this event*/
112ee67461eSJoseph Mingrone 	union {
113ee67461eSJoseph Mingrone 		pcap_usb_setup setup;
114ee67461eSJoseph Mingrone 		iso_rec iso;
115ee67461eSJoseph Mingrone 	} s;
116ee67461eSJoseph Mingrone 	nd_int32_t interval;	/* for Interrupt and Isochronous events */
117ee67461eSJoseph Mingrone 	nd_int32_t start_frame;	/* for Isochronous events */
118ee67461eSJoseph Mingrone 	nd_uint32_t xfer_flags;	/* copy of URB's transfer flags */
119ee67461eSJoseph Mingrone 	nd_uint32_t ndesc;	/* number of isochronous descriptors */
120ee67461eSJoseph Mingrone } pcap_usb_header_mmapped;
121ee67461eSJoseph Mingrone 
122ee67461eSJoseph Mingrone /*
123ee67461eSJoseph Mingrone  * Isochronous descriptors; for isochronous transfers there might be
124ee67461eSJoseph Mingrone  * one or more of these at the beginning of the packet data.  The
125ee67461eSJoseph Mingrone  * number of descriptors is given by the "ndesc" field in the header;
126ee67461eSJoseph Mingrone  * as indicated, in older kernels that don't put the descriptors at
127ee67461eSJoseph Mingrone  * the beginning of the packet, that field is zeroed out, so that field
128ee67461eSJoseph Mingrone  * can be trusted even in captures from older kernels.
129ee67461eSJoseph Mingrone  */
130ee67461eSJoseph Mingrone typedef struct _usb_isodesc {
131ee67461eSJoseph Mingrone 	nd_int32_t	status;
132ee67461eSJoseph Mingrone 	nd_uint32_t	offset;
133ee67461eSJoseph Mingrone 	nd_uint32_t	len;
134ee67461eSJoseph Mingrone 	nd_byte		pad[4];
135ee67461eSJoseph Mingrone } usb_isodesc;
136ee67461eSJoseph Mingrone 
1373c602fabSXin LI 
13827df3f5dSRui Paulo /* returns direction: 1=inbound 2=outbound -1=invalid */
13927df3f5dSRui Paulo static int
get_direction(int transfer_type,int event_type)14027df3f5dSRui Paulo get_direction(int transfer_type, int event_type)
14127df3f5dSRui Paulo {
14227df3f5dSRui Paulo 	int direction;
14327df3f5dSRui Paulo 
14427df3f5dSRui Paulo 	direction = -1;
14527df3f5dSRui Paulo 	switch(transfer_type){
14627df3f5dSRui Paulo 	case URB_BULK:
14727df3f5dSRui Paulo 	case URB_CONTROL:
14827df3f5dSRui Paulo 	case URB_ISOCHRONOUS:
149*0a7e5f1fSJoseph Mingrone 		switch(event_type) {
15027df3f5dSRui Paulo 		case URB_SUBMIT:
15127df3f5dSRui Paulo 			direction = 2;
15227df3f5dSRui Paulo 			break;
15327df3f5dSRui Paulo 		case URB_COMPLETE:
15427df3f5dSRui Paulo 		case URB_ERROR:
15527df3f5dSRui Paulo 			direction = 1;
15627df3f5dSRui Paulo 			break;
15727df3f5dSRui Paulo 		default:
15827df3f5dSRui Paulo 			direction = -1;
15927df3f5dSRui Paulo 		}
16027df3f5dSRui Paulo 		break;
16127df3f5dSRui Paulo 	case URB_INTERRUPT:
162*0a7e5f1fSJoseph Mingrone 		switch(event_type) {
16327df3f5dSRui Paulo 		case URB_SUBMIT:
16427df3f5dSRui Paulo 			direction = 1;
16527df3f5dSRui Paulo 			break;
16627df3f5dSRui Paulo 		case URB_COMPLETE:
16727df3f5dSRui Paulo 		case URB_ERROR:
16827df3f5dSRui Paulo 			direction = 2;
16927df3f5dSRui Paulo 			break;
17027df3f5dSRui Paulo 		default:
17127df3f5dSRui Paulo 			direction = -1;
17227df3f5dSRui Paulo 		}
17327df3f5dSRui Paulo 		break;
17427df3f5dSRui Paulo 	 default:
17527df3f5dSRui Paulo 		direction = -1;
17627df3f5dSRui Paulo 	}
17727df3f5dSRui Paulo 
17827df3f5dSRui Paulo 	return direction;
17927df3f5dSRui Paulo }
18027df3f5dSRui Paulo 
18127df3f5dSRui Paulo static void
usb_header_print(netdissect_options * ndo,const pcap_usb_header * uh)1823c602fabSXin LI usb_header_print(netdissect_options *ndo, const pcap_usb_header *uh)
18327df3f5dSRui Paulo {
18427df3f5dSRui Paulo 	int direction;
185ee67461eSJoseph Mingrone 	uint8_t transfer_type, event_type;
18627df3f5dSRui Paulo 
187ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "usb";
188ee67461eSJoseph Mingrone 
189ee67461eSJoseph Mingrone 	nd_print_protocol_caps(ndo);
190ee67461eSJoseph Mingrone 	if (ndo->ndo_qflag)
191ee67461eSJoseph Mingrone 		return;
192ee67461eSJoseph Mingrone 
193ee67461eSJoseph Mingrone 	ND_PRINT(" ");
194ee67461eSJoseph Mingrone 	transfer_type = GET_U_1(uh->transfer_type);
195*0a7e5f1fSJoseph Mingrone 	switch(transfer_type) {
19627df3f5dSRui Paulo 		case URB_ISOCHRONOUS:
197ee67461eSJoseph Mingrone 			ND_PRINT("ISOCHRONOUS");
19827df3f5dSRui Paulo 			break;
19927df3f5dSRui Paulo 		case URB_INTERRUPT:
200ee67461eSJoseph Mingrone 			ND_PRINT("INTERRUPT");
20127df3f5dSRui Paulo 			break;
20227df3f5dSRui Paulo 		case URB_CONTROL:
203ee67461eSJoseph Mingrone 			ND_PRINT("CONTROL");
20427df3f5dSRui Paulo 			break;
20527df3f5dSRui Paulo 		case URB_BULK:
206ee67461eSJoseph Mingrone 			ND_PRINT("BULK");
20727df3f5dSRui Paulo 			break;
20827df3f5dSRui Paulo 		default:
209ee67461eSJoseph Mingrone 			ND_PRINT(" ?");
21027df3f5dSRui Paulo 	}
21127df3f5dSRui Paulo 
212ee67461eSJoseph Mingrone 	event_type = GET_U_1(uh->event_type);
213*0a7e5f1fSJoseph Mingrone 	switch(event_type) {
21427df3f5dSRui Paulo 		case URB_SUBMIT:
215ee67461eSJoseph Mingrone 			ND_PRINT(" SUBMIT");
21627df3f5dSRui Paulo 			break;
21727df3f5dSRui Paulo 		case URB_COMPLETE:
218ee67461eSJoseph Mingrone 			ND_PRINT(" COMPLETE");
21927df3f5dSRui Paulo 			break;
22027df3f5dSRui Paulo 		case URB_ERROR:
221ee67461eSJoseph Mingrone 			ND_PRINT(" ERROR");
22227df3f5dSRui Paulo 			break;
22327df3f5dSRui Paulo 		default:
224ee67461eSJoseph Mingrone 			ND_PRINT(" ?");
22527df3f5dSRui Paulo 	}
22627df3f5dSRui Paulo 
227ee67461eSJoseph Mingrone 	direction = get_direction(transfer_type, event_type);
22827df3f5dSRui Paulo 	if(direction == 1)
229ee67461eSJoseph Mingrone 		ND_PRINT(" from");
23027df3f5dSRui Paulo 	else if(direction == 2)
231ee67461eSJoseph Mingrone 		ND_PRINT(" to");
232ee67461eSJoseph Mingrone 	ND_PRINT(" %u:%u:%u", GET_HE_U_2(uh->bus_id),
233ee67461eSJoseph Mingrone 		 GET_U_1(uh->device_address),
234ee67461eSJoseph Mingrone 		 GET_U_1(uh->endpoint_number) & 0x7f);
23527df3f5dSRui Paulo }
23627df3f5dSRui Paulo 
23727df3f5dSRui Paulo /*
23827df3f5dSRui Paulo  * This is the top level routine of the printer for captures with a
23927df3f5dSRui Paulo  * 48-byte header.
24027df3f5dSRui Paulo  *
24127df3f5dSRui Paulo  * 'p' points to the header of the packet, 'h->ts' is the timestamp,
24227df3f5dSRui Paulo  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
24327df3f5dSRui Paulo  * is the number of bytes actually captured.
24427df3f5dSRui Paulo  */
245ee67461eSJoseph Mingrone void
usb_linux_48_byte_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h _U_,const u_char * p)246ee67461eSJoseph Mingrone usb_linux_48_byte_if_print(netdissect_options *ndo,
247ee67461eSJoseph Mingrone                            const struct pcap_pkthdr *h _U_, const u_char *p)
24827df3f5dSRui Paulo {
249ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "usb_linux_48_byte";
250ee67461eSJoseph Mingrone 	ND_TCHECK_LEN(p, sizeof(pcap_usb_header));
251ee67461eSJoseph Mingrone 	ndo->ndo_ll_hdr_len += sizeof (pcap_usb_header);
25227df3f5dSRui Paulo 
2533c602fabSXin LI 	usb_header_print(ndo, (const pcap_usb_header *) p);
25427df3f5dSRui Paulo }
25527df3f5dSRui Paulo 
25627df3f5dSRui Paulo #ifdef DLT_USB_LINUX_MMAPPED
25727df3f5dSRui Paulo /*
25827df3f5dSRui Paulo  * This is the top level routine of the printer for captures with a
25927df3f5dSRui Paulo  * 64-byte header.
26027df3f5dSRui Paulo  *
26127df3f5dSRui Paulo  * 'p' points to the header of the packet, 'h->ts' is the timestamp,
26227df3f5dSRui Paulo  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
26327df3f5dSRui Paulo  * is the number of bytes actually captured.
26427df3f5dSRui Paulo  */
265ee67461eSJoseph Mingrone void
usb_linux_64_byte_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h _U_,const u_char * p)266ee67461eSJoseph Mingrone usb_linux_64_byte_if_print(netdissect_options *ndo,
267ee67461eSJoseph Mingrone                            const struct pcap_pkthdr *h _U_, const u_char *p)
26827df3f5dSRui Paulo {
269ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "usb_linux_64_byte";
270ee67461eSJoseph Mingrone 	ND_TCHECK_LEN(p, sizeof(pcap_usb_header_mmapped));
271ee67461eSJoseph Mingrone 	ndo->ndo_ll_hdr_len += sizeof (pcap_usb_header_mmapped);
27227df3f5dSRui Paulo 
2733c602fabSXin LI 	usb_header_print(ndo, (const pcap_usb_header *) p);
27427df3f5dSRui Paulo }
27527df3f5dSRui Paulo #endif /* DLT_USB_LINUX_MMAPPED */
27627df3f5dSRui Paulo 
277ee67461eSJoseph Mingrone #endif /* DLT_USB_LINUX */
27827df3f5dSRui Paulo 
279