xref: /aosp_15_r20/external/tcpdump/print-dccp.c (revision 05b00f6010a2396e3db2409989fc67270046269f)
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