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