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