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