1/*
2 * Copyright (C) Arnaldo Carvalho de Melo 2004
3 * Copyright (C) Ian McDonald 2005
4 * Copyright (C) Yoshifumi Nishida 2005
5 *
6 * This software may be distributed either under the terms of the
7 * BSD-style license that accompanies tcpdump or the GNU GPL version 2
8 */
9
10#ifndef lint
11static const char rcsid[] _U_ =
12    "@(#) $Header: /tcpdump/master/tcpdump/print-dccp.c,v 1.8 2007-11-09 00:44:09 guy Exp $ (LBL)";
13#endif
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <tcpdump-stdinc.h>
20
21#include "dccp.h"
22
23#include <stdio.h>
24#include <string.h>
25
26#include "interface.h"
27#include "addrtoname.h"
28#include "extract.h"			/* must come after interface.h */
29#include "ip.h"
30#ifdef INET6
31#include "ip6.h"
32#endif
33#include "ipproto.h"
34
35static const char *dccp_reset_codes[] = {
36	"unspecified",
37	"closed",
38	"aborted",
39	"no_connection",
40	"packet_error",
41	"option_error",
42	"mandatory_error",
43	"connection_refused",
44	"bad_service_code",
45	"too_busy",
46	"bad_init_cookie",
47	"aggression_penalty",
48};
49
50static const char *dccp_feature_nums[] = {
51	"reserved",
52	"ccid",
53	"allow_short_seqno",
54	"sequence_window",
55	"ecn_incapable",
56	"ack_ratio",
57	"send_ack_vector",
58	"send_ndp_count",
59	"minimum checksum coverage",
60	"check data checksum",
61};
62
63static inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len)
64{
65	u_int cov;
66
67	if (DCCPH_CSCOV(dh) == 0)
68		return len;
69	cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t);
70	return (cov > len)? len : cov;
71}
72
73static int dccp_cksum(const struct ip *ip,
74	const struct dccp_hdr *dh, u_int len)
75{
76	return nextproto4_cksum(ip, (const u_int8_t *)(void *)dh,
77	    dccp_csum_coverage(dh, len), IPPROTO_DCCP);
78}
79
80#ifdef INET6
81static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len)
82{
83	return nextproto6_cksum(ip6, (const u_int8_t *)(void *)dh,
84	    dccp_csum_coverage(dh, len), IPPROTO_DCCP);
85}
86#endif
87
88static const char *dccp_reset_code(u_int8_t code)
89{
90	if (code >= __DCCP_RESET_CODE_LAST)
91		return "invalid";
92	return dccp_reset_codes[code];
93}
94
95static u_int64_t dccp_seqno(const struct dccp_hdr *dh)
96{
97	u_int32_t seq_high = DCCPH_SEQ(dh);
98	u_int64_t seqno = EXTRACT_24BITS(&seq_high) & 0xFFFFFF;
99
100	if (DCCPH_X(dh) != 0) {
101		const struct dccp_hdr_ext *dhx = (void *)(dh + 1);
102		u_int32_t seq_low = dhx->dccph_seq_low;
103		seqno &= 0x00FFFF;  /* clear reserved field */
104		seqno = (seqno << 32) + EXTRACT_32BITS(&seq_low);
105	}
106
107	return seqno;
108}
109
110static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh)
111{
112	return sizeof(*dh) + (DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : 0);
113}
114
115static void dccp_print_ack_no(const u_char *bp)
116{
117	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
118	const struct dccp_hdr_ack_bits *dh_ack =
119		(struct dccp_hdr_ack_bits *)(bp + dccp_basic_hdr_len(dh));
120	u_int32_t ack_high;
121	u_int64_t ackno;
122
123	TCHECK2(*dh_ack,4);
124	ack_high = DCCPH_ACK(dh_ack);
125	ackno = EXTRACT_24BITS(&ack_high) & 0xFFFFFF;
126
127	if (DCCPH_X(dh) != 0) {
128		u_int32_t ack_low;
129
130		TCHECK2(*dh_ack,8);
131		ack_low = dh_ack->dccph_ack_nr_low;
132
133		ackno &= 0x00FFFF;  /* clear reserved field */
134		ackno = (ackno << 32) + EXTRACT_32BITS(&ack_low);
135	}
136
137	(void)printf("(ack=%" PRIu64 ") ", ackno);
138trunc:
139	return;
140}
141
142static inline unsigned int dccp_packet_hdr_len(const u_int8_t type)
143{
144	if (type == DCCP_PKT_DATA)
145		return 0;
146	if (type == DCCP_PKT_DATAACK	||
147	    type == DCCP_PKT_ACK	||
148	    type == DCCP_PKT_SYNC	||
149	    type == DCCP_PKT_SYNCACK	||
150	    type == DCCP_PKT_CLOSE	||
151	    type == DCCP_PKT_CLOSEREQ)
152		return sizeof(struct dccp_hdr_ack_bits);
153	if (type == DCCP_PKT_REQUEST)
154		return sizeof(struct dccp_hdr_request);
155	if (type == DCCP_PKT_RESPONSE)
156		return sizeof(struct dccp_hdr_response);
157	return sizeof(struct dccp_hdr_reset);
158}
159
160static int dccp_print_option(const u_char *option);
161
162/**
163 * dccp_print - show dccp packet
164 * @bp - beginning of dccp packet
165 * @data2 - beginning of enclosing
166 * @len - lenght of ip packet
167 */
168void dccp_print(const u_char *bp, const u_char *data2, u_int len)
169{
170	const struct dccp_hdr *dh;
171	const struct ip *ip;
172#ifdef INET6
173	const struct ip6_hdr *ip6;
174#endif
175	const u_char *cp;
176	u_short sport, dport;
177	u_int hlen;
178	u_int extlen = 0;
179
180	dh = (const struct dccp_hdr *)bp;
181
182	ip = (struct ip *)data2;
183#ifdef INET6
184	if (IP_V(ip) == 6)
185		ip6 = (const struct ip6_hdr *)data2;
186	else
187		ip6 = NULL;
188#endif /*INET6*/
189	cp = (const u_char *)(dh + 1);
190	if (cp > snapend) {
191		printf("[Invalid packet|dccp]");
192		return;
193	}
194
195	if (len < sizeof(struct dccp_hdr)) {
196		printf("truncated-dccp - %ld bytes missing!",
197			     (long)len - sizeof(struct dccp_hdr));
198		return;
199	}
200
201	sport = EXTRACT_16BITS(&dh->dccph_sport);
202	dport = EXTRACT_16BITS(&dh->dccph_dport);
203	hlen = dh->dccph_doff * 4;
204
205#ifdef INET6
206	if (ip6) {
207		(void)printf("%s.%d > %s.%d: ",
208			     ip6addr_string(&ip6->ip6_src), sport,
209			     ip6addr_string(&ip6->ip6_dst), dport);
210	} else
211#endif /*INET6*/
212	{
213		(void)printf("%s.%d > %s.%d: ",
214			     ipaddr_string(&ip->ip_src), sport,
215			     ipaddr_string(&ip->ip_dst), dport);
216	}
217	fflush(stdout);
218
219	if (qflag) {
220		(void)printf(" %d", len - hlen);
221		if (hlen > len) {
222			(void)printf("dccp [bad hdr length %u - too long, > %u]",
223			    hlen, len);
224		}
225		return;
226	}
227
228	/* other variables in generic header */
229	if (vflag) {
230		(void)printf("CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
231	}
232
233	/* checksum calculation */
234	if (vflag && TTEST2(bp[0], len)) {
235		u_int16_t sum = 0, dccp_sum;
236
237		dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
238		(void)printf("cksum 0x%04x ", dccp_sum);
239		if (IP_V(ip) == 4)
240			sum = dccp_cksum(ip, dh, len);
241#ifdef INET6
242		else if (IP_V(ip) == 6)
243			sum = dccp6_cksum(ip6, dh, len);
244#endif
245		if (sum != 0)
246			(void)printf("(incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
247		else
248			(void)printf("(correct), ");
249	}
250
251	switch (DCCPH_TYPE(dh)) {
252	case DCCP_PKT_REQUEST: {
253		struct dccp_hdr_request *dhr =
254			(struct dccp_hdr_request *)(bp + dccp_basic_hdr_len(dh));
255		TCHECK(*dhr);
256		(void)printf("request (service=%d) ",
257			     EXTRACT_32BITS(&dhr->dccph_req_service));
258		extlen += 4;
259		break;
260	}
261	case DCCP_PKT_RESPONSE: {
262		struct dccp_hdr_response *dhr =
263			(struct dccp_hdr_response *)(bp + dccp_basic_hdr_len(dh));
264		TCHECK(*dhr);
265		(void)printf("response (service=%d) ",
266			     EXTRACT_32BITS(&dhr->dccph_resp_service));
267		extlen += 12;
268		break;
269	}
270	case DCCP_PKT_DATA:
271		(void)printf("data ");
272		break;
273	case DCCP_PKT_ACK: {
274		(void)printf("ack ");
275		extlen += 8;
276		break;
277	}
278	case DCCP_PKT_DATAACK: {
279		(void)printf("dataack ");
280		extlen += 8;
281		break;
282	}
283	case DCCP_PKT_CLOSEREQ:
284		(void)printf("closereq ");
285		extlen += 8;
286		break;
287	case DCCP_PKT_CLOSE:
288		(void)printf("close ");
289		extlen += 8;
290		break;
291	case DCCP_PKT_RESET: {
292		struct dccp_hdr_reset *dhr =
293			(struct dccp_hdr_reset *)(bp + dccp_basic_hdr_len(dh));
294		TCHECK(*dhr);
295		(void)printf("reset (code=%s) ",
296			     dccp_reset_code(dhr->dccph_reset_code));
297		extlen += 12;
298		break;
299	}
300	case DCCP_PKT_SYNC:
301		(void)printf("sync ");
302		extlen += 8;
303		break;
304	case DCCP_PKT_SYNCACK:
305		(void)printf("syncack ");
306		extlen += 8;
307		break;
308	default:
309		(void)printf("invalid ");
310		break;
311	}
312
313	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
314			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
315		dccp_print_ack_no(bp);
316
317	if (vflag < 2)
318		return;
319
320	(void)printf("seq %" PRIu64, dccp_seqno(dh));
321
322	/* process options */
323	if (hlen > dccp_basic_hdr_len(dh) + extlen){
324		const u_char *cp;
325		u_int optlen;
326		cp = bp + dccp_basic_hdr_len(dh) + extlen;
327		printf(" <");
328
329		hlen -= dccp_basic_hdr_len(dh) + extlen;
330		while(1){
331			TCHECK(*cp);
332			optlen = dccp_print_option(cp);
333			if (!optlen) goto trunc2;
334			if (hlen <= optlen) break;
335			hlen -= optlen;
336			cp += optlen;
337			printf(", ");
338		}
339		printf(">");
340	}
341	return;
342trunc:
343	printf("[|dccp]");
344trunc2:
345	return;
346}
347
348static int dccp_print_option(const u_char *option)
349{
350	u_int8_t optlen, i;
351
352	TCHECK(*option);
353
354	if (*option >= 32) {
355		TCHECK(*(option+1));
356		optlen = *(option +1);
357		if (optlen < 2) {
358			printf("Option %d optlen too short",*option);
359			return 1;
360		}
361	} else optlen = 1;
362
363	TCHECK2(*option,optlen);
364
365	switch (*option){
366	case 0:
367		printf("nop");
368		break;
369	case 1:
370		printf("mandatory");
371		break;
372	case 2:
373		printf("slowreceiver");
374		break;
375	case 32:
376		printf("change_l");
377		if (*(option +2) < 10){
378			printf(" %s", dccp_feature_nums[*(option +2)]);
379			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
380		}
381		break;
382	case 33:
383		printf("confirm_l");
384		if (*(option +2) < 10){
385			printf(" %s", dccp_feature_nums[*(option +2)]);
386			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
387		}
388		break;
389	case 34:
390	        printf("change_r");
391		if (*(option +2) < 10){
392			printf(" %s", dccp_feature_nums[*(option +2)]);
393			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
394		}
395		break;
396	case 35:
397		printf("confirm_r");
398		if (*(option +2) < 10){
399			printf(" %s", dccp_feature_nums[*(option +2)]);
400			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
401		}
402		break;
403	case 36:
404		printf("initcookie 0x");
405		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
406		break;
407	case 37:
408		printf("ndp_count");
409		for (i = 0; i < optlen -2; i ++) printf(" %d", *(option +2 + i));
410		break;
411	case 38:
412		printf("ack_vector0 0x");
413		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
414		break;
415	case 39:
416		printf("ack_vector1 0x");
417		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
418		break;
419	case 40:
420		printf("data_dropped 0x");
421		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
422		break;
423	case 41:
424		printf("timestamp %u", EXTRACT_32BITS(option + 2));
425		break;
426	case 42:
427		printf("timestamp_echo %u", EXTRACT_32BITS(option + 2));
428		break;
429	case 43:
430		printf("elapsed_time ");
431		if (optlen == 6)
432			printf("%u", EXTRACT_32BITS(option + 2));
433		else
434			printf("%u", EXTRACT_16BITS(option + 2));
435		break;
436	case 44:
437		printf("data_checksum ");
438		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
439		break;
440	default :
441		if (*option >= 128) {
442			printf("CCID option %d",*option);
443			switch (optlen) {
444				case 4:
445					printf(" %u", EXTRACT_16BITS(option + 2));
446					break;
447				case 6:
448					printf(" %u", EXTRACT_32BITS(option + 2));
449					break;
450				default:
451					break;
452			}
453			break;
454		}
455
456		printf("unknown_opt %d", *option);
457		break;
458	}
459
460	return optlen;
461trunc:
462	printf("[|dccp]");
463	return 0;
464}
465