xref: /freebsd/contrib/tcpdump/print-dccp.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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
11 static const char rcsid[] _U_ =
12     "@(#) $Header: /tcpdump/master/tcpdump/print-dccp.c,v 1.1.2.6 2006/02/19 05:08:44 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 
35 static 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 
50 static 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 
63 static int dccp_cksum(const struct ip *ip,
64 	const struct dccp_hdr *dh, u_int len)
65 {
66 	union phu {
67 		struct phdr {
68 			u_int32_t src;
69 			u_int32_t dst;
70 			u_char mbz;
71 			u_char proto;
72 			u_int16_t len;
73 		} ph;
74 		u_int16_t pa[6];
75 	} phu;
76 	const u_int16_t *sp;
77 
78 	/* pseudo-header.. */
79 	phu.ph.mbz = 0;
80 	phu.ph.len = htons(len);
81 	phu.ph.proto = IPPROTO_DCCP;
82 	memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
83 	if (IP_HL(ip) == 5)
84 		memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
85 	else
86 		phu.ph.dst = ip_finddst(ip);
87 
88 	sp = &phu.pa[0];
89 	return in_cksum((u_short *)dh, len, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
90 }
91 
92 #ifdef INET6
93 static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len)
94 {
95 	size_t i;
96 	const u_int16_t *sp;
97 	u_int32_t sum;
98 	union {
99 		struct {
100 			struct in6_addr ph_src;
101 			struct in6_addr ph_dst;
102 			u_int32_t   ph_len;
103 			u_int8_t    ph_zero[3];
104 			u_int8_t    ph_nxt;
105 		} ph;
106 		u_int16_t pa[20];
107 	} phu;
108 
109 	/* pseudo-header */
110 	memset(&phu, 0, sizeof(phu));
111 	phu.ph.ph_src = ip6->ip6_src;
112 	phu.ph.ph_dst = ip6->ip6_dst;
113 	phu.ph.ph_len = htonl(len);
114 	phu.ph.ph_nxt = IPPROTO_DCCP;
115 
116 	sum = 0;
117 	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
118 		sum += phu.pa[i];
119 
120 	sp = (const u_int16_t *)dh;
121 
122 	for (i = 0; i < (len & ~1); i += 2)
123 		sum += *sp++;
124 
125 	if (len & 1)
126 		sum += htons((*(const u_int8_t *)sp) << 8);
127 
128 	while (sum > 0xffff)
129 		sum = (sum & 0xffff) + (sum >> 16);
130 	sum = ~sum & 0xffff;
131 
132 	return (sum);
133 }
134 #endif
135 
136 static const char *dccp_reset_code(u_int8_t code)
137 {
138 	if (code >= __DCCP_RESET_CODE_LAST)
139 		return "invalid";
140 	return dccp_reset_codes[code];
141 }
142 
143 static u_int64_t dccp_seqno(const struct dccp_hdr *dh)
144 {
145 	u_int32_t seq_high = DCCPH_SEQ(dh);
146 	u_int64_t seqno = EXTRACT_24BITS(&seq_high) & 0xFFFFFF;
147 
148 	if (DCCPH_X(dh) != 0) {
149 		const struct dccp_hdr_ext *dhx = (void *)(dh + 1);
150 		u_int32_t seq_low = dhx->dccph_seq_low;
151 		seqno &= 0x00FFFF;  /* clear reserved field */
152 		seqno = (seqno << 32) + EXTRACT_32BITS(&seq_low);
153 	}
154 
155 	return seqno;
156 }
157 
158 static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh)
159 {
160 	return sizeof(*dh) + (DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : 0);
161 }
162 
163 static void dccp_print_ack_no(const u_char *bp)
164 {
165 	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
166 	const struct dccp_hdr_ack_bits *dh_ack =
167 		(struct dccp_hdr_ack_bits *)(bp + dccp_basic_hdr_len(dh));
168 	u_int32_t ack_high;
169 	u_int64_t ackno;
170 
171 	TCHECK2(*dh_ack,4);
172 	ack_high = DCCPH_ACK(dh_ack);
173 	ackno = EXTRACT_24BITS(&ack_high) & 0xFFFFFF;
174 
175 	if (DCCPH_X(dh) != 0) {
176 		u_int32_t ack_low;
177 
178 		TCHECK2(*dh_ack,8);
179 		ack_low = dh_ack->dccph_ack_nr_low;
180 
181 		ackno &= 0x00FFFF;  /* clear reserved field */
182 		ackno = (ackno << 32) + EXTRACT_32BITS(&ack_low);
183 	}
184 
185 	(void)printf("(ack=%" PRIu64 ") ", ackno);
186 trunc:
187 	return;
188 }
189 
190 static inline unsigned int dccp_packet_hdr_len(const u_int8_t type)
191 {
192 	if (type == DCCP_PKT_DATA)
193 		return 0;
194 	if (type == DCCP_PKT_DATAACK	||
195 	    type == DCCP_PKT_ACK	||
196 	    type == DCCP_PKT_SYNC	||
197 	    type == DCCP_PKT_SYNCACK	||
198 	    type == DCCP_PKT_CLOSE	||
199 	    type == DCCP_PKT_CLOSEREQ)
200 		return sizeof(struct dccp_hdr_ack_bits);
201 	if (type == DCCP_PKT_REQUEST)
202 		return sizeof(struct dccp_hdr_request);
203 	if (type == DCCP_PKT_RESPONSE)
204 		return sizeof(struct dccp_hdr_response);
205 	return sizeof(struct dccp_hdr_reset);
206 }
207 
208 static int dccp_print_option(const u_char *option);
209 
210 /**
211  * dccp_print - show dccp packet
212  * @bp - beginning of dccp packet
213  * @data2 - beginning of enclosing
214  * @len - lenght of ip packet
215  */
216 void dccp_print(const u_char *bp, const u_char *data2, u_int len)
217 {
218 	const struct dccp_hdr *dh;
219 	const struct ip *ip;
220 #ifdef INET6
221 	const struct ip6_hdr *ip6;
222 #endif
223 	const u_char *cp;
224 	u_short sport, dport;
225 	u_int hlen;
226 	u_int extlen = 0;
227 
228 	dh = (const struct dccp_hdr *)bp;
229 
230 	ip = (struct ip *)data2;
231 #ifdef INET6
232 	if (IP_V(ip) == 6)
233 		ip6 = (const struct ip6_hdr *)data2;
234 	else
235 		ip6 = NULL;
236 #endif /*INET6*/
237 	cp = (const u_char *)(dh + 1);
238 	if (cp > snapend) {
239 		printf("[Invalid packet|dccp]");
240 		return;
241 	}
242 
243 	if (len < sizeof(struct dccp_hdr)) {
244 		printf("truncated-dccp - %ld bytes missing!",
245 			     (long)len - sizeof(struct dccp_hdr));
246 		return;
247 	}
248 
249 	sport = EXTRACT_16BITS(&dh->dccph_sport);
250 	dport = EXTRACT_16BITS(&dh->dccph_dport);
251 	hlen = dh->dccph_doff * 4;
252 
253 #ifdef INET6
254 	if (ip6) {
255 		(void)printf("%s.%d > %s.%d: ",
256 			     ip6addr_string(&ip6->ip6_src), sport,
257 			     ip6addr_string(&ip6->ip6_dst), dport);
258 	} else
259 #endif /*INET6*/
260 	{
261 		(void)printf("%s.%d > %s.%d: ",
262 			     ipaddr_string(&ip->ip_src), sport,
263 			     ipaddr_string(&ip->ip_dst), dport);
264 	}
265 	fflush(stdout);
266 
267 	if (qflag) {
268 		(void)printf(" %d", len - hlen);
269 		if (hlen > len) {
270 			(void)printf("dccp [bad hdr length %u - too long, > %u]",
271 			    hlen, len);
272 		}
273 		return;
274 	}
275 
276 	/* other variables in generic header */
277 	if (vflag) {
278 		(void)printf("CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
279 	}
280 
281 	/* checksum calculation */
282 #ifdef INET6
283 	if (ip6) {
284 		if (ip6->ip6_plen && vflag) {
285 			u_int16_t sum, dccp_sum;
286 
287 			sum = dccp6_cksum(ip6, dh, len);
288 			dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
289 			printf("cksum 0x%04x", dccp_sum);
290 			if (sum != 0) {
291 				(void)printf(" (incorrect (-> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
292 			} else
293 				(void)printf(" (correct), ");
294 		}
295 	} else
296 #endif /* INET6 */
297 	if (vflag)
298 	{
299 		u_int16_t sum, dccp_sum;
300 
301 		sum = dccp_cksum(ip, dh, len);
302 		dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
303 		printf("cksum 0x%04x", dccp_sum);
304 		if (sum != 0) {
305 			(void)printf(" (incorrect (-> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
306 		} else
307 			(void)printf(" (correct), ");
308 	}
309 
310 	switch (DCCPH_TYPE(dh)) {
311 	case DCCP_PKT_REQUEST: {
312 		struct dccp_hdr_request *dhr =
313 			(struct dccp_hdr_request *)(bp + dccp_basic_hdr_len(dh));
314 		TCHECK(*dhr);
315 		(void)printf("request (service=%d) ",
316 			     EXTRACT_32BITS(&dhr->dccph_req_service));
317 		extlen += 4;
318 		break;
319 	}
320 	case DCCP_PKT_RESPONSE: {
321 		struct dccp_hdr_response *dhr =
322 			(struct dccp_hdr_response *)(bp + dccp_basic_hdr_len(dh));
323 		TCHECK(*dhr);
324 		(void)printf("response (service=%d) ",
325 			     EXTRACT_32BITS(&dhr->dccph_resp_service));
326 		extlen += 12;
327 		break;
328 	}
329 	case DCCP_PKT_DATA:
330 		(void)printf("data ");
331 		break;
332 	case DCCP_PKT_ACK: {
333 		(void)printf("ack ");
334 		extlen += 8;
335 		break;
336 	}
337 	case DCCP_PKT_DATAACK: {
338 		(void)printf("dataack ");
339 		extlen += 8;
340 		break;
341 	}
342 	case DCCP_PKT_CLOSEREQ:
343 		(void)printf("closereq ");
344 		extlen += 8;
345 		break;
346 	case DCCP_PKT_CLOSE:
347 		(void)printf("close ");
348 		extlen += 8;
349 		break;
350 	case DCCP_PKT_RESET: {
351 		struct dccp_hdr_reset *dhr =
352 			(struct dccp_hdr_reset *)(bp + dccp_basic_hdr_len(dh));
353 		TCHECK(*dhr);
354 		(void)printf("reset (code=%s) ",
355 			     dccp_reset_code(dhr->dccph_reset_code));
356 		extlen += 12;
357 		break;
358 	}
359 	case DCCP_PKT_SYNC:
360 		(void)printf("sync ");
361 		extlen += 8;
362 		break;
363 	case DCCP_PKT_SYNCACK:
364 		(void)printf("syncack ");
365 		extlen += 8;
366 		break;
367 	default:
368 		(void)printf("invalid ");
369 		break;
370 	}
371 
372 	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
373 			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
374 		dccp_print_ack_no(bp);
375 
376 	if (vflag < 2)
377 		return;
378 
379 	(void)printf("seq %" PRIu64, dccp_seqno(dh));
380 
381 	/* process options */
382 	if (hlen > dccp_basic_hdr_len(dh) + extlen){
383 		const u_char *cp;
384 		u_int optlen;
385 		cp = bp + dccp_basic_hdr_len(dh) + extlen;
386 		printf(" <");
387 
388 		hlen -= dccp_basic_hdr_len(dh) + extlen;
389 		while(1){
390 			TCHECK(*cp);
391 			optlen = dccp_print_option(cp);
392 			if (!optlen) goto trunc2;
393 			if (hlen <= optlen) break;
394 			hlen -= optlen;
395 			cp += optlen;
396 			printf(", ");
397 		}
398 		printf(">");
399 	}
400 	return;
401 trunc:
402 	printf("[|dccp]");
403 trunc2:
404 	return;
405 }
406 
407 static int dccp_print_option(const u_char *option)
408 {
409 	u_int8_t optlen, i;
410 	u_int32_t *ts;
411 	u_int16_t *var16;
412 	u_int32_t *var32;
413 
414 	TCHECK(*option);
415 
416 	if (*option >= 32) {
417 		TCHECK(*(option+1));
418 		optlen = *(option +1);
419 		if (optlen < 2) {
420 			printf("Option %d optlen too short",*option);
421 			return 1;
422 		}
423 	} else optlen = 1;
424 
425 	TCHECK2(*option,optlen);
426 
427 	switch (*option){
428 	case 0:
429 		printf("nop");
430 		break;
431 	case 1:
432 		printf("mandatory");
433 		break;
434 	case 2:
435 		printf("slowreceiver");
436 		break;
437 	case 32:
438 		printf("change_l");
439 		if (*(option +2) < 10){
440 			printf(" %s", dccp_feature_nums[*(option +2)]);
441 			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
442 		}
443 		break;
444 	case 33:
445 		printf("confirm_l");
446 		if (*(option +2) < 10){
447 			printf(" %s", dccp_feature_nums[*(option +2)]);
448 			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
449 		}
450 		break;
451 	case 34:
452 	        printf("change_r");
453 		if (*(option +2) < 10){
454 			printf(" %s", dccp_feature_nums[*(option +2)]);
455 			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
456 		}
457 		break;
458 	case 35:
459 		printf("confirm_r");
460 		if (*(option +2) < 10){
461 			printf(" %s", dccp_feature_nums[*(option +2)]);
462 			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
463 		}
464 		break;
465 	case 36:
466 		printf("initcookie 0x");
467 		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
468 		break;
469 	case 37:
470 		printf("ndp_count");
471 		for (i = 0; i < optlen -2; i ++) printf(" %d", *(option +2 + i));
472 		break;
473 	case 38:
474 		printf("ack_vector0 0x");
475 		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
476 		break;
477 	case 39:
478 		printf("ack_vector1 0x");
479 		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
480 		break;
481 	case 40:
482 		printf("data_dropped 0x");
483 		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
484 		break;
485 	case 41:
486 		ts = (u_int32_t *)(option + 2);
487 		printf("timestamp %u", (u_int32_t)ntohl(*ts));
488 		break;
489 	case 42:
490 		ts = (u_int32_t *)(option + 2);
491 		printf("timestamp_echo %u", (u_int32_t)ntohl(*ts));
492 		break;
493 	case 43:
494 		printf("elapsed_time ");
495 		if (optlen == 6){
496 			ts = (u_int32_t *)(option + 2);
497 			printf("%u", (u_int32_t)ntohl(*ts));
498 		} else {
499 			var16 = (u_int16_t *)(option + 2);
500 			printf("%u", ntohs(*var16));
501 		}
502 		break;
503 	case 44:
504 		printf("data_checksum ");
505 		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
506 		break;
507 	default :
508 		if (*option >= 128) {
509 			printf("CCID option %d",*option);
510 			switch (optlen) {
511 				case 4:
512 					var16 = (u_int16_t *)(option + 2);
513 					printf(" %u",ntohs(*var16));
514 					break;
515 				case 6:
516 					var32 = (u_int32_t *)(option + 2);
517 					printf(" %u",(u_int32_t)ntohl(*var32));
518 					break;
519 				default:
520 					break;
521 			}
522 			break;
523 		}
524 
525 		printf("unknown_opt %d", *option);
526 		break;
527 	}
528 
529 	return optlen;
530 trunc:
531 	printf("[|dccp]");
532 	return 0;
533 }
534