1*05b00f60SXin Li /*
2*05b00f60SXin Li * Copyright (C) Arnaldo Carvalho de Melo 2004
3*05b00f60SXin Li * Copyright (C) Ian McDonald 2005
4*05b00f60SXin Li * Copyright (C) Yoshifumi Nishida 2005
5*05b00f60SXin Li *
6*05b00f60SXin Li * This software may be distributed either under the terms of the
7*05b00f60SXin Li * BSD-style license that accompanies tcpdump or the GNU GPL version 2
8*05b00f60SXin Li */
9*05b00f60SXin Li
10*05b00f60SXin Li /* \summary: Datagram Congestion Control Protocol (DCCP) printer */
11*05b00f60SXin Li
12*05b00f60SXin Li /* specification: RFC 4340 */
13*05b00f60SXin Li
14*05b00f60SXin Li #ifdef HAVE_CONFIG_H
15*05b00f60SXin Li #include <config.h>
16*05b00f60SXin Li #endif
17*05b00f60SXin Li
18*05b00f60SXin Li #include "netdissect-stdinc.h"
19*05b00f60SXin Li
20*05b00f60SXin Li #include "netdissect.h"
21*05b00f60SXin Li #include "addrtoname.h"
22*05b00f60SXin Li #include "extract.h"
23*05b00f60SXin Li #include "ip.h"
24*05b00f60SXin Li #include "ip6.h"
25*05b00f60SXin Li #include "ipproto.h"
26*05b00f60SXin Li
27*05b00f60SXin Li /* RFC4340: Datagram Congestion Control Protocol (DCCP) */
28*05b00f60SXin Li
29*05b00f60SXin Li /**
30*05b00f60SXin Li * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit
31*05b00f60SXin Li * sequence number
32*05b00f60SXin Li *
33*05b00f60SXin Li * @dccph_sport - Relevant port on the endpoint that sent this packet
34*05b00f60SXin Li * @dccph_dport - Relevant port on the other endpoint
35*05b00f60SXin Li * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
36*05b00f60SXin Li * @dccph_ccval - Used by the HC-Sender CCID
37*05b00f60SXin Li * @dccph_cscov - Parts of the packet that are covered by the Checksum field
38*05b00f60SXin Li * @dccph_checksum - Internet checksum, depends on dccph_cscov
39*05b00f60SXin Li * @dccph_x - 0 = 24 bit sequence number, 1 = 48
40*05b00f60SXin Li * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
41*05b00f60SXin Li * @dccph_seq - 24-bit sequence number
42*05b00f60SXin Li */
43*05b00f60SXin Li struct dccp_hdr {
44*05b00f60SXin Li nd_uint16_t dccph_sport,
45*05b00f60SXin Li dccph_dport;
46*05b00f60SXin Li nd_uint8_t dccph_doff;
47*05b00f60SXin Li nd_uint8_t dccph_ccval_cscov;
48*05b00f60SXin Li nd_uint16_t dccph_checksum;
49*05b00f60SXin Li nd_uint8_t dccph_xtr;
50*05b00f60SXin Li nd_uint24_t dccph_seq;
51*05b00f60SXin Li };
52*05b00f60SXin Li
53*05b00f60SXin Li /**
54*05b00f60SXin Li * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit
55*05b00f60SXin Li * sequence number
56*05b00f60SXin Li *
57*05b00f60SXin Li * @dccph_sport - Relevant port on the endpoint that sent this packet
58*05b00f60SXin Li * @dccph_dport - Relevant port on the other endpoint
59*05b00f60SXin Li * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
60*05b00f60SXin Li * @dccph_ccval - Used by the HC-Sender CCID
61*05b00f60SXin Li * @dccph_cscov - Parts of the packet that are covered by the Checksum field
62*05b00f60SXin Li * @dccph_checksum - Internet checksum, depends on dccph_cscov
63*05b00f60SXin Li * @dccph_x - 0 = 24 bit sequence number, 1 = 48
64*05b00f60SXin Li * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
65*05b00f60SXin Li * @dccph_seq - 48-bit sequence number
66*05b00f60SXin Li */
67*05b00f60SXin Li struct dccp_hdr_ext {
68*05b00f60SXin Li nd_uint16_t dccph_sport,
69*05b00f60SXin Li dccph_dport;
70*05b00f60SXin Li nd_uint8_t dccph_doff;
71*05b00f60SXin Li nd_uint8_t dccph_ccval_cscov;
72*05b00f60SXin Li nd_uint16_t dccph_checksum;
73*05b00f60SXin Li nd_uint8_t dccph_xtr;
74*05b00f60SXin Li nd_uint8_t reserved;
75*05b00f60SXin Li nd_uint48_t dccph_seq;
76*05b00f60SXin Li };
77*05b00f60SXin Li
78*05b00f60SXin Li #define DCCPH_CCVAL(dh) ((GET_U_1((dh)->dccph_ccval_cscov) >> 4) & 0xF)
79*05b00f60SXin Li #define DCCPH_CSCOV(dh) (GET_U_1((dh)->dccph_ccval_cscov) & 0xF)
80*05b00f60SXin Li
81*05b00f60SXin Li #define DCCPH_X(dh) (GET_U_1((dh)->dccph_xtr) & 1)
82*05b00f60SXin Li #define DCCPH_TYPE(dh) ((GET_U_1((dh)->dccph_xtr) >> 1) & 0xF)
83*05b00f60SXin Li
84*05b00f60SXin Li /**
85*05b00f60SXin Li * struct dccp_hdr_request - Connection initiation request header
86*05b00f60SXin Li *
87*05b00f60SXin Li * @dccph_req_service - Service to which the client app wants to connect
88*05b00f60SXin Li */
89*05b00f60SXin Li struct dccp_hdr_request {
90*05b00f60SXin Li nd_uint32_t dccph_req_service;
91*05b00f60SXin Li };
92*05b00f60SXin Li
93*05b00f60SXin Li /**
94*05b00f60SXin Li * struct dccp_hdr_response - Connection initiation response header
95*05b00f60SXin Li *
96*05b00f60SXin Li * @dccph_resp_ack - 48 bit ack number, contains GSR
97*05b00f60SXin Li * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request
98*05b00f60SXin Li */
99*05b00f60SXin Li struct dccp_hdr_response {
100*05b00f60SXin Li nd_uint64_t dccph_resp_ack; /* always 8 bytes, first 2 reserved */
101*05b00f60SXin Li nd_uint32_t dccph_resp_service;
102*05b00f60SXin Li };
103*05b00f60SXin Li
104*05b00f60SXin Li /**
105*05b00f60SXin Li * struct dccp_hdr_reset - Unconditionally shut down a connection
106*05b00f60SXin Li *
107*05b00f60SXin Li * @dccph_resp_ack - 48 bit ack number
108*05b00f60SXin Li * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request
109*05b00f60SXin Li */
110*05b00f60SXin Li struct dccp_hdr_reset {
111*05b00f60SXin Li nd_uint64_t dccph_reset_ack; /* always 8 bytes, first 2 reserved */
112*05b00f60SXin Li nd_uint8_t dccph_reset_code;
113*05b00f60SXin Li nd_uint8_t dccph_reset_data1;
114*05b00f60SXin Li nd_uint8_t dccph_reset_data2;
115*05b00f60SXin Li nd_uint8_t dccph_reset_data3;
116*05b00f60SXin Li };
117*05b00f60SXin Li
118*05b00f60SXin Li enum dccp_pkt_type {
119*05b00f60SXin Li DCCP_PKT_REQUEST = 0,
120*05b00f60SXin Li DCCP_PKT_RESPONSE,
121*05b00f60SXin Li DCCP_PKT_DATA,
122*05b00f60SXin Li DCCP_PKT_ACK,
123*05b00f60SXin Li DCCP_PKT_DATAACK,
124*05b00f60SXin Li DCCP_PKT_CLOSEREQ,
125*05b00f60SXin Li DCCP_PKT_CLOSE,
126*05b00f60SXin Li DCCP_PKT_RESET,
127*05b00f60SXin Li DCCP_PKT_SYNC,
128*05b00f60SXin Li DCCP_PKT_SYNCACK
129*05b00f60SXin Li };
130*05b00f60SXin Li
131*05b00f60SXin Li static const struct tok dccp_pkt_type_str[] = {
132*05b00f60SXin Li { DCCP_PKT_REQUEST, "DCCP-Request" },
133*05b00f60SXin Li { DCCP_PKT_RESPONSE, "DCCP-Response" },
134*05b00f60SXin Li { DCCP_PKT_DATA, "DCCP-Data" },
135*05b00f60SXin Li { DCCP_PKT_ACK, "DCCP-Ack" },
136*05b00f60SXin Li { DCCP_PKT_DATAACK, "DCCP-DataAck" },
137*05b00f60SXin Li { DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" },
138*05b00f60SXin Li { DCCP_PKT_CLOSE, "DCCP-Close" },
139*05b00f60SXin Li { DCCP_PKT_RESET, "DCCP-Reset" },
140*05b00f60SXin Li { DCCP_PKT_SYNC, "DCCP-Sync" },
141*05b00f60SXin Li { DCCP_PKT_SYNCACK, "DCCP-SyncAck" },
142*05b00f60SXin Li { 0, NULL}
143*05b00f60SXin Li };
144*05b00f60SXin Li
145*05b00f60SXin Li enum dccp_reset_codes {
146*05b00f60SXin Li DCCP_RESET_CODE_UNSPECIFIED = 0,
147*05b00f60SXin Li DCCP_RESET_CODE_CLOSED,
148*05b00f60SXin Li DCCP_RESET_CODE_ABORTED,
149*05b00f60SXin Li DCCP_RESET_CODE_NO_CONNECTION,
150*05b00f60SXin Li DCCP_RESET_CODE_PACKET_ERROR,
151*05b00f60SXin Li DCCP_RESET_CODE_OPTION_ERROR,
152*05b00f60SXin Li DCCP_RESET_CODE_MANDATORY_ERROR,
153*05b00f60SXin Li DCCP_RESET_CODE_CONNECTION_REFUSED,
154*05b00f60SXin Li DCCP_RESET_CODE_BAD_SERVICE_CODE,
155*05b00f60SXin Li DCCP_RESET_CODE_TOO_BUSY,
156*05b00f60SXin Li DCCP_RESET_CODE_BAD_INIT_COOKIE,
157*05b00f60SXin Li DCCP_RESET_CODE_AGGRESSION_PENALTY,
158*05b00f60SXin Li __DCCP_RESET_CODE_LAST
159*05b00f60SXin Li };
160*05b00f60SXin Li
161*05b00f60SXin Li
162*05b00f60SXin Li static const char *dccp_reset_codes[] = {
163*05b00f60SXin Li "unspecified",
164*05b00f60SXin Li "closed",
165*05b00f60SXin Li "aborted",
166*05b00f60SXin Li "no_connection",
167*05b00f60SXin Li "packet_error",
168*05b00f60SXin Li "option_error",
169*05b00f60SXin Li "mandatory_error",
170*05b00f60SXin Li "connection_refused",
171*05b00f60SXin Li "bad_service_code",
172*05b00f60SXin Li "too_busy",
173*05b00f60SXin Li "bad_init_cookie",
174*05b00f60SXin Li "aggression_penalty",
175*05b00f60SXin Li };
176*05b00f60SXin Li
177*05b00f60SXin Li static const char *dccp_feature_nums[] = {
178*05b00f60SXin Li "reserved",
179*05b00f60SXin Li "ccid",
180*05b00f60SXin Li "allow_short_seqno",
181*05b00f60SXin Li "sequence_window",
182*05b00f60SXin Li "ecn_incapable",
183*05b00f60SXin Li "ack_ratio",
184*05b00f60SXin Li "send_ack_vector",
185*05b00f60SXin Li "send_ndp_count",
186*05b00f60SXin Li "minimum checksum coverage",
187*05b00f60SXin Li "check data checksum",
188*05b00f60SXin Li };
189*05b00f60SXin Li
190*05b00f60SXin Li static u_int
dccp_csum_coverage(netdissect_options * ndo,const struct dccp_hdr * dh,u_int len)191*05b00f60SXin Li dccp_csum_coverage(netdissect_options *ndo,
192*05b00f60SXin Li const struct dccp_hdr *dh, u_int len)
193*05b00f60SXin Li {
194*05b00f60SXin Li u_int cov;
195*05b00f60SXin Li
196*05b00f60SXin Li if (DCCPH_CSCOV(dh) == 0)
197*05b00f60SXin Li return len;
198*05b00f60SXin Li cov = (GET_U_1(dh->dccph_doff) + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t);
199*05b00f60SXin Li return (cov > len)? len : cov;
200*05b00f60SXin Li }
201*05b00f60SXin Li
dccp_cksum(netdissect_options * ndo,const struct ip * ip,const struct dccp_hdr * dh,u_int len)202*05b00f60SXin Li static uint16_t dccp_cksum(netdissect_options *ndo, const struct ip *ip,
203*05b00f60SXin Li const struct dccp_hdr *dh, u_int len)
204*05b00f60SXin Li {
205*05b00f60SXin Li return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len,
206*05b00f60SXin Li dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP);
207*05b00f60SXin Li }
208*05b00f60SXin Li
dccp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct dccp_hdr * dh,u_int len)209*05b00f60SXin Li static uint16_t dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
210*05b00f60SXin Li const struct dccp_hdr *dh, u_int len)
211*05b00f60SXin Li {
212*05b00f60SXin Li return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len,
213*05b00f60SXin Li dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP);
214*05b00f60SXin Li }
215*05b00f60SXin Li
dccp_reset_code(uint8_t code)216*05b00f60SXin Li static const char *dccp_reset_code(uint8_t code)
217*05b00f60SXin Li {
218*05b00f60SXin Li if (code >= __DCCP_RESET_CODE_LAST)
219*05b00f60SXin Li return "invalid";
220*05b00f60SXin Li return dccp_reset_codes[code];
221*05b00f60SXin Li }
222*05b00f60SXin Li
223*05b00f60SXin Li static uint64_t
dccp_seqno(netdissect_options * ndo,const u_char * bp)224*05b00f60SXin Li dccp_seqno(netdissect_options *ndo, const u_char *bp)
225*05b00f60SXin Li {
226*05b00f60SXin Li const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
227*05b00f60SXin Li uint64_t seqno;
228*05b00f60SXin Li
229*05b00f60SXin Li if (DCCPH_X(dh) != 0) {
230*05b00f60SXin Li const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp;
231*05b00f60SXin Li seqno = GET_BE_U_6(dhx->dccph_seq);
232*05b00f60SXin Li } else {
233*05b00f60SXin Li seqno = GET_BE_U_3(dh->dccph_seq);
234*05b00f60SXin Li }
235*05b00f60SXin Li
236*05b00f60SXin Li return seqno;
237*05b00f60SXin Li }
238*05b00f60SXin Li
239*05b00f60SXin Li static unsigned int
dccp_basic_hdr_len(netdissect_options * ndo,const struct dccp_hdr * dh)240*05b00f60SXin Li dccp_basic_hdr_len(netdissect_options *ndo, const struct dccp_hdr *dh)
241*05b00f60SXin Li {
242*05b00f60SXin Li return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr);
243*05b00f60SXin Li }
244*05b00f60SXin Li
dccp_print_ack_no(netdissect_options * ndo,const u_char * bp)245*05b00f60SXin Li static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp)
246*05b00f60SXin Li {
247*05b00f60SXin Li const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
248*05b00f60SXin Li const u_char *ackp = bp + dccp_basic_hdr_len(ndo, dh);
249*05b00f60SXin Li uint64_t ackno;
250*05b00f60SXin Li
251*05b00f60SXin Li if (DCCPH_X(dh) != 0) {
252*05b00f60SXin Li ackno = GET_BE_U_6(ackp + 2);
253*05b00f60SXin Li } else {
254*05b00f60SXin Li ackno = GET_BE_U_3(ackp + 1);
255*05b00f60SXin Li }
256*05b00f60SXin Li
257*05b00f60SXin Li ND_PRINT("(ack=%" PRIu64 ") ", ackno);
258*05b00f60SXin Li }
259*05b00f60SXin Li
260*05b00f60SXin Li static u_int dccp_print_option(netdissect_options *, const u_char *, u_int);
261*05b00f60SXin Li
262*05b00f60SXin Li /**
263*05b00f60SXin Li * dccp_print - show dccp packet
264*05b00f60SXin Li * @bp - beginning of dccp packet
265*05b00f60SXin Li * @data2 - beginning of enclosing
266*05b00f60SXin Li * @len - length of ip packet
267*05b00f60SXin Li */
268*05b00f60SXin Li void
dccp_print(netdissect_options * ndo,const u_char * bp,const u_char * data2,u_int len)269*05b00f60SXin Li dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2,
270*05b00f60SXin Li u_int len)
271*05b00f60SXin Li {
272*05b00f60SXin Li const struct dccp_hdr *dh;
273*05b00f60SXin Li const struct ip *ip;
274*05b00f60SXin Li const struct ip6_hdr *ip6;
275*05b00f60SXin Li const u_char *cp;
276*05b00f60SXin Li u_short sport, dport;
277*05b00f60SXin Li u_int hlen;
278*05b00f60SXin Li u_int fixed_hdrlen;
279*05b00f60SXin Li uint8_t dccph_type;
280*05b00f60SXin Li
281*05b00f60SXin Li ndo->ndo_protocol = "dccp";
282*05b00f60SXin Li dh = (const struct dccp_hdr *)bp;
283*05b00f60SXin Li
284*05b00f60SXin Li ip = (const struct ip *)data2;
285*05b00f60SXin Li if (IP_V(ip) == 6)
286*05b00f60SXin Li ip6 = (const struct ip6_hdr *)data2;
287*05b00f60SXin Li else
288*05b00f60SXin Li ip6 = NULL;
289*05b00f60SXin Li
290*05b00f60SXin Li /* make sure we have enough data to look at the X bit */
291*05b00f60SXin Li cp = (const u_char *)(dh + 1);
292*05b00f60SXin Li if (cp > ndo->ndo_snapend)
293*05b00f60SXin Li goto trunc;
294*05b00f60SXin Li if (len < sizeof(struct dccp_hdr)) {
295*05b00f60SXin Li ND_PRINT("truncated-dccp - %zu bytes missing!",
296*05b00f60SXin Li sizeof(struct dccp_hdr) - len);
297*05b00f60SXin Li return;
298*05b00f60SXin Li }
299*05b00f60SXin Li
300*05b00f60SXin Li /* get the length of the generic header */
301*05b00f60SXin Li fixed_hdrlen = dccp_basic_hdr_len(ndo, dh);
302*05b00f60SXin Li if (len < fixed_hdrlen) {
303*05b00f60SXin Li ND_PRINT("truncated-dccp - %u bytes missing!",
304*05b00f60SXin Li fixed_hdrlen - len);
305*05b00f60SXin Li return;
306*05b00f60SXin Li }
307*05b00f60SXin Li ND_TCHECK_LEN(dh, fixed_hdrlen);
308*05b00f60SXin Li
309*05b00f60SXin Li sport = GET_BE_U_2(dh->dccph_sport);
310*05b00f60SXin Li dport = GET_BE_U_2(dh->dccph_dport);
311*05b00f60SXin Li hlen = GET_U_1(dh->dccph_doff) * 4;
312*05b00f60SXin Li
313*05b00f60SXin Li if (ip6) {
314*05b00f60SXin Li ND_PRINT("%s.%u > %s.%u: ",
315*05b00f60SXin Li GET_IP6ADDR_STRING(ip6->ip6_src), sport,
316*05b00f60SXin Li GET_IP6ADDR_STRING(ip6->ip6_dst), dport);
317*05b00f60SXin Li } else {
318*05b00f60SXin Li ND_PRINT("%s.%u > %s.%u: ",
319*05b00f60SXin Li GET_IPADDR_STRING(ip->ip_src), sport,
320*05b00f60SXin Li GET_IPADDR_STRING(ip->ip_dst), dport);
321*05b00f60SXin Li }
322*05b00f60SXin Li
323*05b00f60SXin Li nd_print_protocol_caps(ndo);
324*05b00f60SXin Li
325*05b00f60SXin Li if (ndo->ndo_qflag) {
326*05b00f60SXin Li ND_PRINT(" %u", len - hlen);
327*05b00f60SXin Li if (hlen > len) {
328*05b00f60SXin Li ND_PRINT(" [bad hdr length %u - too long, > %u]",
329*05b00f60SXin Li hlen, len);
330*05b00f60SXin Li }
331*05b00f60SXin Li return;
332*05b00f60SXin Li }
333*05b00f60SXin Li
334*05b00f60SXin Li /* other variables in generic header */
335*05b00f60SXin Li if (ndo->ndo_vflag) {
336*05b00f60SXin Li ND_PRINT(" (CCVal %u, CsCov %u", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
337*05b00f60SXin Li }
338*05b00f60SXin Li
339*05b00f60SXin Li /* checksum calculation */
340*05b00f60SXin Li if (ndo->ndo_vflag && ND_TTEST_LEN(bp, len)) {
341*05b00f60SXin Li uint16_t sum = 0, dccp_sum;
342*05b00f60SXin Li
343*05b00f60SXin Li dccp_sum = GET_BE_U_2(dh->dccph_checksum);
344*05b00f60SXin Li ND_PRINT(", cksum 0x%04x ", dccp_sum);
345*05b00f60SXin Li if (IP_V(ip) == 4)
346*05b00f60SXin Li sum = dccp_cksum(ndo, ip, dh, len);
347*05b00f60SXin Li else if (IP_V(ip) == 6)
348*05b00f60SXin Li sum = dccp6_cksum(ndo, ip6, dh, len);
349*05b00f60SXin Li if (sum != 0)
350*05b00f60SXin Li ND_PRINT("(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum));
351*05b00f60SXin Li else
352*05b00f60SXin Li ND_PRINT("(correct)");
353*05b00f60SXin Li }
354*05b00f60SXin Li
355*05b00f60SXin Li if (ndo->ndo_vflag)
356*05b00f60SXin Li ND_PRINT(")");
357*05b00f60SXin Li ND_PRINT(" ");
358*05b00f60SXin Li
359*05b00f60SXin Li dccph_type = DCCPH_TYPE(dh);
360*05b00f60SXin Li switch (dccph_type) {
361*05b00f60SXin Li case DCCP_PKT_REQUEST: {
362*05b00f60SXin Li const struct dccp_hdr_request *dhr =
363*05b00f60SXin Li (const struct dccp_hdr_request *)(bp + fixed_hdrlen);
364*05b00f60SXin Li fixed_hdrlen += 4;
365*05b00f60SXin Li if (len < fixed_hdrlen) {
366*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
367*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
368*05b00f60SXin Li fixed_hdrlen - len);
369*05b00f60SXin Li return;
370*05b00f60SXin Li }
371*05b00f60SXin Li ND_TCHECK_SIZE(dhr);
372*05b00f60SXin Li ND_PRINT("%s (service=%u) ",
373*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
374*05b00f60SXin Li GET_BE_U_4(dhr->dccph_req_service));
375*05b00f60SXin Li break;
376*05b00f60SXin Li }
377*05b00f60SXin Li case DCCP_PKT_RESPONSE: {
378*05b00f60SXin Li const struct dccp_hdr_response *dhr =
379*05b00f60SXin Li (const struct dccp_hdr_response *)(bp + fixed_hdrlen);
380*05b00f60SXin Li fixed_hdrlen += 12;
381*05b00f60SXin Li if (len < fixed_hdrlen) {
382*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
383*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
384*05b00f60SXin Li fixed_hdrlen - len);
385*05b00f60SXin Li return;
386*05b00f60SXin Li }
387*05b00f60SXin Li ND_TCHECK_SIZE(dhr);
388*05b00f60SXin Li ND_PRINT("%s (service=%u) ",
389*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
390*05b00f60SXin Li GET_BE_U_4(dhr->dccph_resp_service));
391*05b00f60SXin Li break;
392*05b00f60SXin Li }
393*05b00f60SXin Li case DCCP_PKT_DATA:
394*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
395*05b00f60SXin Li break;
396*05b00f60SXin Li case DCCP_PKT_ACK: {
397*05b00f60SXin Li fixed_hdrlen += 8;
398*05b00f60SXin Li if (len < fixed_hdrlen) {
399*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
400*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
401*05b00f60SXin Li fixed_hdrlen - len);
402*05b00f60SXin Li return;
403*05b00f60SXin Li }
404*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
405*05b00f60SXin Li break;
406*05b00f60SXin Li }
407*05b00f60SXin Li case DCCP_PKT_DATAACK: {
408*05b00f60SXin Li fixed_hdrlen += 8;
409*05b00f60SXin Li if (len < fixed_hdrlen) {
410*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
411*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
412*05b00f60SXin Li fixed_hdrlen - len);
413*05b00f60SXin Li return;
414*05b00f60SXin Li }
415*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
416*05b00f60SXin Li break;
417*05b00f60SXin Li }
418*05b00f60SXin Li case DCCP_PKT_CLOSEREQ:
419*05b00f60SXin Li fixed_hdrlen += 8;
420*05b00f60SXin Li if (len < fixed_hdrlen) {
421*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
422*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
423*05b00f60SXin Li fixed_hdrlen - len);
424*05b00f60SXin Li return;
425*05b00f60SXin Li }
426*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
427*05b00f60SXin Li break;
428*05b00f60SXin Li case DCCP_PKT_CLOSE:
429*05b00f60SXin Li fixed_hdrlen += 8;
430*05b00f60SXin Li if (len < fixed_hdrlen) {
431*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
432*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
433*05b00f60SXin Li fixed_hdrlen - len);
434*05b00f60SXin Li return;
435*05b00f60SXin Li }
436*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
437*05b00f60SXin Li break;
438*05b00f60SXin Li case DCCP_PKT_RESET: {
439*05b00f60SXin Li const struct dccp_hdr_reset *dhr =
440*05b00f60SXin Li (const struct dccp_hdr_reset *)(bp + fixed_hdrlen);
441*05b00f60SXin Li fixed_hdrlen += 12;
442*05b00f60SXin Li if (len < fixed_hdrlen) {
443*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
444*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
445*05b00f60SXin Li fixed_hdrlen - len);
446*05b00f60SXin Li return;
447*05b00f60SXin Li }
448*05b00f60SXin Li ND_TCHECK_SIZE(dhr);
449*05b00f60SXin Li ND_PRINT("%s (code=%s) ",
450*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
451*05b00f60SXin Li dccp_reset_code(GET_U_1(dhr->dccph_reset_code)));
452*05b00f60SXin Li break;
453*05b00f60SXin Li }
454*05b00f60SXin Li case DCCP_PKT_SYNC:
455*05b00f60SXin Li fixed_hdrlen += 8;
456*05b00f60SXin Li if (len < fixed_hdrlen) {
457*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
458*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
459*05b00f60SXin Li fixed_hdrlen - len);
460*05b00f60SXin Li return;
461*05b00f60SXin Li }
462*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
463*05b00f60SXin Li break;
464*05b00f60SXin Li case DCCP_PKT_SYNCACK:
465*05b00f60SXin Li fixed_hdrlen += 8;
466*05b00f60SXin Li if (len < fixed_hdrlen) {
467*05b00f60SXin Li ND_PRINT("truncated-%s - %u bytes missing!",
468*05b00f60SXin Li tok2str(dccp_pkt_type_str, "", dccph_type),
469*05b00f60SXin Li fixed_hdrlen - len);
470*05b00f60SXin Li return;
471*05b00f60SXin Li }
472*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
473*05b00f60SXin Li break;
474*05b00f60SXin Li default:
475*05b00f60SXin Li ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type));
476*05b00f60SXin Li break;
477*05b00f60SXin Li }
478*05b00f60SXin Li
479*05b00f60SXin Li if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
480*05b00f60SXin Li (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
481*05b00f60SXin Li dccp_print_ack_no(ndo, bp);
482*05b00f60SXin Li
483*05b00f60SXin Li if (ndo->ndo_vflag < 2)
484*05b00f60SXin Li return;
485*05b00f60SXin Li
486*05b00f60SXin Li ND_PRINT("seq %" PRIu64, dccp_seqno(ndo, bp));
487*05b00f60SXin Li
488*05b00f60SXin Li /* process options */
489*05b00f60SXin Li if (hlen > fixed_hdrlen){
490*05b00f60SXin Li u_int optlen;
491*05b00f60SXin Li cp = bp + fixed_hdrlen;
492*05b00f60SXin Li ND_PRINT(" <");
493*05b00f60SXin Li
494*05b00f60SXin Li hlen -= fixed_hdrlen;
495*05b00f60SXin Li while(1){
496*05b00f60SXin Li optlen = dccp_print_option(ndo, cp, hlen);
497*05b00f60SXin Li if (!optlen)
498*05b00f60SXin Li break;
499*05b00f60SXin Li if (hlen <= optlen)
500*05b00f60SXin Li break;
501*05b00f60SXin Li hlen -= optlen;
502*05b00f60SXin Li cp += optlen;
503*05b00f60SXin Li ND_PRINT(", ");
504*05b00f60SXin Li }
505*05b00f60SXin Li ND_PRINT(">");
506*05b00f60SXin Li }
507*05b00f60SXin Li return;
508*05b00f60SXin Li trunc:
509*05b00f60SXin Li nd_print_trunc(ndo);
510*05b00f60SXin Li }
511*05b00f60SXin Li
512*05b00f60SXin Li static const struct tok dccp_option_values[] = {
513*05b00f60SXin Li { 0, "nop" },
514*05b00f60SXin Li { 1, "mandatory" },
515*05b00f60SXin Li { 2, "slowreceiver" },
516*05b00f60SXin Li { 32, "change_l" },
517*05b00f60SXin Li { 33, "confirm_l" },
518*05b00f60SXin Li { 34, "change_r" },
519*05b00f60SXin Li { 35, "confirm_r" },
520*05b00f60SXin Li { 36, "initcookie" },
521*05b00f60SXin Li { 37, "ndp_count" },
522*05b00f60SXin Li { 38, "ack_vector0" },
523*05b00f60SXin Li { 39, "ack_vector1" },
524*05b00f60SXin Li { 40, "data_dropped" },
525*05b00f60SXin Li { 41, "timestamp" },
526*05b00f60SXin Li { 42, "timestamp_echo" },
527*05b00f60SXin Li { 43, "elapsed_time" },
528*05b00f60SXin Li { 44, "data_checksum" },
529*05b00f60SXin Li { 0, NULL }
530*05b00f60SXin Li };
531*05b00f60SXin Li
532*05b00f60SXin Li static u_int
dccp_print_option(netdissect_options * ndo,const u_char * option,u_int hlen)533*05b00f60SXin Li dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
534*05b00f60SXin Li {
535*05b00f60SXin Li uint8_t optlen, i;
536*05b00f60SXin Li
537*05b00f60SXin Li if (GET_U_1(option) >= 32) {
538*05b00f60SXin Li optlen = GET_U_1(option + 1);
539*05b00f60SXin Li if (optlen < 2) {
540*05b00f60SXin Li if (GET_U_1(option) >= 128)
541*05b00f60SXin Li ND_PRINT("CCID option %u optlen too short",
542*05b00f60SXin Li GET_U_1(option));
543*05b00f60SXin Li else
544*05b00f60SXin Li ND_PRINT("%s optlen too short",
545*05b00f60SXin Li tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
546*05b00f60SXin Li return 0;
547*05b00f60SXin Li }
548*05b00f60SXin Li } else
549*05b00f60SXin Li optlen = 1;
550*05b00f60SXin Li
551*05b00f60SXin Li if (hlen < optlen) {
552*05b00f60SXin Li if (GET_U_1(option) >= 128)
553*05b00f60SXin Li ND_PRINT("CCID option %u optlen goes past header length",
554*05b00f60SXin Li GET_U_1(option));
555*05b00f60SXin Li else
556*05b00f60SXin Li ND_PRINT("%s optlen goes past header length",
557*05b00f60SXin Li tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
558*05b00f60SXin Li return 0;
559*05b00f60SXin Li }
560*05b00f60SXin Li ND_TCHECK_LEN(option, optlen);
561*05b00f60SXin Li
562*05b00f60SXin Li if (GET_U_1(option) >= 128) {
563*05b00f60SXin Li ND_PRINT("CCID option %u", GET_U_1(option));
564*05b00f60SXin Li switch (optlen) {
565*05b00f60SXin Li case 4:
566*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_2(option + 2));
567*05b00f60SXin Li break;
568*05b00f60SXin Li case 6:
569*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_4(option + 2));
570*05b00f60SXin Li break;
571*05b00f60SXin Li default:
572*05b00f60SXin Li break;
573*05b00f60SXin Li }
574*05b00f60SXin Li } else {
575*05b00f60SXin Li ND_PRINT("%s",
576*05b00f60SXin Li tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
577*05b00f60SXin Li switch (GET_U_1(option)) {
578*05b00f60SXin Li case 32:
579*05b00f60SXin Li case 33:
580*05b00f60SXin Li case 34:
581*05b00f60SXin Li case 35:
582*05b00f60SXin Li if (optlen < 3) {
583*05b00f60SXin Li ND_PRINT(" optlen too short");
584*05b00f60SXin Li return optlen;
585*05b00f60SXin Li }
586*05b00f60SXin Li if (GET_U_1(option + 2) < 10){
587*05b00f60SXin Li ND_PRINT(" %s",
588*05b00f60SXin Li dccp_feature_nums[GET_U_1(option + 2)]);
589*05b00f60SXin Li for (i = 0; i < optlen - 3; i++)
590*05b00f60SXin Li ND_PRINT(" %u",
591*05b00f60SXin Li GET_U_1(option + 3 + i));
592*05b00f60SXin Li }
593*05b00f60SXin Li break;
594*05b00f60SXin Li case 36:
595*05b00f60SXin Li if (optlen > 2) {
596*05b00f60SXin Li ND_PRINT(" 0x");
597*05b00f60SXin Li for (i = 0; i < optlen - 2; i++)
598*05b00f60SXin Li ND_PRINT("%02x",
599*05b00f60SXin Li GET_U_1(option + 2 + i));
600*05b00f60SXin Li }
601*05b00f60SXin Li break;
602*05b00f60SXin Li case 37:
603*05b00f60SXin Li for (i = 0; i < optlen - 2; i++)
604*05b00f60SXin Li ND_PRINT(" %u", GET_U_1(option + 2 + i));
605*05b00f60SXin Li break;
606*05b00f60SXin Li case 38:
607*05b00f60SXin Li if (optlen > 2) {
608*05b00f60SXin Li ND_PRINT(" 0x");
609*05b00f60SXin Li for (i = 0; i < optlen - 2; i++)
610*05b00f60SXin Li ND_PRINT("%02x",
611*05b00f60SXin Li GET_U_1(option + 2 + i));
612*05b00f60SXin Li }
613*05b00f60SXin Li break;
614*05b00f60SXin Li case 39:
615*05b00f60SXin Li if (optlen > 2) {
616*05b00f60SXin Li ND_PRINT(" 0x");
617*05b00f60SXin Li for (i = 0; i < optlen - 2; i++)
618*05b00f60SXin Li ND_PRINT("%02x",
619*05b00f60SXin Li GET_U_1(option + 2 + i));
620*05b00f60SXin Li }
621*05b00f60SXin Li break;
622*05b00f60SXin Li case 40:
623*05b00f60SXin Li if (optlen > 2) {
624*05b00f60SXin Li ND_PRINT(" 0x");
625*05b00f60SXin Li for (i = 0; i < optlen - 2; i++)
626*05b00f60SXin Li ND_PRINT("%02x",
627*05b00f60SXin Li GET_U_1(option + 2 + i));
628*05b00f60SXin Li }
629*05b00f60SXin Li break;
630*05b00f60SXin Li case 41:
631*05b00f60SXin Li /*
632*05b00f60SXin Li * 13.1. Timestamp Option
633*05b00f60SXin Li *
634*05b00f60SXin Li * +--------+--------+--------+--------+--------+--------+
635*05b00f60SXin Li * |00101001|00000110| Timestamp Value |
636*05b00f60SXin Li * +--------+--------+--------+--------+--------+--------+
637*05b00f60SXin Li * Type=41 Length=6
638*05b00f60SXin Li */
639*05b00f60SXin Li if (optlen == 6)
640*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_4(option + 2));
641*05b00f60SXin Li else
642*05b00f60SXin Li ND_PRINT(" [optlen != 6]");
643*05b00f60SXin Li break;
644*05b00f60SXin Li case 42:
645*05b00f60SXin Li /*
646*05b00f60SXin Li * 13.3. Timestamp Echo Option
647*05b00f60SXin Li *
648*05b00f60SXin Li * +--------+--------+--------+--------+--------+--------+
649*05b00f60SXin Li * |00101010|00000110| Timestamp Echo |
650*05b00f60SXin Li * +--------+--------+--------+--------+--------+--------+
651*05b00f60SXin Li * Type=42 Len=6
652*05b00f60SXin Li *
653*05b00f60SXin Li * +--------+--------+------- ... -------+--------+--------+
654*05b00f60SXin Li * |00101010|00001000| Timestamp Echo | Elapsed Time |
655*05b00f60SXin Li * +--------+--------+------- ... -------+--------+--------+
656*05b00f60SXin Li * Type=42 Len=8 (4 bytes)
657*05b00f60SXin Li *
658*05b00f60SXin Li * +--------+--------+------- ... -------+------- ... -------+
659*05b00f60SXin Li * |00101010|00001010| Timestamp Echo | Elapsed Time |
660*05b00f60SXin Li * +--------+--------+------- ... -------+------- ... -------+
661*05b00f60SXin Li * Type=42 Len=10 (4 bytes) (4 bytes)
662*05b00f60SXin Li */
663*05b00f60SXin Li switch (optlen) {
664*05b00f60SXin Li case 6:
665*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_4(option + 2));
666*05b00f60SXin Li break;
667*05b00f60SXin Li case 8:
668*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_4(option + 2));
669*05b00f60SXin Li ND_PRINT(" (elapsed time %u)",
670*05b00f60SXin Li GET_BE_U_2(option + 6));
671*05b00f60SXin Li break;
672*05b00f60SXin Li case 10:
673*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_4(option + 2));
674*05b00f60SXin Li ND_PRINT(" (elapsed time %u)",
675*05b00f60SXin Li GET_BE_U_4(option + 6));
676*05b00f60SXin Li break;
677*05b00f60SXin Li default:
678*05b00f60SXin Li ND_PRINT(" [optlen != 6 or 8 or 10]");
679*05b00f60SXin Li break;
680*05b00f60SXin Li }
681*05b00f60SXin Li break;
682*05b00f60SXin Li case 43:
683*05b00f60SXin Li if (optlen == 6)
684*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_4(option + 2));
685*05b00f60SXin Li else if (optlen == 4)
686*05b00f60SXin Li ND_PRINT(" %u", GET_BE_U_2(option + 2));
687*05b00f60SXin Li else
688*05b00f60SXin Li ND_PRINT(" [optlen != 4 or 6]");
689*05b00f60SXin Li break;
690*05b00f60SXin Li case 44:
691*05b00f60SXin Li if (optlen > 2) {
692*05b00f60SXin Li ND_PRINT(" ");
693*05b00f60SXin Li for (i = 0; i < optlen - 2; i++)
694*05b00f60SXin Li ND_PRINT("%02x",
695*05b00f60SXin Li GET_U_1(option + 2 + i));
696*05b00f60SXin Li }
697*05b00f60SXin Li break;
698*05b00f60SXin Li }
699*05b00f60SXin Li }
700*05b00f60SXin Li
701*05b00f60SXin Li return optlen;
702*05b00f60SXin Li trunc:
703*05b00f60SXin Li nd_print_trunc(ndo);
704*05b00f60SXin Li return 0;
705*05b00f60SXin Li }
706