141c99275SPeter Avalos /*
241c99275SPeter Avalos * Copyright (C) Arnaldo Carvalho de Melo 2004
341c99275SPeter Avalos * Copyright (C) Ian McDonald 2005
441c99275SPeter Avalos * Copyright (C) Yoshifumi Nishida 2005
541c99275SPeter Avalos *
641c99275SPeter Avalos * This software may be distributed either under the terms of the
741c99275SPeter Avalos * BSD-style license that accompanies tcpdump or the GNU GPL version 2
841c99275SPeter Avalos */
941c99275SPeter Avalos
10411677aeSAaron LI /* \summary: Datagram Congestion Control Protocol (DCCP) printer */
1141c99275SPeter Avalos
12*ed775ee7SAntonio Huete Jimenez /* specification: RFC 4340 */
13*ed775ee7SAntonio Huete Jimenez
1441c99275SPeter Avalos #ifdef HAVE_CONFIG_H
15*ed775ee7SAntonio Huete Jimenez #include <config.h>
1641c99275SPeter Avalos #endif
1741c99275SPeter Avalos
18*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
1941c99275SPeter Avalos
20411677aeSAaron LI #include "netdissect.h"
2141c99275SPeter Avalos #include "addrtoname.h"
22411677aeSAaron LI #include "extract.h"
2341c99275SPeter Avalos #include "ip.h"
2441c99275SPeter Avalos #include "ip6.h"
2541c99275SPeter Avalos #include "ipproto.h"
2641c99275SPeter Avalos
27411677aeSAaron LI /* RFC4340: Datagram Congestion Control Protocol (DCCP) */
28411677aeSAaron LI
29411677aeSAaron LI /**
30411677aeSAaron LI * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit
31411677aeSAaron LI * sequence number
32411677aeSAaron LI *
33411677aeSAaron LI * @dccph_sport - Relevant port on the endpoint that sent this packet
34411677aeSAaron LI * @dccph_dport - Relevant port on the other endpoint
35411677aeSAaron LI * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
36411677aeSAaron LI * @dccph_ccval - Used by the HC-Sender CCID
37411677aeSAaron LI * @dccph_cscov - Parts of the packet that are covered by the Checksum field
38411677aeSAaron LI * @dccph_checksum - Internet checksum, depends on dccph_cscov
39411677aeSAaron LI * @dccph_x - 0 = 24 bit sequence number, 1 = 48
40411677aeSAaron LI * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
41411677aeSAaron LI * @dccph_seq - 24-bit sequence number
42411677aeSAaron LI */
43411677aeSAaron LI struct dccp_hdr {
44*ed775ee7SAntonio Huete Jimenez nd_uint16_t dccph_sport,
45411677aeSAaron LI dccph_dport;
46*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_doff;
47*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_ccval_cscov;
48*ed775ee7SAntonio Huete Jimenez nd_uint16_t dccph_checksum;
49*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_xtr;
50*ed775ee7SAntonio Huete Jimenez nd_uint24_t dccph_seq;
51*ed775ee7SAntonio Huete Jimenez };
52411677aeSAaron LI
53411677aeSAaron LI /**
54411677aeSAaron LI * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit
55411677aeSAaron LI * sequence number
56411677aeSAaron LI *
57411677aeSAaron LI * @dccph_sport - Relevant port on the endpoint that sent this packet
58411677aeSAaron LI * @dccph_dport - Relevant port on the other endpoint
59411677aeSAaron LI * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
60411677aeSAaron LI * @dccph_ccval - Used by the HC-Sender CCID
61411677aeSAaron LI * @dccph_cscov - Parts of the packet that are covered by the Checksum field
62411677aeSAaron LI * @dccph_checksum - Internet checksum, depends on dccph_cscov
63411677aeSAaron LI * @dccph_x - 0 = 24 bit sequence number, 1 = 48
64411677aeSAaron LI * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
65411677aeSAaron LI * @dccph_seq - 48-bit sequence number
66411677aeSAaron LI */
67411677aeSAaron LI struct dccp_hdr_ext {
68*ed775ee7SAntonio Huete Jimenez nd_uint16_t dccph_sport,
69411677aeSAaron LI dccph_dport;
70*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_doff;
71*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_ccval_cscov;
72*ed775ee7SAntonio Huete Jimenez nd_uint16_t dccph_checksum;
73*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_xtr;
74*ed775ee7SAntonio Huete Jimenez nd_uint8_t reserved;
75*ed775ee7SAntonio Huete Jimenez nd_uint48_t dccph_seq;
76*ed775ee7SAntonio Huete Jimenez };
77411677aeSAaron LI
78*ed775ee7SAntonio Huete Jimenez #define DCCPH_CCVAL(dh) ((GET_U_1((dh)->dccph_ccval_cscov) >> 4) & 0xF)
79*ed775ee7SAntonio Huete Jimenez #define DCCPH_CSCOV(dh) (GET_U_1((dh)->dccph_ccval_cscov) & 0xF)
80411677aeSAaron LI
81*ed775ee7SAntonio Huete Jimenez #define DCCPH_X(dh) (GET_U_1((dh)->dccph_xtr) & 1)
82*ed775ee7SAntonio Huete Jimenez #define DCCPH_TYPE(dh) ((GET_U_1((dh)->dccph_xtr) >> 1) & 0xF)
83411677aeSAaron LI
84411677aeSAaron LI /**
85*ed775ee7SAntonio Huete Jimenez * struct dccp_hdr_request - Connection initiation request header
86411677aeSAaron LI *
87411677aeSAaron LI * @dccph_req_service - Service to which the client app wants to connect
88411677aeSAaron LI */
89411677aeSAaron LI struct dccp_hdr_request {
90*ed775ee7SAntonio Huete Jimenez nd_uint32_t dccph_req_service;
91*ed775ee7SAntonio Huete Jimenez };
92411677aeSAaron LI
93411677aeSAaron LI /**
94*ed775ee7SAntonio Huete Jimenez * struct dccp_hdr_response - Connection initiation response header
95411677aeSAaron LI *
96411677aeSAaron LI * @dccph_resp_ack - 48 bit ack number, contains GSR
97411677aeSAaron LI * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request
98411677aeSAaron LI */
99411677aeSAaron LI struct dccp_hdr_response {
100*ed775ee7SAntonio Huete Jimenez nd_uint64_t dccph_resp_ack; /* always 8 bytes, first 2 reserved */
101*ed775ee7SAntonio Huete Jimenez nd_uint32_t dccph_resp_service;
102*ed775ee7SAntonio Huete Jimenez };
103411677aeSAaron LI
104411677aeSAaron LI /**
105411677aeSAaron LI * struct dccp_hdr_reset - Unconditionally shut down a connection
106411677aeSAaron LI *
107411677aeSAaron LI * @dccph_resp_ack - 48 bit ack number
108411677aeSAaron LI * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request
109411677aeSAaron LI */
110411677aeSAaron LI struct dccp_hdr_reset {
111*ed775ee7SAntonio Huete Jimenez nd_uint64_t dccph_reset_ack; /* always 8 bytes, first 2 reserved */
112*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_reset_code;
113*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_reset_data1;
114*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_reset_data2;
115*ed775ee7SAntonio Huete Jimenez nd_uint8_t dccph_reset_data3;
116*ed775ee7SAntonio Huete Jimenez };
117411677aeSAaron LI
118411677aeSAaron LI enum dccp_pkt_type {
119411677aeSAaron LI DCCP_PKT_REQUEST = 0,
120411677aeSAaron LI DCCP_PKT_RESPONSE,
121411677aeSAaron LI DCCP_PKT_DATA,
122411677aeSAaron LI DCCP_PKT_ACK,
123411677aeSAaron LI DCCP_PKT_DATAACK,
124411677aeSAaron LI DCCP_PKT_CLOSEREQ,
125411677aeSAaron LI DCCP_PKT_CLOSE,
126411677aeSAaron LI DCCP_PKT_RESET,
127411677aeSAaron LI DCCP_PKT_SYNC,
128411677aeSAaron LI DCCP_PKT_SYNCACK
129411677aeSAaron LI };
130411677aeSAaron LI
131411677aeSAaron LI static const struct tok dccp_pkt_type_str[] = {
132411677aeSAaron LI { DCCP_PKT_REQUEST, "DCCP-Request" },
133411677aeSAaron LI { DCCP_PKT_RESPONSE, "DCCP-Response" },
134411677aeSAaron LI { DCCP_PKT_DATA, "DCCP-Data" },
135411677aeSAaron LI { DCCP_PKT_ACK, "DCCP-Ack" },
136411677aeSAaron LI { DCCP_PKT_DATAACK, "DCCP-DataAck" },
137411677aeSAaron LI { DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" },
138411677aeSAaron LI { DCCP_PKT_CLOSE, "DCCP-Close" },
139411677aeSAaron LI { DCCP_PKT_RESET, "DCCP-Reset" },
140411677aeSAaron LI { DCCP_PKT_SYNC, "DCCP-Sync" },
141411677aeSAaron LI { DCCP_PKT_SYNCACK, "DCCP-SyncAck" },
142411677aeSAaron LI { 0, NULL}
143411677aeSAaron LI };
144411677aeSAaron LI
145411677aeSAaron LI enum dccp_reset_codes {
146411677aeSAaron LI DCCP_RESET_CODE_UNSPECIFIED = 0,
147411677aeSAaron LI DCCP_RESET_CODE_CLOSED,
148411677aeSAaron LI DCCP_RESET_CODE_ABORTED,
149411677aeSAaron LI DCCP_RESET_CODE_NO_CONNECTION,
150411677aeSAaron LI DCCP_RESET_CODE_PACKET_ERROR,
151411677aeSAaron LI DCCP_RESET_CODE_OPTION_ERROR,
152411677aeSAaron LI DCCP_RESET_CODE_MANDATORY_ERROR,
153411677aeSAaron LI DCCP_RESET_CODE_CONNECTION_REFUSED,
154411677aeSAaron LI DCCP_RESET_CODE_BAD_SERVICE_CODE,
155411677aeSAaron LI DCCP_RESET_CODE_TOO_BUSY,
156411677aeSAaron LI DCCP_RESET_CODE_BAD_INIT_COOKIE,
157411677aeSAaron LI DCCP_RESET_CODE_AGGRESSION_PENALTY,
158411677aeSAaron LI __DCCP_RESET_CODE_LAST
159411677aeSAaron LI };
160411677aeSAaron LI
161411677aeSAaron LI
16241c99275SPeter Avalos static const char *dccp_reset_codes[] = {
16341c99275SPeter Avalos "unspecified",
16441c99275SPeter Avalos "closed",
16541c99275SPeter Avalos "aborted",
16641c99275SPeter Avalos "no_connection",
16741c99275SPeter Avalos "packet_error",
16841c99275SPeter Avalos "option_error",
16941c99275SPeter Avalos "mandatory_error",
17041c99275SPeter Avalos "connection_refused",
17141c99275SPeter Avalos "bad_service_code",
17241c99275SPeter Avalos "too_busy",
17341c99275SPeter Avalos "bad_init_cookie",
17441c99275SPeter Avalos "aggression_penalty",
17541c99275SPeter Avalos };
17641c99275SPeter Avalos
17741c99275SPeter Avalos static const char *dccp_feature_nums[] = {
17841c99275SPeter Avalos "reserved",
17941c99275SPeter Avalos "ccid",
18041c99275SPeter Avalos "allow_short_seqno",
18141c99275SPeter Avalos "sequence_window",
18241c99275SPeter Avalos "ecn_incapable",
18341c99275SPeter Avalos "ack_ratio",
18441c99275SPeter Avalos "send_ack_vector",
18541c99275SPeter Avalos "send_ndp_count",
18641c99275SPeter Avalos "minimum checksum coverage",
18741c99275SPeter Avalos "check data checksum",
18841c99275SPeter Avalos };
18941c99275SPeter Avalos
190*ed775ee7SAntonio Huete Jimenez static u_int
dccp_csum_coverage(netdissect_options * ndo,const struct dccp_hdr * dh,u_int len)191*ed775ee7SAntonio Huete Jimenez dccp_csum_coverage(netdissect_options *ndo,
192*ed775ee7SAntonio Huete Jimenez const struct dccp_hdr* dh, u_int len)
193ea7b4bf5SPeter Avalos {
194ea7b4bf5SPeter Avalos u_int cov;
195ea7b4bf5SPeter Avalos
196ea7b4bf5SPeter Avalos if (DCCPH_CSCOV(dh) == 0)
197ea7b4bf5SPeter Avalos return len;
198*ed775ee7SAntonio Huete Jimenez cov = (GET_U_1(dh->dccph_doff) + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t);
199ea7b4bf5SPeter Avalos return (cov > len)? len : cov;
200ea7b4bf5SPeter Avalos }
201ea7b4bf5SPeter Avalos
dccp_cksum(netdissect_options * ndo,const struct ip * ip,const struct dccp_hdr * dh,u_int len)202*ed775ee7SAntonio Huete Jimenez static uint16_t dccp_cksum(netdissect_options *ndo, const struct ip *ip,
20341c99275SPeter Avalos const struct dccp_hdr *dh, u_int len)
20441c99275SPeter Avalos {
205411677aeSAaron LI return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len,
206*ed775ee7SAntonio Huete Jimenez dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP);
20741c99275SPeter Avalos }
20841c99275SPeter Avalos
dccp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct dccp_hdr * dh,u_int len)209*ed775ee7SAntonio Huete Jimenez static uint16_t dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
210411677aeSAaron LI const struct dccp_hdr *dh, u_int len)
21141c99275SPeter Avalos {
212411677aeSAaron LI return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len,
213*ed775ee7SAntonio Huete Jimenez dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP);
21441c99275SPeter Avalos }
21541c99275SPeter Avalos
dccp_reset_code(uint8_t code)216411677aeSAaron LI static const char *dccp_reset_code(uint8_t code)
21741c99275SPeter Avalos {
21841c99275SPeter Avalos if (code >= __DCCP_RESET_CODE_LAST)
21941c99275SPeter Avalos return "invalid";
22041c99275SPeter Avalos return dccp_reset_codes[code];
22141c99275SPeter Avalos }
22241c99275SPeter Avalos
223*ed775ee7SAntonio Huete Jimenez static uint64_t
dccp_seqno(netdissect_options * ndo,const u_char * bp)224*ed775ee7SAntonio Huete Jimenez dccp_seqno(netdissect_options *ndo, const u_char *bp)
22541c99275SPeter Avalos {
226411677aeSAaron LI const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
227411677aeSAaron LI uint64_t seqno;
22841c99275SPeter Avalos
22941c99275SPeter Avalos if (DCCPH_X(dh) != 0) {
230411677aeSAaron LI const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp;
231*ed775ee7SAntonio Huete Jimenez seqno = GET_BE_U_6(dhx->dccph_seq);
232411677aeSAaron LI } else {
233*ed775ee7SAntonio Huete Jimenez seqno = GET_BE_U_3(dh->dccph_seq);
23441c99275SPeter Avalos }
23541c99275SPeter Avalos
23641c99275SPeter Avalos return seqno;
23741c99275SPeter Avalos }
23841c99275SPeter Avalos
239*ed775ee7SAntonio Huete Jimenez static unsigned int
dccp_basic_hdr_len(netdissect_options * ndo,const struct dccp_hdr * dh)240*ed775ee7SAntonio Huete Jimenez dccp_basic_hdr_len(netdissect_options *ndo, const struct dccp_hdr *dh)
24141c99275SPeter Avalos {
242411677aeSAaron LI return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr);
24341c99275SPeter Avalos }
24441c99275SPeter Avalos
dccp_print_ack_no(netdissect_options * ndo,const u_char * bp)245411677aeSAaron LI static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp)
24641c99275SPeter Avalos {
24741c99275SPeter Avalos const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
248*ed775ee7SAntonio Huete Jimenez const u_char *ackp = bp + dccp_basic_hdr_len(ndo, dh);
249411677aeSAaron LI uint64_t ackno;
25041c99275SPeter Avalos
25141c99275SPeter Avalos if (DCCPH_X(dh) != 0) {
252*ed775ee7SAntonio Huete Jimenez ackno = GET_BE_U_6(ackp + 2);
253411677aeSAaron LI } else {
254*ed775ee7SAntonio Huete Jimenez ackno = GET_BE_U_3(ackp + 1);
25541c99275SPeter Avalos }
25641c99275SPeter Avalos
257*ed775ee7SAntonio Huete Jimenez ND_PRINT("(ack=%" PRIu64 ") ", ackno);
25841c99275SPeter Avalos }
25941c99275SPeter Avalos
260*ed775ee7SAntonio Huete Jimenez static u_int dccp_print_option(netdissect_options *, const u_char *, u_int);
26141c99275SPeter Avalos
26241c99275SPeter Avalos /**
26341c99275SPeter Avalos * dccp_print - show dccp packet
26441c99275SPeter Avalos * @bp - beginning of dccp packet
26541c99275SPeter Avalos * @data2 - beginning of enclosing
266*ed775ee7SAntonio Huete Jimenez * @len - length of ip packet
26741c99275SPeter Avalos */
268*ed775ee7SAntonio Huete Jimenez void
dccp_print(netdissect_options * ndo,const u_char * bp,const u_char * data2,u_int len)269*ed775ee7SAntonio Huete Jimenez dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2,
270411677aeSAaron LI u_int len)
27141c99275SPeter Avalos {
27241c99275SPeter Avalos const struct dccp_hdr *dh;
27341c99275SPeter Avalos const struct ip *ip;
27441c99275SPeter Avalos const struct ip6_hdr *ip6;
27541c99275SPeter Avalos const u_char *cp;
27641c99275SPeter Avalos u_short sport, dport;
27741c99275SPeter Avalos u_int hlen;
278411677aeSAaron LI u_int fixed_hdrlen;
279411677aeSAaron LI uint8_t dccph_type;
28041c99275SPeter Avalos
281*ed775ee7SAntonio Huete Jimenez ndo->ndo_protocol = "dccp";
28241c99275SPeter Avalos dh = (const struct dccp_hdr *)bp;
28341c99275SPeter Avalos
284411677aeSAaron LI ip = (const struct ip *)data2;
28541c99275SPeter Avalos if (IP_V(ip) == 6)
28641c99275SPeter Avalos ip6 = (const struct ip6_hdr *)data2;
28741c99275SPeter Avalos else
28841c99275SPeter Avalos ip6 = NULL;
289411677aeSAaron LI
290411677aeSAaron LI /* make sure we have enough data to look at the X bit */
29141c99275SPeter Avalos cp = (const u_char *)(dh + 1);
292*ed775ee7SAntonio Huete Jimenez if (cp > ndo->ndo_snapend)
293*ed775ee7SAntonio Huete Jimenez goto trunc;
294411677aeSAaron LI if (len < sizeof(struct dccp_hdr)) {
295*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-dccp - %zu bytes missing!",
296*ed775ee7SAntonio Huete Jimenez sizeof(struct dccp_hdr) - len);
29741c99275SPeter Avalos return;
29841c99275SPeter Avalos }
29941c99275SPeter Avalos
300411677aeSAaron LI /* get the length of the generic header */
301*ed775ee7SAntonio Huete Jimenez fixed_hdrlen = dccp_basic_hdr_len(ndo, dh);
302411677aeSAaron LI if (len < fixed_hdrlen) {
303*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-dccp - %u bytes missing!",
304*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
30541c99275SPeter Avalos return;
30641c99275SPeter Avalos }
307*ed775ee7SAntonio Huete Jimenez ND_TCHECK_LEN(dh, fixed_hdrlen);
30841c99275SPeter Avalos
309*ed775ee7SAntonio Huete Jimenez sport = GET_BE_U_2(dh->dccph_sport);
310*ed775ee7SAntonio Huete Jimenez dport = GET_BE_U_2(dh->dccph_dport);
311*ed775ee7SAntonio Huete Jimenez hlen = GET_U_1(dh->dccph_doff) * 4;
31241c99275SPeter Avalos
31341c99275SPeter Avalos if (ip6) {
314*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s.%u > %s.%u: ",
315*ed775ee7SAntonio Huete Jimenez GET_IP6ADDR_STRING(ip6->ip6_src), sport,
316*ed775ee7SAntonio Huete Jimenez GET_IP6ADDR_STRING(ip6->ip6_dst), dport);
317411677aeSAaron LI } else {
318*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s.%u > %s.%u: ",
319*ed775ee7SAntonio Huete Jimenez GET_IPADDR_STRING(ip->ip_src), sport,
320*ed775ee7SAntonio Huete Jimenez GET_IPADDR_STRING(ip->ip_dst), dport);
32141c99275SPeter Avalos }
32241c99275SPeter Avalos
323*ed775ee7SAntonio Huete Jimenez nd_print_protocol_caps(ndo);
324411677aeSAaron LI
325411677aeSAaron LI if (ndo->ndo_qflag) {
326*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", len - hlen);
32741c99275SPeter Avalos if (hlen > len) {
328*ed775ee7SAntonio Huete Jimenez ND_PRINT(" [bad hdr length %u - too long, > %u]",
329*ed775ee7SAntonio Huete Jimenez hlen, len);
33041c99275SPeter Avalos }
33141c99275SPeter Avalos return;
33241c99275SPeter Avalos }
33341c99275SPeter Avalos
33441c99275SPeter Avalos /* other variables in generic header */
335411677aeSAaron LI if (ndo->ndo_vflag) {
336*ed775ee7SAntonio Huete Jimenez ND_PRINT(" (CCVal %u, CsCov %u, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
33741c99275SPeter Avalos }
33841c99275SPeter Avalos
33941c99275SPeter Avalos /* checksum calculation */
340*ed775ee7SAntonio Huete Jimenez if (ndo->ndo_vflag && ND_TTEST_LEN(bp, len)) {
341411677aeSAaron LI uint16_t sum = 0, dccp_sum;
34241c99275SPeter Avalos
343*ed775ee7SAntonio Huete Jimenez dccp_sum = GET_BE_U_2(dh->dccph_checksum);
344*ed775ee7SAntonio Huete Jimenez ND_PRINT("cksum 0x%04x ", dccp_sum);
345ea7b4bf5SPeter Avalos if (IP_V(ip) == 4)
346411677aeSAaron LI sum = dccp_cksum(ndo, ip, dh, len);
347ea7b4bf5SPeter Avalos else if (IP_V(ip) == 6)
348411677aeSAaron LI sum = dccp6_cksum(ndo, ip6, dh, len);
349ea7b4bf5SPeter Avalos if (sum != 0)
350*ed775ee7SAntonio Huete Jimenez ND_PRINT("(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum));
351ea7b4bf5SPeter Avalos else
352*ed775ee7SAntonio Huete Jimenez ND_PRINT("(correct)");
35341c99275SPeter Avalos }
35441c99275SPeter Avalos
355411677aeSAaron LI if (ndo->ndo_vflag)
356*ed775ee7SAntonio Huete Jimenez ND_PRINT(")");
357*ed775ee7SAntonio Huete Jimenez ND_PRINT(" ");
358411677aeSAaron LI
359411677aeSAaron LI dccph_type = DCCPH_TYPE(dh);
360411677aeSAaron LI switch (dccph_type) {
36141c99275SPeter Avalos case DCCP_PKT_REQUEST: {
362411677aeSAaron LI const struct dccp_hdr_request *dhr =
363411677aeSAaron LI (const struct dccp_hdr_request *)(bp + fixed_hdrlen);
364411677aeSAaron LI fixed_hdrlen += 4;
365411677aeSAaron LI if (len < fixed_hdrlen) {
366*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
367411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
368*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
369411677aeSAaron LI return;
370411677aeSAaron LI }
371*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(dhr);
372*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s (service=%u) ",
373411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
374*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(dhr->dccph_req_service));
37541c99275SPeter Avalos break;
37641c99275SPeter Avalos }
37741c99275SPeter Avalos case DCCP_PKT_RESPONSE: {
378411677aeSAaron LI const struct dccp_hdr_response *dhr =
379411677aeSAaron LI (const struct dccp_hdr_response *)(bp + fixed_hdrlen);
380411677aeSAaron LI fixed_hdrlen += 12;
381411677aeSAaron LI if (len < fixed_hdrlen) {
382*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
383411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
384*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
385411677aeSAaron LI return;
386411677aeSAaron LI }
387*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(dhr);
388*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s (service=%u) ",
389411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
390*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(dhr->dccph_resp_service));
39141c99275SPeter Avalos break;
39241c99275SPeter Avalos }
39341c99275SPeter Avalos case DCCP_PKT_DATA:
394*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
39541c99275SPeter Avalos break;
39641c99275SPeter Avalos case DCCP_PKT_ACK: {
397411677aeSAaron LI fixed_hdrlen += 8;
398411677aeSAaron LI if (len < fixed_hdrlen) {
399*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
400411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
401*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
402411677aeSAaron LI return;
403411677aeSAaron LI }
404*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
40541c99275SPeter Avalos break;
40641c99275SPeter Avalos }
40741c99275SPeter Avalos case DCCP_PKT_DATAACK: {
408411677aeSAaron LI fixed_hdrlen += 8;
409411677aeSAaron LI if (len < fixed_hdrlen) {
410*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
411411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
412*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
413411677aeSAaron LI return;
414411677aeSAaron LI }
415*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
41641c99275SPeter Avalos break;
41741c99275SPeter Avalos }
41841c99275SPeter Avalos case DCCP_PKT_CLOSEREQ:
419411677aeSAaron LI fixed_hdrlen += 8;
420411677aeSAaron LI if (len < fixed_hdrlen) {
421*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
422411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
423*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
424411677aeSAaron LI return;
425411677aeSAaron LI }
426*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
42741c99275SPeter Avalos break;
42841c99275SPeter Avalos case DCCP_PKT_CLOSE:
429411677aeSAaron LI fixed_hdrlen += 8;
430411677aeSAaron LI if (len < fixed_hdrlen) {
431*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
432411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
433*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
434411677aeSAaron LI return;
435411677aeSAaron LI }
436*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
43741c99275SPeter Avalos break;
43841c99275SPeter Avalos case DCCP_PKT_RESET: {
439411677aeSAaron LI const struct dccp_hdr_reset *dhr =
440411677aeSAaron LI (const struct dccp_hdr_reset *)(bp + fixed_hdrlen);
441411677aeSAaron LI fixed_hdrlen += 12;
442411677aeSAaron LI if (len < fixed_hdrlen) {
443*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
444411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
445*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
446411677aeSAaron LI return;
447411677aeSAaron LI }
448*ed775ee7SAntonio Huete Jimenez ND_TCHECK_SIZE(dhr);
449*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s (code=%s) ",
450411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
451*ed775ee7SAntonio Huete Jimenez dccp_reset_code(GET_U_1(dhr->dccph_reset_code)));
45241c99275SPeter Avalos break;
45341c99275SPeter Avalos }
45441c99275SPeter Avalos case DCCP_PKT_SYNC:
455411677aeSAaron LI fixed_hdrlen += 8;
456411677aeSAaron LI if (len < fixed_hdrlen) {
457*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
458411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
459*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
460411677aeSAaron LI return;
461411677aeSAaron LI }
462*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
46341c99275SPeter Avalos break;
46441c99275SPeter Avalos case DCCP_PKT_SYNCACK:
465411677aeSAaron LI fixed_hdrlen += 8;
466411677aeSAaron LI if (len < fixed_hdrlen) {
467*ed775ee7SAntonio Huete Jimenez ND_PRINT("truncated-%s - %u bytes missing!",
468411677aeSAaron LI tok2str(dccp_pkt_type_str, "", dccph_type),
469*ed775ee7SAntonio Huete Jimenez fixed_hdrlen - len);
470411677aeSAaron LI return;
471411677aeSAaron LI }
472*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
47341c99275SPeter Avalos break;
47441c99275SPeter Avalos default:
475*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type));
47641c99275SPeter Avalos break;
47741c99275SPeter Avalos }
47841c99275SPeter Avalos
47941c99275SPeter Avalos if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
48041c99275SPeter Avalos (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
481411677aeSAaron LI dccp_print_ack_no(ndo, bp);
48241c99275SPeter Avalos
483411677aeSAaron LI if (ndo->ndo_vflag < 2)
48441c99275SPeter Avalos return;
48541c99275SPeter Avalos
486*ed775ee7SAntonio Huete Jimenez ND_PRINT("seq %" PRIu64, dccp_seqno(ndo, bp));
48741c99275SPeter Avalos
48841c99275SPeter Avalos /* process options */
489411677aeSAaron LI if (hlen > fixed_hdrlen){
49041c99275SPeter Avalos u_int optlen;
491411677aeSAaron LI cp = bp + fixed_hdrlen;
492*ed775ee7SAntonio Huete Jimenez ND_PRINT(" <");
49341c99275SPeter Avalos
494411677aeSAaron LI hlen -= fixed_hdrlen;
49541c99275SPeter Avalos while(1){
496411677aeSAaron LI optlen = dccp_print_option(ndo, cp, hlen);
497411677aeSAaron LI if (!optlen)
498411677aeSAaron LI break;
499411677aeSAaron LI if (hlen <= optlen)
500411677aeSAaron LI break;
50141c99275SPeter Avalos hlen -= optlen;
50241c99275SPeter Avalos cp += optlen;
503*ed775ee7SAntonio Huete Jimenez ND_PRINT(", ");
50441c99275SPeter Avalos }
505*ed775ee7SAntonio Huete Jimenez ND_PRINT(">");
50641c99275SPeter Avalos }
50741c99275SPeter Avalos return;
50841c99275SPeter Avalos trunc:
509*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
51041c99275SPeter Avalos }
51141c99275SPeter Avalos
512411677aeSAaron LI static const struct tok dccp_option_values[] = {
513411677aeSAaron LI { 0, "nop" },
514411677aeSAaron LI { 1, "mandatory" },
515411677aeSAaron LI { 2, "slowreceiver" },
516411677aeSAaron LI { 32, "change_l" },
517411677aeSAaron LI { 33, "confirm_l" },
518411677aeSAaron LI { 34, "change_r" },
519411677aeSAaron LI { 35, "confirm_r" },
520411677aeSAaron LI { 36, "initcookie" },
521411677aeSAaron LI { 37, "ndp_count" },
522411677aeSAaron LI { 38, "ack_vector0" },
523411677aeSAaron LI { 39, "ack_vector1" },
524411677aeSAaron LI { 40, "data_dropped" },
525411677aeSAaron LI { 41, "timestamp" },
526411677aeSAaron LI { 42, "timestamp_echo" },
527411677aeSAaron LI { 43, "elapsed_time" },
528411677aeSAaron LI { 44, "data_checksum" },
529411677aeSAaron LI { 0, NULL }
530411677aeSAaron LI };
53141c99275SPeter Avalos
532*ed775ee7SAntonio Huete Jimenez static u_int
dccp_print_option(netdissect_options * ndo,const u_char * option,u_int hlen)533411677aeSAaron LI dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
534411677aeSAaron LI {
535411677aeSAaron LI uint8_t optlen, i;
536411677aeSAaron LI
537*ed775ee7SAntonio Huete Jimenez if (GET_U_1(option) >= 32) {
538*ed775ee7SAntonio Huete Jimenez optlen = GET_U_1(option + 1);
53941c99275SPeter Avalos if (optlen < 2) {
540*ed775ee7SAntonio Huete Jimenez if (GET_U_1(option) >= 128)
541*ed775ee7SAntonio Huete Jimenez ND_PRINT("CCID option %u optlen too short",
542*ed775ee7SAntonio Huete Jimenez GET_U_1(option));
543411677aeSAaron LI else
544*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s optlen too short",
545*ed775ee7SAntonio Huete Jimenez tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
546411677aeSAaron LI return 0;
54741c99275SPeter Avalos }
548411677aeSAaron LI } else
549411677aeSAaron LI optlen = 1;
55041c99275SPeter Avalos
551411677aeSAaron LI if (hlen < optlen) {
552*ed775ee7SAntonio Huete Jimenez if (GET_U_1(option) >= 128)
553*ed775ee7SAntonio Huete Jimenez ND_PRINT("CCID option %u optlen goes past header length",
554*ed775ee7SAntonio Huete Jimenez GET_U_1(option));
555411677aeSAaron LI else
556*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s optlen goes past header length",
557*ed775ee7SAntonio Huete Jimenez tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
558411677aeSAaron LI return 0;
559411677aeSAaron LI }
560*ed775ee7SAntonio Huete Jimenez ND_TCHECK_LEN(option, optlen);
56141c99275SPeter Avalos
562*ed775ee7SAntonio Huete Jimenez if (GET_U_1(option) >= 128) {
563*ed775ee7SAntonio Huete Jimenez ND_PRINT("CCID option %u", GET_U_1(option));
564411677aeSAaron LI switch (optlen) {
565411677aeSAaron LI case 4:
566*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_2(option + 2));
567411677aeSAaron LI break;
568411677aeSAaron LI case 6:
569*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_4(option + 2));
570411677aeSAaron LI break;
571411677aeSAaron LI default:
572411677aeSAaron LI break;
573411677aeSAaron LI }
574411677aeSAaron LI } else {
575*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s",
576*ed775ee7SAntonio Huete Jimenez tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
577*ed775ee7SAntonio Huete Jimenez switch (GET_U_1(option)) {
57841c99275SPeter Avalos case 32:
57941c99275SPeter Avalos case 33:
58041c99275SPeter Avalos case 34:
58141c99275SPeter Avalos case 35:
582411677aeSAaron LI if (optlen < 3) {
583*ed775ee7SAntonio Huete Jimenez ND_PRINT(" optlen too short");
584411677aeSAaron LI return optlen;
585411677aeSAaron LI }
586*ed775ee7SAntonio Huete Jimenez if (GET_U_1(option + 2) < 10){
587*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %s",
588*ed775ee7SAntonio Huete Jimenez dccp_feature_nums[GET_U_1(option + 2)]);
589411677aeSAaron LI for (i = 0; i < optlen - 3; i++)
590*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u",
591*ed775ee7SAntonio Huete Jimenez GET_U_1(option + 3 + i));
59241c99275SPeter Avalos }
59341c99275SPeter Avalos break;
59441c99275SPeter Avalos case 36:
595411677aeSAaron LI if (optlen > 2) {
596*ed775ee7SAntonio Huete Jimenez ND_PRINT(" 0x");
597411677aeSAaron LI for (i = 0; i < optlen - 2; i++)
598*ed775ee7SAntonio Huete Jimenez ND_PRINT("%02x",
599*ed775ee7SAntonio Huete Jimenez GET_U_1(option + 2 + i));
600411677aeSAaron LI }
60141c99275SPeter Avalos break;
60241c99275SPeter Avalos case 37:
603411677aeSAaron LI for (i = 0; i < optlen - 2; i++)
604*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_U_1(option + 2 + i));
60541c99275SPeter Avalos break;
60641c99275SPeter Avalos case 38:
607411677aeSAaron LI if (optlen > 2) {
608*ed775ee7SAntonio Huete Jimenez ND_PRINT(" 0x");
609411677aeSAaron LI for (i = 0; i < optlen - 2; i++)
610*ed775ee7SAntonio Huete Jimenez ND_PRINT("%02x",
611*ed775ee7SAntonio Huete Jimenez GET_U_1(option + 2 + i));
612411677aeSAaron LI }
61341c99275SPeter Avalos break;
61441c99275SPeter Avalos case 39:
615411677aeSAaron LI if (optlen > 2) {
616*ed775ee7SAntonio Huete Jimenez ND_PRINT(" 0x");
617411677aeSAaron LI for (i = 0; i < optlen - 2; i++)
618*ed775ee7SAntonio Huete Jimenez ND_PRINT("%02x",
619*ed775ee7SAntonio Huete Jimenez GET_U_1(option + 2 + i));
620411677aeSAaron LI }
62141c99275SPeter Avalos break;
62241c99275SPeter Avalos case 40:
623411677aeSAaron LI if (optlen > 2) {
624*ed775ee7SAntonio Huete Jimenez ND_PRINT(" 0x");
625411677aeSAaron LI for (i = 0; i < optlen - 2; i++)
626*ed775ee7SAntonio Huete Jimenez ND_PRINT("%02x",
627*ed775ee7SAntonio Huete Jimenez GET_U_1(option + 2 + i));
628411677aeSAaron LI }
62941c99275SPeter Avalos break;
63041c99275SPeter Avalos case 41:
631411677aeSAaron LI /*
632411677aeSAaron LI * 13.1. Timestamp Option
633411677aeSAaron LI *
634411677aeSAaron LI * +--------+--------+--------+--------+--------+--------+
635411677aeSAaron LI * |00101001|00000110| Timestamp Value |
636411677aeSAaron LI * +--------+--------+--------+--------+--------+--------+
637411677aeSAaron LI * Type=41 Length=6
638411677aeSAaron LI */
639411677aeSAaron LI if (optlen == 6)
640*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_4(option + 2));
641411677aeSAaron LI else
642*ed775ee7SAntonio Huete Jimenez ND_PRINT(" [optlen != 6]");
64341c99275SPeter Avalos break;
64441c99275SPeter Avalos case 42:
645411677aeSAaron LI /*
646411677aeSAaron LI * 13.3. Timestamp Echo Option
647411677aeSAaron LI *
648411677aeSAaron LI * +--------+--------+--------+--------+--------+--------+
649411677aeSAaron LI * |00101010|00000110| Timestamp Echo |
650411677aeSAaron LI * +--------+--------+--------+--------+--------+--------+
651411677aeSAaron LI * Type=42 Len=6
652411677aeSAaron LI *
653411677aeSAaron LI * +--------+--------+------- ... -------+--------+--------+
654411677aeSAaron LI * |00101010|00001000| Timestamp Echo | Elapsed Time |
655411677aeSAaron LI * +--------+--------+------- ... -------+--------+--------+
656411677aeSAaron LI * Type=42 Len=8 (4 bytes)
657411677aeSAaron LI *
658411677aeSAaron LI * +--------+--------+------- ... -------+------- ... -------+
659411677aeSAaron LI * |00101010|00001010| Timestamp Echo | Elapsed Time |
660411677aeSAaron LI * +--------+--------+------- ... -------+------- ... -------+
661411677aeSAaron LI * Type=42 Len=10 (4 bytes) (4 bytes)
662411677aeSAaron LI */
663411677aeSAaron LI switch (optlen) {
664411677aeSAaron LI case 6:
665*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_4(option + 2));
666411677aeSAaron LI break;
667411677aeSAaron LI case 8:
668*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_4(option + 2));
669*ed775ee7SAntonio Huete Jimenez ND_PRINT(" (elapsed time %u)",
670*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(option + 6));
671411677aeSAaron LI break;
672411677aeSAaron LI case 10:
673*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_4(option + 2));
674*ed775ee7SAntonio Huete Jimenez ND_PRINT(" (elapsed time %u)",
675*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(option + 6));
676411677aeSAaron LI break;
677411677aeSAaron LI default:
678*ed775ee7SAntonio Huete Jimenez ND_PRINT(" [optlen != 6 or 8 or 10]");
679411677aeSAaron LI break;
680411677aeSAaron LI }
68141c99275SPeter Avalos break;
68241c99275SPeter Avalos case 43:
68327bfbee1SPeter Avalos if (optlen == 6)
684*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_4(option + 2));
685411677aeSAaron LI else if (optlen == 4)
686*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %u", GET_BE_U_2(option + 2));
68727bfbee1SPeter Avalos else
688*ed775ee7SAntonio Huete Jimenez ND_PRINT(" [optlen != 4 or 6]");
68941c99275SPeter Avalos break;
69041c99275SPeter Avalos case 44:
691411677aeSAaron LI if (optlen > 2) {
692*ed775ee7SAntonio Huete Jimenez ND_PRINT(" ");
693411677aeSAaron LI for (i = 0; i < optlen - 2; i++)
694*ed775ee7SAntonio Huete Jimenez ND_PRINT("%02x",
695*ed775ee7SAntonio Huete Jimenez GET_U_1(option + 2 + i));
69641c99275SPeter Avalos }
69741c99275SPeter Avalos break;
69841c99275SPeter Avalos }
69941c99275SPeter Avalos }
70041c99275SPeter Avalos
70141c99275SPeter Avalos return optlen;
70241c99275SPeter Avalos trunc:
703*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
70441c99275SPeter Avalos return 0;
70541c99275SPeter Avalos }
706