1162017Ssam/*
2162017Ssam * Copyright (C) Arnaldo Carvalho de Melo 2004
3162017Ssam * Copyright (C) Ian McDonald 2005
4162017Ssam * Copyright (C) Yoshifumi Nishida 2005
5162017Ssam *
6162017Ssam * This software may be distributed either under the terms of the
7162017Ssam * BSD-style license that accompanies tcpdump or the GNU GPL version 2
8162017Ssam */
9162017Ssam
10162017Ssam#ifndef lint
11162017Ssamstatic const char rcsid[] _U_ =
12214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-dccp.c,v 1.8 2007-11-09 00:44:09 guy Exp $ (LBL)";
13162017Ssam#endif
14162017Ssam
15162017Ssam#ifdef HAVE_CONFIG_H
16162017Ssam#include "config.h"
17162017Ssam#endif
18162017Ssam
19162017Ssam#include <tcpdump-stdinc.h>
20162017Ssam
21162017Ssam#include "dccp.h"
22162017Ssam
23162017Ssam#include <stdio.h>
24162017Ssam#include <string.h>
25162017Ssam
26162017Ssam#include "interface.h"
27162017Ssam#include "addrtoname.h"
28162017Ssam#include "extract.h"			/* must come after interface.h */
29162017Ssam#include "ip.h"
30162017Ssam#ifdef INET6
31162017Ssam#include "ip6.h"
32162017Ssam#endif
33162017Ssam#include "ipproto.h"
34162017Ssam
35162017Ssamstatic const char *dccp_reset_codes[] = {
36162017Ssam	"unspecified",
37162017Ssam	"closed",
38162017Ssam	"aborted",
39162017Ssam	"no_connection",
40162017Ssam	"packet_error",
41162017Ssam	"option_error",
42162017Ssam	"mandatory_error",
43162017Ssam	"connection_refused",
44162017Ssam	"bad_service_code",
45162017Ssam	"too_busy",
46162017Ssam	"bad_init_cookie",
47162017Ssam	"aggression_penalty",
48162017Ssam};
49162017Ssam
50162017Ssamstatic const char *dccp_feature_nums[] = {
51162017Ssam	"reserved",
52162017Ssam	"ccid",
53162017Ssam	"allow_short_seqno",
54162017Ssam	"sequence_window",
55162017Ssam	"ecn_incapable",
56162017Ssam	"ack_ratio",
57162017Ssam	"send_ack_vector",
58162017Ssam	"send_ndp_count",
59162017Ssam	"minimum checksum coverage",
60162017Ssam	"check data checksum",
61162017Ssam};
62162017Ssam
63236192Sdelphijstatic inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len)
64190207Srpaulo{
65190207Srpaulo	u_int cov;
66190207Srpaulo
67190207Srpaulo	if (DCCPH_CSCOV(dh) == 0)
68190207Srpaulo		return len;
69190207Srpaulo	cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t);
70190207Srpaulo	return (cov > len)? len : cov;
71190207Srpaulo}
72190207Srpaulo
73162017Ssamstatic int dccp_cksum(const struct ip *ip,
74162017Ssam	const struct dccp_hdr *dh, u_int len)
75162017Ssam{
76236192Sdelphij	return nextproto4_cksum(ip, (const u_int8_t *)(void *)dh,
77236192Sdelphij	    dccp_csum_coverage(dh, len), IPPROTO_DCCP);
78162017Ssam}
79162017Ssam
80162017Ssam#ifdef INET6
81162017Ssamstatic int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len)
82162017Ssam{
83236192Sdelphij	return nextproto6_cksum(ip6, (const u_int8_t *)(void *)dh,
84236192Sdelphij	    dccp_csum_coverage(dh, len), IPPROTO_DCCP);
85162017Ssam}
86162017Ssam#endif
87162017Ssam
88162017Ssamstatic const char *dccp_reset_code(u_int8_t code)
89162017Ssam{
90162017Ssam	if (code >= __DCCP_RESET_CODE_LAST)
91162017Ssam		return "invalid";
92162017Ssam	return dccp_reset_codes[code];
93162017Ssam}
94162017Ssam
95162017Ssamstatic u_int64_t dccp_seqno(const struct dccp_hdr *dh)
96162017Ssam{
97162017Ssam	u_int32_t seq_high = DCCPH_SEQ(dh);
98162017Ssam	u_int64_t seqno = EXTRACT_24BITS(&seq_high) & 0xFFFFFF;
99162017Ssam
100162017Ssam	if (DCCPH_X(dh) != 0) {
101172683Smlaier		const struct dccp_hdr_ext *dhx = (void *)(dh + 1);
102162017Ssam		u_int32_t seq_low = dhx->dccph_seq_low;
103162017Ssam		seqno &= 0x00FFFF;  /* clear reserved field */
104162017Ssam		seqno = (seqno << 32) + EXTRACT_32BITS(&seq_low);
105162017Ssam	}
106162017Ssam
107162017Ssam	return seqno;
108162017Ssam}
109162017Ssam
110172683Smlaierstatic inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh)
111162017Ssam{
112172683Smlaier	return sizeof(*dh) + (DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : 0);
113172683Smlaier}
114162017Ssam
115172683Smlaierstatic void dccp_print_ack_no(const u_char *bp)
116172683Smlaier{
117172683Smlaier	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
118172683Smlaier	const struct dccp_hdr_ack_bits *dh_ack =
119172683Smlaier		(struct dccp_hdr_ack_bits *)(bp + dccp_basic_hdr_len(dh));
120172683Smlaier	u_int32_t ack_high;
121172683Smlaier	u_int64_t ackno;
122172683Smlaier
123172683Smlaier	TCHECK2(*dh_ack,4);
124172683Smlaier	ack_high = DCCPH_ACK(dh_ack);
125172683Smlaier	ackno = EXTRACT_24BITS(&ack_high) & 0xFFFFFF;
126172683Smlaier
127162017Ssam	if (DCCPH_X(dh) != 0) {
128172683Smlaier		u_int32_t ack_low;
129172683Smlaier
130172683Smlaier		TCHECK2(*dh_ack,8);
131172683Smlaier		ack_low = dh_ack->dccph_ack_nr_low;
132172683Smlaier
133162017Ssam		ackno &= 0x00FFFF;  /* clear reserved field */
134162017Ssam		ackno = (ackno << 32) + EXTRACT_32BITS(&ack_low);
135162017Ssam	}
136162017Ssam
137172683Smlaier	(void)printf("(ack=%" PRIu64 ") ", ackno);
138172683Smlaiertrunc:
139172683Smlaier	return;
140162017Ssam}
141162017Ssam
142162017Ssamstatic inline unsigned int dccp_packet_hdr_len(const u_int8_t type)
143162017Ssam{
144162017Ssam	if (type == DCCP_PKT_DATA)
145162017Ssam		return 0;
146162017Ssam	if (type == DCCP_PKT_DATAACK	||
147162017Ssam	    type == DCCP_PKT_ACK	||
148162017Ssam	    type == DCCP_PKT_SYNC	||
149162017Ssam	    type == DCCP_PKT_SYNCACK	||
150162017Ssam	    type == DCCP_PKT_CLOSE	||
151162017Ssam	    type == DCCP_PKT_CLOSEREQ)
152162017Ssam		return sizeof(struct dccp_hdr_ack_bits);
153162017Ssam	if (type == DCCP_PKT_REQUEST)
154162017Ssam		return sizeof(struct dccp_hdr_request);
155162017Ssam	if (type == DCCP_PKT_RESPONSE)
156162017Ssam		return sizeof(struct dccp_hdr_response);
157162017Ssam	return sizeof(struct dccp_hdr_reset);
158162017Ssam}
159162017Ssam
160162017Ssamstatic int dccp_print_option(const u_char *option);
161162017Ssam
162162017Ssam/**
163162017Ssam * dccp_print - show dccp packet
164162017Ssam * @bp - beginning of dccp packet
165162017Ssam * @data2 - beginning of enclosing
166162017Ssam * @len - lenght of ip packet
167162017Ssam */
168162017Ssamvoid dccp_print(const u_char *bp, const u_char *data2, u_int len)
169162017Ssam{
170162017Ssam	const struct dccp_hdr *dh;
171162017Ssam	const struct ip *ip;
172162017Ssam#ifdef INET6
173162017Ssam	const struct ip6_hdr *ip6;
174162017Ssam#endif
175162017Ssam	const u_char *cp;
176162017Ssam	u_short sport, dport;
177162017Ssam	u_int hlen;
178162017Ssam	u_int extlen = 0;
179162017Ssam
180162017Ssam	dh = (const struct dccp_hdr *)bp;
181162017Ssam
182162017Ssam	ip = (struct ip *)data2;
183162017Ssam#ifdef INET6
184162017Ssam	if (IP_V(ip) == 6)
185162017Ssam		ip6 = (const struct ip6_hdr *)data2;
186162017Ssam	else
187162017Ssam		ip6 = NULL;
188162017Ssam#endif /*INET6*/
189162017Ssam	cp = (const u_char *)(dh + 1);
190162017Ssam	if (cp > snapend) {
191162017Ssam		printf("[Invalid packet|dccp]");
192162017Ssam		return;
193162017Ssam	}
194162017Ssam
195162017Ssam	if (len < sizeof(struct dccp_hdr)) {
196162017Ssam		printf("truncated-dccp - %ld bytes missing!",
197162017Ssam			     (long)len - sizeof(struct dccp_hdr));
198162017Ssam		return;
199162017Ssam	}
200162017Ssam
201162017Ssam	sport = EXTRACT_16BITS(&dh->dccph_sport);
202162017Ssam	dport = EXTRACT_16BITS(&dh->dccph_dport);
203162017Ssam	hlen = dh->dccph_doff * 4;
204162017Ssam
205162017Ssam#ifdef INET6
206162017Ssam	if (ip6) {
207162017Ssam		(void)printf("%s.%d > %s.%d: ",
208162017Ssam			     ip6addr_string(&ip6->ip6_src), sport,
209162017Ssam			     ip6addr_string(&ip6->ip6_dst), dport);
210162017Ssam	} else
211162017Ssam#endif /*INET6*/
212162017Ssam	{
213162017Ssam		(void)printf("%s.%d > %s.%d: ",
214162017Ssam			     ipaddr_string(&ip->ip_src), sport,
215162017Ssam			     ipaddr_string(&ip->ip_dst), dport);
216162017Ssam	}
217162017Ssam	fflush(stdout);
218162017Ssam
219162017Ssam	if (qflag) {
220162017Ssam		(void)printf(" %d", len - hlen);
221162017Ssam		if (hlen > len) {
222162017Ssam			(void)printf("dccp [bad hdr length %u - too long, > %u]",
223162017Ssam			    hlen, len);
224162017Ssam		}
225162017Ssam		return;
226162017Ssam	}
227162017Ssam
228162017Ssam	/* other variables in generic header */
229162017Ssam	if (vflag) {
230162017Ssam		(void)printf("CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
231162017Ssam	}
232162017Ssam
233162017Ssam	/* checksum calculation */
234190207Srpaulo	if (vflag && TTEST2(bp[0], len)) {
235190207Srpaulo		u_int16_t sum = 0, dccp_sum;
236190207Srpaulo
237190207Srpaulo		dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
238190207Srpaulo		(void)printf("cksum 0x%04x ", dccp_sum);
239190207Srpaulo		if (IP_V(ip) == 4)
240190207Srpaulo			sum = dccp_cksum(ip, dh, len);
241162017Ssam#ifdef INET6
242190207Srpaulo		else if (IP_V(ip) == 6)
243162017Ssam			sum = dccp6_cksum(ip6, dh, len);
244190207Srpaulo#endif
245190207Srpaulo		if (sum != 0)
246190207Srpaulo			(void)printf("(incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
247190207Srpaulo		else
248190207Srpaulo			(void)printf("(correct), ");
249162017Ssam	}
250162017Ssam
251162017Ssam	switch (DCCPH_TYPE(dh)) {
252162017Ssam	case DCCP_PKT_REQUEST: {
253162017Ssam		struct dccp_hdr_request *dhr =
254162017Ssam			(struct dccp_hdr_request *)(bp + dccp_basic_hdr_len(dh));
255162017Ssam		TCHECK(*dhr);
256172683Smlaier		(void)printf("request (service=%d) ",
257172683Smlaier			     EXTRACT_32BITS(&dhr->dccph_req_service));
258162017Ssam		extlen += 4;
259162017Ssam		break;
260162017Ssam	}
261162017Ssam	case DCCP_PKT_RESPONSE: {
262162017Ssam		struct dccp_hdr_response *dhr =
263162017Ssam			(struct dccp_hdr_response *)(bp + dccp_basic_hdr_len(dh));
264162017Ssam		TCHECK(*dhr);
265172683Smlaier		(void)printf("response (service=%d) ",
266172683Smlaier			     EXTRACT_32BITS(&dhr->dccph_resp_service));
267162017Ssam		extlen += 12;
268162017Ssam		break;
269162017Ssam	}
270162017Ssam	case DCCP_PKT_DATA:
271162017Ssam		(void)printf("data ");
272162017Ssam		break;
273162017Ssam	case DCCP_PKT_ACK: {
274172683Smlaier		(void)printf("ack ");
275162017Ssam		extlen += 8;
276162017Ssam		break;
277162017Ssam	}
278162017Ssam	case DCCP_PKT_DATAACK: {
279172683Smlaier		(void)printf("dataack ");
280162017Ssam		extlen += 8;
281162017Ssam		break;
282162017Ssam	}
283162017Ssam	case DCCP_PKT_CLOSEREQ:
284162017Ssam		(void)printf("closereq ");
285162017Ssam		extlen += 8;
286162017Ssam		break;
287162017Ssam	case DCCP_PKT_CLOSE:
288162017Ssam		(void)printf("close ");
289162017Ssam		extlen += 8;
290162017Ssam		break;
291162017Ssam	case DCCP_PKT_RESET: {
292162017Ssam		struct dccp_hdr_reset *dhr =
293162017Ssam			(struct dccp_hdr_reset *)(bp + dccp_basic_hdr_len(dh));
294162017Ssam		TCHECK(*dhr);
295162017Ssam		(void)printf("reset (code=%s) ",
296162017Ssam			     dccp_reset_code(dhr->dccph_reset_code));
297162017Ssam		extlen += 12;
298162017Ssam		break;
299162017Ssam	}
300162017Ssam	case DCCP_PKT_SYNC:
301162017Ssam		(void)printf("sync ");
302162017Ssam		extlen += 8;
303162017Ssam		break;
304162017Ssam	case DCCP_PKT_SYNCACK:
305162017Ssam		(void)printf("syncack ");
306162017Ssam		extlen += 8;
307162017Ssam		break;
308162017Ssam	default:
309162017Ssam		(void)printf("invalid ");
310162017Ssam		break;
311162017Ssam	}
312162017Ssam
313172683Smlaier	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
314172683Smlaier			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
315172683Smlaier		dccp_print_ack_no(bp);
316172683Smlaier
317162017Ssam	if (vflag < 2)
318162017Ssam		return;
319162017Ssam
320162017Ssam	(void)printf("seq %" PRIu64, dccp_seqno(dh));
321162017Ssam
322162017Ssam	/* process options */
323162017Ssam	if (hlen > dccp_basic_hdr_len(dh) + extlen){
324162017Ssam		const u_char *cp;
325162017Ssam		u_int optlen;
326162017Ssam		cp = bp + dccp_basic_hdr_len(dh) + extlen;
327162017Ssam		printf(" <");
328162017Ssam
329162017Ssam		hlen -= dccp_basic_hdr_len(dh) + extlen;
330162017Ssam		while(1){
331162017Ssam			TCHECK(*cp);
332162017Ssam			optlen = dccp_print_option(cp);
333162017Ssam			if (!optlen) goto trunc2;
334162017Ssam			if (hlen <= optlen) break;
335162017Ssam			hlen -= optlen;
336162017Ssam			cp += optlen;
337162017Ssam			printf(", ");
338162017Ssam		}
339162017Ssam		printf(">");
340162017Ssam	}
341162017Ssam	return;
342162017Ssamtrunc:
343162017Ssam	printf("[|dccp]");
344162017Ssamtrunc2:
345162017Ssam	return;
346162017Ssam}
347162017Ssam
348162017Ssamstatic int dccp_print_option(const u_char *option)
349162017Ssam{
350162017Ssam	u_int8_t optlen, i;
351162017Ssam
352162017Ssam	TCHECK(*option);
353162017Ssam
354162017Ssam	if (*option >= 32) {
355162017Ssam		TCHECK(*(option+1));
356162017Ssam		optlen = *(option +1);
357162017Ssam		if (optlen < 2) {
358162017Ssam			printf("Option %d optlen too short",*option);
359162017Ssam			return 1;
360162017Ssam		}
361162017Ssam	} else optlen = 1;
362162017Ssam
363162017Ssam	TCHECK2(*option,optlen);
364162017Ssam
365162017Ssam	switch (*option){
366162017Ssam	case 0:
367162017Ssam		printf("nop");
368162017Ssam		break;
369162017Ssam	case 1:
370162017Ssam		printf("mandatory");
371162017Ssam		break;
372162017Ssam	case 2:
373162017Ssam		printf("slowreceiver");
374162017Ssam		break;
375162017Ssam	case 32:
376162017Ssam		printf("change_l");
377162017Ssam		if (*(option +2) < 10){
378162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
379162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
380162017Ssam		}
381162017Ssam		break;
382162017Ssam	case 33:
383162017Ssam		printf("confirm_l");
384162017Ssam		if (*(option +2) < 10){
385162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
386162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
387162017Ssam		}
388162017Ssam		break;
389162017Ssam	case 34:
390162017Ssam	        printf("change_r");
391162017Ssam		if (*(option +2) < 10){
392162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
393162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
394162017Ssam		}
395162017Ssam		break;
396162017Ssam	case 35:
397162017Ssam		printf("confirm_r");
398162017Ssam		if (*(option +2) < 10){
399162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
400162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
401162017Ssam		}
402162017Ssam		break;
403162017Ssam	case 36:
404162017Ssam		printf("initcookie 0x");
405162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
406162017Ssam		break;
407162017Ssam	case 37:
408162017Ssam		printf("ndp_count");
409162017Ssam		for (i = 0; i < optlen -2; i ++) printf(" %d", *(option +2 + i));
410162017Ssam		break;
411162017Ssam	case 38:
412162017Ssam		printf("ack_vector0 0x");
413162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
414162017Ssam		break;
415162017Ssam	case 39:
416162017Ssam		printf("ack_vector1 0x");
417162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
418162017Ssam		break;
419162017Ssam	case 40:
420162017Ssam		printf("data_dropped 0x");
421162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
422162017Ssam		break;
423162017Ssam	case 41:
424214478Srpaulo		printf("timestamp %u", EXTRACT_32BITS(option + 2));
425162017Ssam		break;
426162017Ssam	case 42:
427214478Srpaulo		printf("timestamp_echo %u", EXTRACT_32BITS(option + 2));
428162017Ssam		break;
429162017Ssam	case 43:
430162017Ssam		printf("elapsed_time ");
431214478Srpaulo		if (optlen == 6)
432214478Srpaulo			printf("%u", EXTRACT_32BITS(option + 2));
433214478Srpaulo		else
434214478Srpaulo			printf("%u", EXTRACT_16BITS(option + 2));
435162017Ssam		break;
436162017Ssam	case 44:
437162017Ssam		printf("data_checksum ");
438162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
439162017Ssam		break;
440162017Ssam	default :
441162017Ssam		if (*option >= 128) {
442162017Ssam			printf("CCID option %d",*option);
443162017Ssam			switch (optlen) {
444162017Ssam				case 4:
445214478Srpaulo					printf(" %u", EXTRACT_16BITS(option + 2));
446162017Ssam					break;
447162017Ssam				case 6:
448214478Srpaulo					printf(" %u", EXTRACT_32BITS(option + 2));
449162017Ssam					break;
450162017Ssam				default:
451162017Ssam					break;
452162017Ssam			}
453162017Ssam			break;
454162017Ssam		}
455162017Ssam
456162017Ssam		printf("unknown_opt %d", *option);
457162017Ssam		break;
458162017Ssam	}
459162017Ssam
460162017Ssam	return optlen;
461162017Ssamtrunc:
462162017Ssam	printf("[|dccp]");
463162017Ssam	return 0;
464162017Ssam}
465