xref: /dragonfly/contrib/tcpdump/print-usb.c (revision ed775ee7)
127bfbee1SPeter Avalos /*
227bfbee1SPeter Avalos  * Copyright 2009 Bert Vermeulen <bert@biot.com>
327bfbee1SPeter Avalos  *
427bfbee1SPeter Avalos  * Redistribution and use in source and binary forms, with or without
527bfbee1SPeter Avalos  * modification, are permitted provided that: (1) source code distributions
627bfbee1SPeter Avalos  * retain the above copyright notice and this paragraph in its entirety, (2)
727bfbee1SPeter Avalos  * distributions including binary code include the above copyright notice and
827bfbee1SPeter Avalos  * this paragraph in its entirety in the documentation or other materials
927bfbee1SPeter Avalos  * provided with the distribution, and (3) all advertising materials mentioning
1027bfbee1SPeter Avalos  * features or use of this software display the following acknowledgement:
1127bfbee1SPeter Avalos  * ``This product includes software developed by Paolo Abeni.''
1227bfbee1SPeter Avalos  * The name of author may not be used to endorse or promote products derived
1327bfbee1SPeter Avalos  * from this software without specific prior written permission.
1427bfbee1SPeter Avalos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1527bfbee1SPeter Avalos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1627bfbee1SPeter Avalos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1727bfbee1SPeter Avalos  *
1827bfbee1SPeter Avalos  * Support for USB packets
1927bfbee1SPeter Avalos  *
2027bfbee1SPeter Avalos  */
2127bfbee1SPeter Avalos 
22411677aeSAaron LI /* \summary: USB printer */
23411677aeSAaron LI 
2427bfbee1SPeter Avalos #ifdef HAVE_CONFIG_H
25*ed775ee7SAntonio Huete Jimenez #include <config.h>
2627bfbee1SPeter Avalos #endif
2727bfbee1SPeter Avalos 
28*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
2927bfbee1SPeter Avalos 
30*ed775ee7SAntonio Huete Jimenez #define ND_LONGJMP_FROM_TCHECK
31411677aeSAaron LI #include "netdissect.h"
32*ed775ee7SAntonio Huete Jimenez #include "extract.h"
3327bfbee1SPeter Avalos 
34*ed775ee7SAntonio Huete Jimenez #ifdef DLT_USB_LINUX
35*ed775ee7SAntonio Huete Jimenez /*
36*ed775ee7SAntonio Huete Jimenez  * possible transfer mode
37*ed775ee7SAntonio Huete Jimenez  */
38*ed775ee7SAntonio Huete Jimenez #define URB_TRANSFER_IN   0x80
39*ed775ee7SAntonio Huete Jimenez #define URB_ISOCHRONOUS   0x0
40*ed775ee7SAntonio Huete Jimenez #define URB_INTERRUPT     0x1
41*ed775ee7SAntonio Huete Jimenez #define URB_CONTROL       0x2
42*ed775ee7SAntonio Huete Jimenez #define URB_BULK          0x3
4327bfbee1SPeter Avalos 
44*ed775ee7SAntonio Huete Jimenez /*
45*ed775ee7SAntonio Huete Jimenez  * possible event type
46*ed775ee7SAntonio Huete Jimenez  */
47*ed775ee7SAntonio Huete Jimenez #define URB_SUBMIT        'S'
48*ed775ee7SAntonio Huete Jimenez #define URB_COMPLETE      'C'
49*ed775ee7SAntonio Huete Jimenez #define URB_ERROR         'E'
5027bfbee1SPeter Avalos 
51*ed775ee7SAntonio Huete Jimenez /*
52*ed775ee7SAntonio Huete Jimenez  * USB setup header as defined in USB specification.
53*ed775ee7SAntonio Huete Jimenez  * Appears at the front of each Control S-type packet in DLT_USB captures.
54*ed775ee7SAntonio Huete Jimenez  */
55*ed775ee7SAntonio Huete Jimenez typedef struct _usb_setup {
56*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t bmRequestType;
57*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t bRequest;
58*ed775ee7SAntonio Huete Jimenez 	nd_uint16_t wValue;
59*ed775ee7SAntonio Huete Jimenez 	nd_uint16_t wIndex;
60*ed775ee7SAntonio Huete Jimenez 	nd_uint16_t wLength;
61*ed775ee7SAntonio Huete Jimenez } pcap_usb_setup;
62*ed775ee7SAntonio Huete Jimenez 
63*ed775ee7SAntonio Huete Jimenez /*
64*ed775ee7SAntonio Huete Jimenez  * Information from the URB for Isochronous transfers.
65*ed775ee7SAntonio Huete Jimenez  */
66*ed775ee7SAntonio Huete Jimenez typedef struct _iso_rec {
67*ed775ee7SAntonio Huete Jimenez 	nd_int32_t	error_count;
68*ed775ee7SAntonio Huete Jimenez 	nd_int32_t	numdesc;
69*ed775ee7SAntonio Huete Jimenez } iso_rec;
70*ed775ee7SAntonio Huete Jimenez 
71*ed775ee7SAntonio Huete Jimenez /*
72*ed775ee7SAntonio Huete Jimenez  * Header prepended by linux kernel to each event.
73*ed775ee7SAntonio Huete Jimenez  * Appears at the front of each packet in DLT_USB_LINUX captures.
74*ed775ee7SAntonio Huete Jimenez  */
75*ed775ee7SAntonio Huete Jimenez typedef struct _usb_header {
76*ed775ee7SAntonio Huete Jimenez 	nd_uint64_t id;
77*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t event_type;
78*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t transfer_type;
79*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t endpoint_number;
80*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t device_address;
81*ed775ee7SAntonio Huete Jimenez 	nd_uint16_t bus_id;
82*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t setup_flag;/*if !=0 the urb setup header is not present*/
83*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t data_flag; /*if !=0 no urb data is present*/
84*ed775ee7SAntonio Huete Jimenez 	nd_int64_t ts_sec;
85*ed775ee7SAntonio Huete Jimenez 	nd_int32_t ts_usec;
86*ed775ee7SAntonio Huete Jimenez 	nd_int32_t status;
87*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t urb_len;
88*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t data_len; /* amount of urb data really present in this event*/
89*ed775ee7SAntonio Huete Jimenez 	pcap_usb_setup setup;
90*ed775ee7SAntonio Huete Jimenez } pcap_usb_header;
91*ed775ee7SAntonio Huete Jimenez 
92*ed775ee7SAntonio Huete Jimenez /*
93*ed775ee7SAntonio Huete Jimenez  * Header prepended by linux kernel to each event for the 2.6.31
94*ed775ee7SAntonio Huete Jimenez  * and later kernels; for the 2.6.21 through 2.6.30 kernels, the
95*ed775ee7SAntonio Huete Jimenez  * "iso_rec" information, and the fields starting with "interval"
96*ed775ee7SAntonio Huete Jimenez  * are zeroed-out padding fields.
97*ed775ee7SAntonio Huete Jimenez  *
98*ed775ee7SAntonio Huete Jimenez  * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures.
99*ed775ee7SAntonio Huete Jimenez  */
100*ed775ee7SAntonio Huete Jimenez typedef struct _usb_header_mmapped {
101*ed775ee7SAntonio Huete Jimenez 	nd_uint64_t id;
102*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t event_type;
103*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t transfer_type;
104*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t endpoint_number;
105*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t device_address;
106*ed775ee7SAntonio Huete Jimenez 	nd_uint16_t bus_id;
107*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t setup_flag;/*if !=0 the urb setup header is not present*/
108*ed775ee7SAntonio Huete Jimenez 	nd_uint8_t data_flag; /*if !=0 no urb data is present*/
109*ed775ee7SAntonio Huete Jimenez 	nd_int64_t ts_sec;
110*ed775ee7SAntonio Huete Jimenez 	nd_int32_t ts_usec;
111*ed775ee7SAntonio Huete Jimenez 	nd_int32_t status;
112*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t urb_len;
113*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t data_len; /* amount of urb data really present in this event*/
114*ed775ee7SAntonio Huete Jimenez 	union {
115*ed775ee7SAntonio Huete Jimenez 		pcap_usb_setup setup;
116*ed775ee7SAntonio Huete Jimenez 		iso_rec iso;
117*ed775ee7SAntonio Huete Jimenez 	} s;
118*ed775ee7SAntonio Huete Jimenez 	nd_int32_t interval;	/* for Interrupt and Isochronous events */
119*ed775ee7SAntonio Huete Jimenez 	nd_int32_t start_frame;	/* for Isochronous events */
120*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t xfer_flags;	/* copy of URB's transfer flags */
121*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t ndesc;	/* number of isochronous descriptors */
122*ed775ee7SAntonio Huete Jimenez } pcap_usb_header_mmapped;
123*ed775ee7SAntonio Huete Jimenez 
124*ed775ee7SAntonio Huete Jimenez /*
125*ed775ee7SAntonio Huete Jimenez  * Isochronous descriptors; for isochronous transfers there might be
126*ed775ee7SAntonio Huete Jimenez  * one or more of these at the beginning of the packet data.  The
127*ed775ee7SAntonio Huete Jimenez  * number of descriptors is given by the "ndesc" field in the header;
128*ed775ee7SAntonio Huete Jimenez  * as indicated, in older kernels that don't put the descriptors at
129*ed775ee7SAntonio Huete Jimenez  * the beginning of the packet, that field is zeroed out, so that field
130*ed775ee7SAntonio Huete Jimenez  * can be trusted even in captures from older kernels.
131*ed775ee7SAntonio Huete Jimenez  */
132*ed775ee7SAntonio Huete Jimenez typedef struct _usb_isodesc {
133*ed775ee7SAntonio Huete Jimenez 	nd_int32_t	status;
134*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t	offset;
135*ed775ee7SAntonio Huete Jimenez 	nd_uint32_t	len;
136*ed775ee7SAntonio Huete Jimenez 	nd_byte		pad[4];
137*ed775ee7SAntonio Huete Jimenez } usb_isodesc;
138*ed775ee7SAntonio Huete Jimenez 
139411677aeSAaron LI 
14027bfbee1SPeter Avalos /* returns direction: 1=inbound 2=outbound -1=invalid */
14127bfbee1SPeter Avalos static int
get_direction(int transfer_type,int event_type)14227bfbee1SPeter Avalos get_direction(int transfer_type, int event_type)
14327bfbee1SPeter Avalos {
14427bfbee1SPeter Avalos 	int direction;
14527bfbee1SPeter Avalos 
14627bfbee1SPeter Avalos 	direction = -1;
14727bfbee1SPeter Avalos 	switch(transfer_type){
14827bfbee1SPeter Avalos 	case URB_BULK:
14927bfbee1SPeter Avalos 	case URB_CONTROL:
15027bfbee1SPeter Avalos 	case URB_ISOCHRONOUS:
15127bfbee1SPeter Avalos 		switch(event_type)
15227bfbee1SPeter Avalos 		{
15327bfbee1SPeter Avalos 		case URB_SUBMIT:
15427bfbee1SPeter Avalos 			direction = 2;
15527bfbee1SPeter Avalos 			break;
15627bfbee1SPeter Avalos 		case URB_COMPLETE:
15727bfbee1SPeter Avalos 		case URB_ERROR:
15827bfbee1SPeter Avalos 			direction = 1;
15927bfbee1SPeter Avalos 			break;
16027bfbee1SPeter Avalos 		default:
16127bfbee1SPeter Avalos 			direction = -1;
16227bfbee1SPeter Avalos 		}
16327bfbee1SPeter Avalos 		break;
16427bfbee1SPeter Avalos 	case URB_INTERRUPT:
16527bfbee1SPeter Avalos 		switch(event_type)
16627bfbee1SPeter Avalos 		{
16727bfbee1SPeter Avalos 		case URB_SUBMIT:
16827bfbee1SPeter Avalos 			direction = 1;
16927bfbee1SPeter Avalos 			break;
17027bfbee1SPeter Avalos 		case URB_COMPLETE:
17127bfbee1SPeter Avalos 		case URB_ERROR:
17227bfbee1SPeter Avalos 			direction = 2;
17327bfbee1SPeter Avalos 			break;
17427bfbee1SPeter Avalos 		default:
17527bfbee1SPeter Avalos 			direction = -1;
17627bfbee1SPeter Avalos 		}
17727bfbee1SPeter Avalos 		break;
17827bfbee1SPeter Avalos 	 default:
17927bfbee1SPeter Avalos 		direction = -1;
18027bfbee1SPeter Avalos 	}
18127bfbee1SPeter Avalos 
18227bfbee1SPeter Avalos 	return direction;
18327bfbee1SPeter Avalos }
18427bfbee1SPeter Avalos 
18527bfbee1SPeter Avalos static void
usb_header_print(netdissect_options * ndo,const pcap_usb_header * uh)186411677aeSAaron LI usb_header_print(netdissect_options *ndo, const pcap_usb_header *uh)
18727bfbee1SPeter Avalos {
18827bfbee1SPeter Avalos 	int direction;
189*ed775ee7SAntonio Huete Jimenez 	uint8_t transfer_type, event_type;
19027bfbee1SPeter Avalos 
191*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "usb";
192*ed775ee7SAntonio Huete Jimenez 
193*ed775ee7SAntonio Huete Jimenez 	nd_print_protocol_caps(ndo);
194*ed775ee7SAntonio Huete Jimenez 	if (ndo->ndo_qflag)
195*ed775ee7SAntonio Huete Jimenez 		return;
196*ed775ee7SAntonio Huete Jimenez 
197*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(" ");
198*ed775ee7SAntonio Huete Jimenez 	transfer_type = GET_U_1(uh->transfer_type);
199*ed775ee7SAntonio Huete Jimenez 	switch(transfer_type)
20027bfbee1SPeter Avalos 	{
20127bfbee1SPeter Avalos 		case URB_ISOCHRONOUS:
202*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("ISOCHRONOUS");
20327bfbee1SPeter Avalos 			break;
20427bfbee1SPeter Avalos 		case URB_INTERRUPT:
205*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("INTERRUPT");
20627bfbee1SPeter Avalos 			break;
20727bfbee1SPeter Avalos 		case URB_CONTROL:
208*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("CONTROL");
20927bfbee1SPeter Avalos 			break;
21027bfbee1SPeter Avalos 		case URB_BULK:
211*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("BULK");
21227bfbee1SPeter Avalos 			break;
21327bfbee1SPeter Avalos 		default:
214*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" ?");
21527bfbee1SPeter Avalos 	}
21627bfbee1SPeter Avalos 
217*ed775ee7SAntonio Huete Jimenez 	event_type = GET_U_1(uh->event_type);
218*ed775ee7SAntonio Huete Jimenez 	switch(event_type)
21927bfbee1SPeter Avalos 	{
22027bfbee1SPeter Avalos 		case URB_SUBMIT:
221*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" SUBMIT");
22227bfbee1SPeter Avalos 			break;
22327bfbee1SPeter Avalos 		case URB_COMPLETE:
224*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" COMPLETE");
22527bfbee1SPeter Avalos 			break;
22627bfbee1SPeter Avalos 		case URB_ERROR:
227*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" ERROR");
22827bfbee1SPeter Avalos 			break;
22927bfbee1SPeter Avalos 		default:
230*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" ?");
23127bfbee1SPeter Avalos 	}
23227bfbee1SPeter Avalos 
233*ed775ee7SAntonio Huete Jimenez 	direction = get_direction(transfer_type, event_type);
23427bfbee1SPeter Avalos 	if(direction == 1)
235*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" from");
23627bfbee1SPeter Avalos 	else if(direction == 2)
237*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" to");
238*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(" %u:%u:%u", GET_HE_U_2(uh->bus_id),
239*ed775ee7SAntonio Huete Jimenez 		 GET_U_1(uh->device_address),
240*ed775ee7SAntonio Huete Jimenez 		 GET_U_1(uh->endpoint_number) & 0x7f);
24127bfbee1SPeter Avalos }
24227bfbee1SPeter Avalos 
24327bfbee1SPeter Avalos /*
24427bfbee1SPeter Avalos  * This is the top level routine of the printer for captures with a
24527bfbee1SPeter Avalos  * 48-byte header.
24627bfbee1SPeter Avalos  *
24727bfbee1SPeter Avalos  * 'p' points to the header of the packet, 'h->ts' is the timestamp,
24827bfbee1SPeter Avalos  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
24927bfbee1SPeter Avalos  * is the number of bytes actually captured.
25027bfbee1SPeter Avalos  */
251*ed775ee7SAntonio Huete Jimenez void
usb_linux_48_byte_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h _U_,const u_char * p)252*ed775ee7SAntonio Huete Jimenez usb_linux_48_byte_if_print(netdissect_options *ndo,
253*ed775ee7SAntonio Huete Jimenez                            const struct pcap_pkthdr *h _U_, const u_char *p)
25427bfbee1SPeter Avalos {
255*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "usb_linux_48_byte";
256*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(p, sizeof(pcap_usb_header));
257*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_ll_hdr_len += sizeof (pcap_usb_header);
25827bfbee1SPeter Avalos 
259411677aeSAaron LI 	usb_header_print(ndo, (const pcap_usb_header *) p);
26027bfbee1SPeter Avalos }
26127bfbee1SPeter Avalos 
26227bfbee1SPeter Avalos #ifdef DLT_USB_LINUX_MMAPPED
26327bfbee1SPeter Avalos /*
26427bfbee1SPeter Avalos  * This is the top level routine of the printer for captures with a
26527bfbee1SPeter Avalos  * 64-byte header.
26627bfbee1SPeter Avalos  *
26727bfbee1SPeter Avalos  * 'p' points to the header of the packet, 'h->ts' is the timestamp,
26827bfbee1SPeter Avalos  * 'h->len' is the length of the packet off the wire, and 'h->caplen'
26927bfbee1SPeter Avalos  * is the number of bytes actually captured.
27027bfbee1SPeter Avalos  */
271*ed775ee7SAntonio Huete Jimenez void
usb_linux_64_byte_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h _U_,const u_char * p)272*ed775ee7SAntonio Huete Jimenez usb_linux_64_byte_if_print(netdissect_options *ndo,
273*ed775ee7SAntonio Huete Jimenez                            const struct pcap_pkthdr *h _U_, const u_char *p)
27427bfbee1SPeter Avalos {
275*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "usb_linux_64_byte";
276*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_LEN(p, sizeof(pcap_usb_header_mmapped));
277*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_ll_hdr_len += sizeof (pcap_usb_header_mmapped);
27827bfbee1SPeter Avalos 
279411677aeSAaron LI 	usb_header_print(ndo, (const pcap_usb_header *) p);
28027bfbee1SPeter Avalos }
28127bfbee1SPeter Avalos #endif /* DLT_USB_LINUX_MMAPPED */
28227bfbee1SPeter Avalos 
283*ed775ee7SAntonio Huete Jimenez #endif /* DLT_USB_LINUX */
28427bfbee1SPeter Avalos 
285