xref: /netbsd-src/external/bsd/tcpdump/dist/print-dccp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (C) Arnaldo Carvalho de Melo 2004
30f74e101Schristos  * Copyright (C) Ian McDonald 2005
40f74e101Schristos  * Copyright (C) Yoshifumi Nishida 2005
50f74e101Schristos  *
60f74e101Schristos  * This software may be distributed either under the terms of the
70f74e101Schristos  * BSD-style license that accompanies tcpdump or the GNU GPL version 2
80f74e101Schristos  */
90f74e101Schristos 
1011b3aaa1Schristos #include <sys/cdefs.h>
110f74e101Schristos #ifndef lint
12*26ba0b50Schristos __RCSID("$NetBSD: print-dccp.c,v 1.10 2024/09/02 16:15:31 christos Exp $");
130f74e101Schristos #endif
140f74e101Schristos 
15dc860a36Sspz /* \summary: Datagram Congestion Control Protocol (DCCP) printer */
16dc860a36Sspz 
17c74ad251Schristos /* specification: RFC 4340 */
18c74ad251Schristos 
19c74ad251Schristos #include <config.h>
200f74e101Schristos 
21c74ad251Schristos #include "netdissect-stdinc.h"
220f74e101Schristos 
23fdccd7e4Schristos #include "netdissect.h"
240f74e101Schristos #include "addrtoname.h"
25fdccd7e4Schristos #include "extract.h"
260f74e101Schristos #include "ip.h"
270f74e101Schristos #include "ip6.h"
280f74e101Schristos #include "ipproto.h"
290f74e101Schristos 
30ba2ff121Schristos /* RFC4340: Datagram Congestion Control Protocol (DCCP) */
31ba2ff121Schristos 
32b3a00663Schristos /**
33b3a00663Schristos  * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit
34b3a00663Schristos  * sequence number
35b3a00663Schristos  *
36b3a00663Schristos  * @dccph_sport - Relevant port on the endpoint that sent this packet
37b3a00663Schristos  * @dccph_dport - Relevant port on the other endpoint
38b3a00663Schristos  * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
39b3a00663Schristos  * @dccph_ccval - Used by the HC-Sender CCID
40b3a00663Schristos  * @dccph_cscov - Parts of the packet that are covered by the Checksum field
41b3a00663Schristos  * @dccph_checksum - Internet checksum, depends on dccph_cscov
42b3a00663Schristos  * @dccph_x - 0 = 24 bit sequence number, 1 = 48
43b3a00663Schristos  * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
44b3a00663Schristos  * @dccph_seq - 24-bit sequence number
45b3a00663Schristos  */
46b3a00663Schristos struct dccp_hdr {
47c74ad251Schristos 	nd_uint16_t	dccph_sport,
48b3a00663Schristos 			dccph_dport;
49c74ad251Schristos 	nd_uint8_t	dccph_doff;
50c74ad251Schristos 	nd_uint8_t	dccph_ccval_cscov;
51c74ad251Schristos 	nd_uint16_t	dccph_checksum;
52c74ad251Schristos 	nd_uint8_t	dccph_xtr;
53c74ad251Schristos 	nd_uint24_t	dccph_seq;
54c74ad251Schristos };
55b3a00663Schristos 
56b3a00663Schristos /**
57b3a00663Schristos  * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit
58b3a00663Schristos  * sequence number
59b3a00663Schristos  *
60b3a00663Schristos  * @dccph_sport - Relevant port on the endpoint that sent this packet
61b3a00663Schristos  * @dccph_dport - Relevant port on the other endpoint
62b3a00663Schristos  * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
63b3a00663Schristos  * @dccph_ccval - Used by the HC-Sender CCID
64b3a00663Schristos  * @dccph_cscov - Parts of the packet that are covered by the Checksum field
65b3a00663Schristos  * @dccph_checksum - Internet checksum, depends on dccph_cscov
66b3a00663Schristos  * @dccph_x - 0 = 24 bit sequence number, 1 = 48
67b3a00663Schristos  * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
68b3a00663Schristos  * @dccph_seq - 48-bit sequence number
69b3a00663Schristos  */
70b3a00663Schristos struct dccp_hdr_ext {
71c74ad251Schristos 	nd_uint16_t	dccph_sport,
72b3a00663Schristos 			dccph_dport;
73c74ad251Schristos 	nd_uint8_t	dccph_doff;
74c74ad251Schristos 	nd_uint8_t	dccph_ccval_cscov;
75c74ad251Schristos 	nd_uint16_t	dccph_checksum;
76c74ad251Schristos 	nd_uint8_t	dccph_xtr;
77c74ad251Schristos 	nd_uint8_t	reserved;
78c74ad251Schristos 	nd_uint48_t	dccph_seq;
79c74ad251Schristos };
80b3a00663Schristos 
81c74ad251Schristos #define DCCPH_CCVAL(dh)	((GET_U_1((dh)->dccph_ccval_cscov) >> 4) & 0xF)
82c74ad251Schristos #define DCCPH_CSCOV(dh)	(GET_U_1((dh)->dccph_ccval_cscov) & 0xF)
83b3a00663Schristos 
84c74ad251Schristos #define DCCPH_X(dh)	(GET_U_1((dh)->dccph_xtr) & 1)
85c74ad251Schristos #define DCCPH_TYPE(dh)	((GET_U_1((dh)->dccph_xtr) >> 1) & 0xF)
86b3a00663Schristos 
87b3a00663Schristos /**
88c74ad251Schristos  * struct dccp_hdr_request - Connection initiation request header
89b3a00663Schristos  *
90b3a00663Schristos  * @dccph_req_service - Service to which the client app wants to connect
91b3a00663Schristos  */
92b3a00663Schristos struct dccp_hdr_request {
93c74ad251Schristos 	nd_uint32_t	dccph_req_service;
94c74ad251Schristos };
95b3a00663Schristos 
96b3a00663Schristos /**
97c74ad251Schristos  * struct dccp_hdr_response - Connection initiation response header
98b3a00663Schristos  *
99b3a00663Schristos  * @dccph_resp_ack - 48 bit ack number, contains GSR
100b3a00663Schristos  * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request
101b3a00663Schristos  */
102b3a00663Schristos struct dccp_hdr_response {
103c74ad251Schristos 	nd_uint64_t	dccph_resp_ack;	/* always 8 bytes, first 2 reserved */
104c74ad251Schristos 	nd_uint32_t	dccph_resp_service;
105c74ad251Schristos };
106b3a00663Schristos 
107b3a00663Schristos /**
108b3a00663Schristos  * struct dccp_hdr_reset - Unconditionally shut down a connection
109b3a00663Schristos  *
110b3a00663Schristos  * @dccph_resp_ack - 48 bit ack number
111b3a00663Schristos  * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request
112b3a00663Schristos  */
113b3a00663Schristos struct dccp_hdr_reset {
114c74ad251Schristos 	nd_uint64_t	dccph_reset_ack;	/* always 8 bytes, first 2 reserved */
115c74ad251Schristos 	nd_uint8_t	dccph_reset_code;
116c74ad251Schristos 	nd_uint8_t	dccph_reset_data1;
117c74ad251Schristos 	nd_uint8_t	dccph_reset_data2;
118c74ad251Schristos 	nd_uint8_t	dccph_reset_data3;
119c74ad251Schristos };
120b3a00663Schristos 
121b3a00663Schristos enum dccp_pkt_type {
122b3a00663Schristos 	DCCP_PKT_REQUEST = 0,
123b3a00663Schristos 	DCCP_PKT_RESPONSE,
124b3a00663Schristos 	DCCP_PKT_DATA,
125b3a00663Schristos 	DCCP_PKT_ACK,
126b3a00663Schristos 	DCCP_PKT_DATAACK,
127b3a00663Schristos 	DCCP_PKT_CLOSEREQ,
128b3a00663Schristos 	DCCP_PKT_CLOSE,
129b3a00663Schristos 	DCCP_PKT_RESET,
130b3a00663Schristos 	DCCP_PKT_SYNC,
131ba2ff121Schristos 	DCCP_PKT_SYNCACK
132ba2ff121Schristos };
133ba2ff121Schristos 
134ba2ff121Schristos static const struct tok dccp_pkt_type_str[] = {
135ba2ff121Schristos 	{ DCCP_PKT_REQUEST, "DCCP-Request" },
136ba2ff121Schristos 	{ DCCP_PKT_RESPONSE, "DCCP-Response" },
137ba2ff121Schristos 	{ DCCP_PKT_DATA, "DCCP-Data" },
138ba2ff121Schristos 	{ DCCP_PKT_ACK, "DCCP-Ack" },
139ba2ff121Schristos 	{ DCCP_PKT_DATAACK, "DCCP-DataAck" },
140ba2ff121Schristos 	{ DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" },
141ba2ff121Schristos 	{ DCCP_PKT_CLOSE, "DCCP-Close" },
142ba2ff121Schristos 	{ DCCP_PKT_RESET, "DCCP-Reset" },
143ba2ff121Schristos 	{ DCCP_PKT_SYNC, "DCCP-Sync" },
144ba2ff121Schristos 	{ DCCP_PKT_SYNCACK, "DCCP-SyncAck" },
145ba2ff121Schristos 	{ 0, NULL}
146b3a00663Schristos };
147b3a00663Schristos 
148b3a00663Schristos enum dccp_reset_codes {
149b3a00663Schristos 	DCCP_RESET_CODE_UNSPECIFIED = 0,
150b3a00663Schristos 	DCCP_RESET_CODE_CLOSED,
151b3a00663Schristos 	DCCP_RESET_CODE_ABORTED,
152b3a00663Schristos 	DCCP_RESET_CODE_NO_CONNECTION,
153b3a00663Schristos 	DCCP_RESET_CODE_PACKET_ERROR,
154b3a00663Schristos 	DCCP_RESET_CODE_OPTION_ERROR,
155b3a00663Schristos 	DCCP_RESET_CODE_MANDATORY_ERROR,
156b3a00663Schristos 	DCCP_RESET_CODE_CONNECTION_REFUSED,
157b3a00663Schristos 	DCCP_RESET_CODE_BAD_SERVICE_CODE,
158b3a00663Schristos 	DCCP_RESET_CODE_TOO_BUSY,
159b3a00663Schristos 	DCCP_RESET_CODE_BAD_INIT_COOKIE,
160b3a00663Schristos 	DCCP_RESET_CODE_AGGRESSION_PENALTY,
161b3a00663Schristos 	__DCCP_RESET_CODE_LAST
162b3a00663Schristos };
163b3a00663Schristos 
164b3a00663Schristos 
1650f74e101Schristos static const char *dccp_reset_codes[] = {
1660f74e101Schristos 	"unspecified",
1670f74e101Schristos 	"closed",
1680f74e101Schristos 	"aborted",
1690f74e101Schristos 	"no_connection",
1700f74e101Schristos 	"packet_error",
1710f74e101Schristos 	"option_error",
1720f74e101Schristos 	"mandatory_error",
1730f74e101Schristos 	"connection_refused",
1740f74e101Schristos 	"bad_service_code",
1750f74e101Schristos 	"too_busy",
1760f74e101Schristos 	"bad_init_cookie",
1770f74e101Schristos 	"aggression_penalty",
1780f74e101Schristos };
1790f74e101Schristos 
1800f74e101Schristos static const char *dccp_feature_nums[] = {
1810f74e101Schristos 	"reserved",
1820f74e101Schristos 	"ccid",
1830f74e101Schristos 	"allow_short_seqno",
1840f74e101Schristos 	"sequence_window",
1850f74e101Schristos 	"ecn_incapable",
1860f74e101Schristos 	"ack_ratio",
1870f74e101Schristos 	"send_ack_vector",
1880f74e101Schristos 	"send_ndp_count",
1890f74e101Schristos 	"minimum checksum coverage",
1900f74e101Schristos 	"check data checksum",
1910f74e101Schristos };
1920f74e101Schristos 
193c74ad251Schristos static u_int
194c74ad251Schristos dccp_csum_coverage(netdissect_options *ndo,
195c74ad251Schristos 		   const struct dccp_hdr *dh, u_int len)
1960f74e101Schristos {
1970f74e101Schristos 	u_int cov;
1980f74e101Schristos 
1990f74e101Schristos 	if (DCCPH_CSCOV(dh) == 0)
2000f74e101Schristos 		return len;
201c74ad251Schristos 	cov = (GET_U_1(dh->dccph_doff) + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t);
2020f74e101Schristos 	return (cov > len)? len : cov;
2030f74e101Schristos }
2040f74e101Schristos 
205c74ad251Schristos static uint16_t dccp_cksum(netdissect_options *ndo, const struct ip *ip,
2060f74e101Schristos 	const struct dccp_hdr *dh, u_int len)
2070f74e101Schristos {
208fdccd7e4Schristos 	return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len,
209c74ad251Schristos 				dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP);
2100f74e101Schristos }
2110f74e101Schristos 
212c74ad251Schristos static uint16_t dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
213fdccd7e4Schristos 	const struct dccp_hdr *dh, u_int len)
2140f74e101Schristos {
215fdccd7e4Schristos 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len,
216c74ad251Schristos 				dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP);
2170f74e101Schristos }
2180f74e101Schristos 
219b3a00663Schristos static const char *dccp_reset_code(uint8_t code)
2200f74e101Schristos {
2210f74e101Schristos 	if (code >= __DCCP_RESET_CODE_LAST)
2220f74e101Schristos 		return "invalid";
2230f74e101Schristos 	return dccp_reset_codes[code];
2240f74e101Schristos }
2250f74e101Schristos 
226c74ad251Schristos static uint64_t
227c74ad251Schristos dccp_seqno(netdissect_options *ndo, const u_char *bp)
2280f74e101Schristos {
229b3a00663Schristos 	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
230b3a00663Schristos 	uint64_t seqno;
2310f74e101Schristos 
2320f74e101Schristos 	if (DCCPH_X(dh) != 0) {
233b3a00663Schristos 		const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp;
234c74ad251Schristos 		seqno = GET_BE_U_6(dhx->dccph_seq);
235b3a00663Schristos 	} else {
236c74ad251Schristos 		seqno = GET_BE_U_3(dh->dccph_seq);
2370f74e101Schristos 	}
2380f74e101Schristos 
2390f74e101Schristos 	return seqno;
2400f74e101Schristos }
2410f74e101Schristos 
242c74ad251Schristos static unsigned int
243c74ad251Schristos dccp_basic_hdr_len(netdissect_options *ndo, const struct dccp_hdr *dh)
2440f74e101Schristos {
245b3a00663Schristos 	return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr);
2460f74e101Schristos }
2470f74e101Schristos 
248b3a00663Schristos static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp)
2490f74e101Schristos {
2500f74e101Schristos 	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
251c74ad251Schristos 	const u_char *ackp = bp + dccp_basic_hdr_len(ndo, dh);
252b3a00663Schristos 	uint64_t ackno;
2530f74e101Schristos 
2540f74e101Schristos 	if (DCCPH_X(dh) != 0) {
255c74ad251Schristos 		ackno = GET_BE_U_6(ackp + 2);
256b3a00663Schristos 	} else {
257c74ad251Schristos 		ackno = GET_BE_U_3(ackp + 1);
2580f74e101Schristos 	}
2590f74e101Schristos 
260c74ad251Schristos 	ND_PRINT("(ack=%" PRIu64 ") ", ackno);
2610f74e101Schristos }
2620f74e101Schristos 
263c74ad251Schristos static u_int dccp_print_option(netdissect_options *, const u_char *, u_int);
2640f74e101Schristos 
2650f74e101Schristos /**
2660f74e101Schristos  * dccp_print - show dccp packet
2670f74e101Schristos  * @bp - beginning of dccp packet
2680f74e101Schristos  * @data2 - beginning of enclosing
269c74ad251Schristos  * @len - length of ip packet
2700f74e101Schristos  */
271c74ad251Schristos void
272c74ad251Schristos dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2,
273b3a00663Schristos 	   u_int len)
2740f74e101Schristos {
2750f74e101Schristos 	const struct dccp_hdr *dh;
2760f74e101Schristos 	const struct ip *ip;
2770f74e101Schristos 	const struct ip6_hdr *ip6;
2780f74e101Schristos 	const u_char *cp;
2790f74e101Schristos 	u_short sport, dport;
2800f74e101Schristos 	u_int hlen;
281b3a00663Schristos 	u_int fixed_hdrlen;
282ba2ff121Schristos 	uint8_t	dccph_type;
2830f74e101Schristos 
284c74ad251Schristos 	ndo->ndo_protocol = "dccp";
2850f74e101Schristos 	dh = (const struct dccp_hdr *)bp;
2860f74e101Schristos 
287fdccd7e4Schristos 	ip = (const struct ip *)data2;
2880f74e101Schristos 	if (IP_V(ip) == 6)
2890f74e101Schristos 		ip6 = (const struct ip6_hdr *)data2;
2900f74e101Schristos 	else
2910f74e101Schristos 		ip6 = NULL;
292b3a00663Schristos 
293b3a00663Schristos 	/* make sure we have enough data to look at the X bit */
2940f74e101Schristos 	cp = (const u_char *)(dh + 1);
295c74ad251Schristos 	if (cp > ndo->ndo_snapend)
296c74ad251Schristos 		goto trunc;
297b3a00663Schristos 	if (len < sizeof(struct dccp_hdr)) {
298c74ad251Schristos 		ND_PRINT("truncated-dccp - %zu bytes missing!",
299c74ad251Schristos 			 sizeof(struct dccp_hdr) - len);
3000f74e101Schristos 		return;
3010f74e101Schristos 	}
3020f74e101Schristos 
303b3a00663Schristos 	/* get the length of the generic header */
304c74ad251Schristos 	fixed_hdrlen = dccp_basic_hdr_len(ndo, dh);
305b3a00663Schristos 	if (len < fixed_hdrlen) {
306c74ad251Schristos 		ND_PRINT("truncated-dccp - %u bytes missing!",
307c74ad251Schristos 			  fixed_hdrlen - len);
3080f74e101Schristos 		return;
3090f74e101Schristos 	}
310c74ad251Schristos 	ND_TCHECK_LEN(dh, fixed_hdrlen);
3110f74e101Schristos 
312c74ad251Schristos 	sport = GET_BE_U_2(dh->dccph_sport);
313c74ad251Schristos 	dport = GET_BE_U_2(dh->dccph_dport);
314c74ad251Schristos 	hlen = GET_U_1(dh->dccph_doff) * 4;
3150f74e101Schristos 
3160f74e101Schristos 	if (ip6) {
317c74ad251Schristos 		ND_PRINT("%s.%u > %s.%u: ",
318c74ad251Schristos 			  GET_IP6ADDR_STRING(ip6->ip6_src), sport,
319c74ad251Schristos 			  GET_IP6ADDR_STRING(ip6->ip6_dst), dport);
320fdccd7e4Schristos 	} else {
321c74ad251Schristos 		ND_PRINT("%s.%u > %s.%u: ",
322c74ad251Schristos 			  GET_IPADDR_STRING(ip->ip_src), sport,
323c74ad251Schristos 			  GET_IPADDR_STRING(ip->ip_dst), dport);
3240f74e101Schristos 	}
3250f74e101Schristos 
326c74ad251Schristos 	nd_print_protocol_caps(ndo);
327ba2ff121Schristos 
328b3a00663Schristos 	if (ndo->ndo_qflag) {
329c74ad251Schristos 		ND_PRINT(" %u", len - hlen);
3300f74e101Schristos 		if (hlen > len) {
331c74ad251Schristos 			ND_PRINT(" [bad hdr length %u - too long, > %u]",
332c74ad251Schristos 				  hlen, len);
3330f74e101Schristos 		}
3340f74e101Schristos 		return;
3350f74e101Schristos 	}
3360f74e101Schristos 
3370f74e101Schristos 	/* other variables in generic header */
338b3a00663Schristos 	if (ndo->ndo_vflag) {
339c74ad251Schristos 		ND_PRINT(" (CCVal %u, CsCov %u", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
3400f74e101Schristos 	}
3410f74e101Schristos 
3420f74e101Schristos 	/* checksum calculation */
343c74ad251Schristos 	if (ndo->ndo_vflag && ND_TTEST_LEN(bp, len)) {
344b3a00663Schristos 		uint16_t sum = 0, dccp_sum;
3450f74e101Schristos 
346c74ad251Schristos 		dccp_sum = GET_BE_U_2(dh->dccph_checksum);
347c74ad251Schristos 		ND_PRINT(", cksum 0x%04x ", dccp_sum);
3480f74e101Schristos 		if (IP_V(ip) == 4)
349b3a00663Schristos 			sum = dccp_cksum(ndo, ip, dh, len);
3500f74e101Schristos 		else if (IP_V(ip) == 6)
351fdccd7e4Schristos 			sum = dccp6_cksum(ndo, ip6, dh, len);
3520f74e101Schristos 		if (sum != 0)
353c74ad251Schristos 			ND_PRINT("(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum));
3540f74e101Schristos 		else
355c74ad251Schristos 			ND_PRINT("(correct)");
3560f74e101Schristos 	}
3570f74e101Schristos 
358ba2ff121Schristos 	if (ndo->ndo_vflag)
359c74ad251Schristos 		ND_PRINT(")");
360c74ad251Schristos 	ND_PRINT(" ");
361ba2ff121Schristos 
362ba2ff121Schristos 	dccph_type = DCCPH_TYPE(dh);
363ba2ff121Schristos 	switch (dccph_type) {
3640f74e101Schristos 	case DCCP_PKT_REQUEST: {
365fdccd7e4Schristos 		const struct dccp_hdr_request *dhr =
366fdccd7e4Schristos 			(const struct dccp_hdr_request *)(bp + fixed_hdrlen);
367b3a00663Schristos 		fixed_hdrlen += 4;
368b3a00663Schristos 		if (len < fixed_hdrlen) {
369c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
370ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
371c74ad251Schristos 				  fixed_hdrlen - len);
372b3a00663Schristos 			return;
373b3a00663Schristos 		}
374c74ad251Schristos 		ND_TCHECK_SIZE(dhr);
375c74ad251Schristos 		ND_PRINT("%s (service=%u) ",
376ba2ff121Schristos 			  tok2str(dccp_pkt_type_str, "", dccph_type),
377c74ad251Schristos 			  GET_BE_U_4(dhr->dccph_req_service));
3780f74e101Schristos 		break;
3790f74e101Schristos 	}
3800f74e101Schristos 	case DCCP_PKT_RESPONSE: {
381fdccd7e4Schristos 		const struct dccp_hdr_response *dhr =
382fdccd7e4Schristos 			(const struct dccp_hdr_response *)(bp + fixed_hdrlen);
383b3a00663Schristos 		fixed_hdrlen += 12;
384b3a00663Schristos 		if (len < fixed_hdrlen) {
385c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
386ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
387c74ad251Schristos 				  fixed_hdrlen - len);
388b3a00663Schristos 			return;
389b3a00663Schristos 		}
390c74ad251Schristos 		ND_TCHECK_SIZE(dhr);
391c74ad251Schristos 		ND_PRINT("%s (service=%u) ",
392ba2ff121Schristos 			  tok2str(dccp_pkt_type_str, "", dccph_type),
393c74ad251Schristos 			  GET_BE_U_4(dhr->dccph_resp_service));
3940f74e101Schristos 		break;
3950f74e101Schristos 	}
3960f74e101Schristos 	case DCCP_PKT_DATA:
397c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
3980f74e101Schristos 		break;
3990f74e101Schristos 	case DCCP_PKT_ACK: {
400b3a00663Schristos 		fixed_hdrlen += 8;
401b3a00663Schristos 		if (len < fixed_hdrlen) {
402c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
403ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
404c74ad251Schristos 				  fixed_hdrlen - len);
405b3a00663Schristos 			return;
406b3a00663Schristos 		}
407c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
4080f74e101Schristos 		break;
4090f74e101Schristos 	}
4100f74e101Schristos 	case DCCP_PKT_DATAACK: {
411b3a00663Schristos 		fixed_hdrlen += 8;
412b3a00663Schristos 		if (len < fixed_hdrlen) {
413c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
414ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
415c74ad251Schristos 				  fixed_hdrlen - len);
416b3a00663Schristos 			return;
417b3a00663Schristos 		}
418c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
4190f74e101Schristos 		break;
4200f74e101Schristos 	}
4210f74e101Schristos 	case DCCP_PKT_CLOSEREQ:
422b3a00663Schristos 		fixed_hdrlen += 8;
423b3a00663Schristos 		if (len < fixed_hdrlen) {
424c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
425ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
426c74ad251Schristos 				  fixed_hdrlen - len);
427b3a00663Schristos 			return;
428b3a00663Schristos 		}
429c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
4300f74e101Schristos 		break;
4310f74e101Schristos 	case DCCP_PKT_CLOSE:
432b3a00663Schristos 		fixed_hdrlen += 8;
433b3a00663Schristos 		if (len < fixed_hdrlen) {
434c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
435ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
436c74ad251Schristos 				  fixed_hdrlen - len);
437b3a00663Schristos 			return;
438b3a00663Schristos 		}
439c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
4400f74e101Schristos 		break;
4410f74e101Schristos 	case DCCP_PKT_RESET: {
442fdccd7e4Schristos 		const struct dccp_hdr_reset *dhr =
443fdccd7e4Schristos 			(const struct dccp_hdr_reset *)(bp + fixed_hdrlen);
444b3a00663Schristos 		fixed_hdrlen += 12;
445b3a00663Schristos 		if (len < fixed_hdrlen) {
446c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
447ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
448c74ad251Schristos 				  fixed_hdrlen - len);
449b3a00663Schristos 			return;
450b3a00663Schristos 		}
451c74ad251Schristos 		ND_TCHECK_SIZE(dhr);
452c74ad251Schristos 		ND_PRINT("%s (code=%s) ",
453ba2ff121Schristos 			  tok2str(dccp_pkt_type_str, "", dccph_type),
454c74ad251Schristos 			  dccp_reset_code(GET_U_1(dhr->dccph_reset_code)));
4550f74e101Schristos 		break;
4560f74e101Schristos 	}
4570f74e101Schristos 	case DCCP_PKT_SYNC:
458b3a00663Schristos 		fixed_hdrlen += 8;
459b3a00663Schristos 		if (len < fixed_hdrlen) {
460c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
461ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
462c74ad251Schristos 				  fixed_hdrlen - len);
463b3a00663Schristos 			return;
464b3a00663Schristos 		}
465c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
4660f74e101Schristos 		break;
4670f74e101Schristos 	case DCCP_PKT_SYNCACK:
468b3a00663Schristos 		fixed_hdrlen += 8;
469b3a00663Schristos 		if (len < fixed_hdrlen) {
470c74ad251Schristos 			ND_PRINT("truncated-%s - %u bytes missing!",
471ba2ff121Schristos 				  tok2str(dccp_pkt_type_str, "", dccph_type),
472c74ad251Schristos 				  fixed_hdrlen - len);
473b3a00663Schristos 			return;
474b3a00663Schristos 		}
475c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type));
4760f74e101Schristos 		break;
4770f74e101Schristos 	default:
478c74ad251Schristos 		ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type));
4790f74e101Schristos 		break;
4800f74e101Schristos 	}
4810f74e101Schristos 
4820f74e101Schristos 	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
4830f74e101Schristos 			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
484b3a00663Schristos 		dccp_print_ack_no(ndo, bp);
4850f74e101Schristos 
486b3a00663Schristos 	if (ndo->ndo_vflag < 2)
4870f74e101Schristos 		return;
4880f74e101Schristos 
489c74ad251Schristos 	ND_PRINT("seq %" PRIu64, dccp_seqno(ndo, bp));
4900f74e101Schristos 
4910f74e101Schristos 	/* process options */
492b3a00663Schristos 	if (hlen > fixed_hdrlen){
4930f74e101Schristos 		u_int optlen;
494b3a00663Schristos 		cp = bp + fixed_hdrlen;
495c74ad251Schristos 		ND_PRINT(" <");
4960f74e101Schristos 
497b3a00663Schristos 		hlen -= fixed_hdrlen;
4980f74e101Schristos 		while(1){
499b3a00663Schristos 			optlen = dccp_print_option(ndo, cp, hlen);
500b3a00663Schristos 			if (!optlen)
501b3a00663Schristos 				break;
502b3a00663Schristos 			if (hlen <= optlen)
503b3a00663Schristos 				break;
5040f74e101Schristos 			hlen -= optlen;
5050f74e101Schristos 			cp += optlen;
506c74ad251Schristos 			ND_PRINT(", ");
5070f74e101Schristos 		}
508c74ad251Schristos 		ND_PRINT(">");
5090f74e101Schristos 	}
5100f74e101Schristos 	return;
5110f74e101Schristos trunc:
512c74ad251Schristos 	nd_print_trunc(ndo);
5130f74e101Schristos }
5140f74e101Schristos 
515b3a00663Schristos static const struct tok dccp_option_values[] = {
516b3a00663Schristos 	{ 0, "nop" },
517b3a00663Schristos 	{ 1, "mandatory" },
518b3a00663Schristos 	{ 2, "slowreceiver" },
519b3a00663Schristos 	{ 32, "change_l" },
520b3a00663Schristos 	{ 33, "confirm_l" },
521b3a00663Schristos 	{ 34, "change_r" },
522b3a00663Schristos 	{ 35, "confirm_r" },
523b3a00663Schristos 	{ 36, "initcookie" },
524b3a00663Schristos 	{ 37, "ndp_count" },
525b3a00663Schristos 	{ 38, "ack_vector0" },
526b3a00663Schristos 	{ 39, "ack_vector1" },
527b3a00663Schristos 	{ 40, "data_dropped" },
528b3a00663Schristos 	{ 41, "timestamp" },
529b3a00663Schristos 	{ 42, "timestamp_echo" },
530b3a00663Schristos 	{ 43, "elapsed_time" },
531b3a00663Schristos 	{ 44, "data_checksum" },
532b3a00663Schristos 	{ 0, NULL }
533b3a00663Schristos };
5340f74e101Schristos 
535c74ad251Schristos static u_int
536817e9a7eSchristos dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
537b3a00663Schristos {
538b3a00663Schristos 	uint8_t optlen, i;
539b3a00663Schristos 
540c74ad251Schristos 	if (GET_U_1(option) >= 32) {
541c74ad251Schristos 		optlen = GET_U_1(option + 1);
5420f74e101Schristos 		if (optlen < 2) {
543c74ad251Schristos 			if (GET_U_1(option) >= 128)
544c74ad251Schristos 				ND_PRINT("CCID option %u optlen too short",
545c74ad251Schristos 					 GET_U_1(option));
546b3a00663Schristos 			else
547c74ad251Schristos 				ND_PRINT("%s optlen too short",
548c74ad251Schristos 					  tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
549b3a00663Schristos 			return 0;
5500f74e101Schristos 		}
551b3a00663Schristos 	} else
552b3a00663Schristos 		optlen = 1;
5530f74e101Schristos 
554b3a00663Schristos 	if (hlen < optlen) {
555c74ad251Schristos 		if (GET_U_1(option) >= 128)
556c74ad251Schristos 			ND_PRINT("CCID option %u optlen goes past header length",
557c74ad251Schristos 				  GET_U_1(option));
558b3a00663Schristos 		else
559c74ad251Schristos 			ND_PRINT("%s optlen goes past header length",
560c74ad251Schristos 				  tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
561b3a00663Schristos 		return 0;
562b3a00663Schristos 	}
563c74ad251Schristos 	ND_TCHECK_LEN(option, optlen);
5640f74e101Schristos 
565c74ad251Schristos 	if (GET_U_1(option) >= 128) {
566c74ad251Schristos 		ND_PRINT("CCID option %u", GET_U_1(option));
567b3a00663Schristos 		switch (optlen) {
568b3a00663Schristos 			case 4:
569c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_2(option + 2));
570b3a00663Schristos 				break;
571b3a00663Schristos 			case 6:
572c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_4(option + 2));
573b3a00663Schristos 				break;
574b3a00663Schristos 			default:
575b3a00663Schristos 				break;
576b3a00663Schristos 		}
577b3a00663Schristos 	} else {
578c74ad251Schristos 		ND_PRINT("%s",
579c74ad251Schristos 			 tok2str(dccp_option_values, "Option %u", GET_U_1(option)));
580c74ad251Schristos 		switch (GET_U_1(option)) {
5810f74e101Schristos 		case 32:
5820f74e101Schristos 		case 33:
5830f74e101Schristos 		case 34:
5840f74e101Schristos 		case 35:
585b3a00663Schristos 			if (optlen < 3) {
586c74ad251Schristos 				ND_PRINT(" optlen too short");
587b3a00663Schristos 				return optlen;
588b3a00663Schristos 			}
589c74ad251Schristos 			if (GET_U_1(option + 2) < 10){
590c74ad251Schristos 				ND_PRINT(" %s",
591c74ad251Schristos 					 dccp_feature_nums[GET_U_1(option + 2)]);
592b3a00663Schristos 				for (i = 0; i < optlen - 3; i++)
593c74ad251Schristos 					ND_PRINT(" %u",
594c74ad251Schristos 						 GET_U_1(option + 3 + i));
5950f74e101Schristos 			}
5960f74e101Schristos 			break;
5970f74e101Schristos 		case 36:
598b3a00663Schristos 			if (optlen > 2) {
599c74ad251Schristos 				ND_PRINT(" 0x");
600b3a00663Schristos 				for (i = 0; i < optlen - 2; i++)
601c74ad251Schristos 					ND_PRINT("%02x",
602c74ad251Schristos 						 GET_U_1(option + 2 + i));
603b3a00663Schristos 			}
6040f74e101Schristos 			break;
6050f74e101Schristos 		case 37:
606b3a00663Schristos 			for (i = 0; i < optlen - 2; i++)
607c74ad251Schristos 				ND_PRINT(" %u", GET_U_1(option + 2 + i));
6080f74e101Schristos 			break;
6090f74e101Schristos 		case 38:
610b3a00663Schristos 			if (optlen > 2) {
611c74ad251Schristos 				ND_PRINT(" 0x");
612b3a00663Schristos 				for (i = 0; i < optlen - 2; i++)
613c74ad251Schristos 					ND_PRINT("%02x",
614c74ad251Schristos 						 GET_U_1(option + 2 + i));
615b3a00663Schristos 			}
6160f74e101Schristos 			break;
6170f74e101Schristos 		case 39:
618b3a00663Schristos 			if (optlen > 2) {
619c74ad251Schristos 				ND_PRINT(" 0x");
620b3a00663Schristos 				for (i = 0; i < optlen - 2; i++)
621c74ad251Schristos 					ND_PRINT("%02x",
622c74ad251Schristos 						 GET_U_1(option + 2 + i));
623b3a00663Schristos 			}
6240f74e101Schristos 			break;
6250f74e101Schristos 		case 40:
626b3a00663Schristos 			if (optlen > 2) {
627c74ad251Schristos 				ND_PRINT(" 0x");
628b3a00663Schristos 				for (i = 0; i < optlen - 2; i++)
629c74ad251Schristos 					ND_PRINT("%02x",
630c74ad251Schristos 						 GET_U_1(option + 2 + i));
631b3a00663Schristos 			}
6320f74e101Schristos 			break;
6330f74e101Schristos 		case 41:
634817e9a7eSchristos 		/*
635817e9a7eSchristos 		 * 13.1.  Timestamp Option
636817e9a7eSchristos 		 *
637817e9a7eSchristos 		 *  +--------+--------+--------+--------+--------+--------+
638817e9a7eSchristos 		 *  |00101001|00000110|          Timestamp Value          |
639817e9a7eSchristos 		 *  +--------+--------+--------+--------+--------+--------+
640817e9a7eSchristos 		 *   Type=41  Length=6
641817e9a7eSchristos 		 */
642817e9a7eSchristos 			if (optlen == 6)
643c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_4(option + 2));
644b3a00663Schristos 			else
645c74ad251Schristos 				ND_PRINT(" [optlen != 6]");
6460f74e101Schristos 			break;
6470f74e101Schristos 		case 42:
648817e9a7eSchristos 		/*
649817e9a7eSchristos 		 * 13.3.  Timestamp Echo Option
650817e9a7eSchristos 		 *
651817e9a7eSchristos 		 *  +--------+--------+--------+--------+--------+--------+
652817e9a7eSchristos 		 *  |00101010|00000110|           Timestamp Echo          |
653817e9a7eSchristos 		 *  +--------+--------+--------+--------+--------+--------+
654817e9a7eSchristos 		 *   Type=42    Len=6
655817e9a7eSchristos 		 *
656817e9a7eSchristos 		 *  +--------+--------+------- ... -------+--------+--------+
657817e9a7eSchristos 		 *  |00101010|00001000|  Timestamp Echo   |   Elapsed Time  |
658817e9a7eSchristos 		 *  +--------+--------+------- ... -------+--------+--------+
659817e9a7eSchristos 		 *   Type=42    Len=8       (4 bytes)
660817e9a7eSchristos 		 *
661817e9a7eSchristos 		 *  +--------+--------+------- ... -------+------- ... -------+
662817e9a7eSchristos 		 *  |00101010|00001010|  Timestamp Echo   |    Elapsed Time   |
663817e9a7eSchristos 		 *  +--------+--------+------- ... -------+------- ... -------+
664817e9a7eSchristos 		 *   Type=42   Len=10       (4 bytes)           (4 bytes)
665817e9a7eSchristos 		 */
666817e9a7eSchristos 			switch (optlen) {
667817e9a7eSchristos 			case 6:
668c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_4(option + 2));
669817e9a7eSchristos 				break;
670817e9a7eSchristos 			case 8:
671c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_4(option + 2));
672c74ad251Schristos 				ND_PRINT(" (elapsed time %u)",
673c74ad251Schristos 					 GET_BE_U_2(option + 6));
674817e9a7eSchristos 				break;
675817e9a7eSchristos 			case 10:
676c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_4(option + 2));
677c74ad251Schristos 				ND_PRINT(" (elapsed time %u)",
678c74ad251Schristos 					 GET_BE_U_4(option + 6));
679817e9a7eSchristos 				break;
680817e9a7eSchristos 			default:
681c74ad251Schristos 				ND_PRINT(" [optlen != 6 or 8 or 10]");
682817e9a7eSchristos 				break;
683817e9a7eSchristos 			}
6840f74e101Schristos 			break;
6850f74e101Schristos 		case 43:
6860f74e101Schristos 			if (optlen == 6)
687c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_4(option + 2));
688b3a00663Schristos 			else if (optlen == 4)
689c74ad251Schristos 				ND_PRINT(" %u", GET_BE_U_2(option + 2));
6900f74e101Schristos 			else
691c74ad251Schristos 				ND_PRINT(" [optlen != 4 or 6]");
6920f74e101Schristos 			break;
6930f74e101Schristos 		case 44:
694b3a00663Schristos 			if (optlen > 2) {
695c74ad251Schristos 				ND_PRINT(" ");
696b3a00663Schristos 				for (i = 0; i < optlen - 2; i++)
697c74ad251Schristos 					ND_PRINT("%02x",
698c74ad251Schristos 						 GET_U_1(option + 2 + i));
6990f74e101Schristos 			}
7000f74e101Schristos 			break;
7010f74e101Schristos 		}
7020f74e101Schristos 	}
7030f74e101Schristos 
7040f74e101Schristos 	return optlen;
7050f74e101Schristos trunc:
706c74ad251Schristos 	nd_print_trunc(ndo);
7070f74e101Schristos 	return 0;
7080f74e101Schristos }
709