12ebc47dbSSam Leffler /* 22ebc47dbSSam Leffler * Copyright (C) Arnaldo Carvalho de Melo 2004 32ebc47dbSSam Leffler * Copyright (C) Ian McDonald 2005 42ebc47dbSSam Leffler * Copyright (C) Yoshifumi Nishida 2005 52ebc47dbSSam Leffler * 62ebc47dbSSam Leffler * This software may be distributed either under the terms of the 72ebc47dbSSam Leffler * BSD-style license that accompanies tcpdump or the GNU GPL version 2 82ebc47dbSSam Leffler */ 92ebc47dbSSam Leffler 103340d773SGleb Smirnoff /* \summary: Datagram Congestion Control Protocol (DCCP) printer */ 113340d773SGleb Smirnoff 12*ee67461eSJoseph Mingrone /* specification: RFC 4340 */ 13*ee67461eSJoseph Mingrone 14*ee67461eSJoseph Mingrone #include <config.h> 152ebc47dbSSam Leffler 16*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 172ebc47dbSSam Leffler 183340d773SGleb Smirnoff #include "netdissect.h" 192ebc47dbSSam Leffler #include "addrtoname.h" 203340d773SGleb Smirnoff #include "extract.h" 212ebc47dbSSam Leffler #include "ip.h" 222ebc47dbSSam Leffler #include "ip6.h" 232ebc47dbSSam Leffler #include "ipproto.h" 242ebc47dbSSam Leffler 258bdc5a62SPatrick Kelsey /* RFC4340: Datagram Congestion Control Protocol (DCCP) */ 268bdc5a62SPatrick Kelsey 273c602fabSXin LI /** 283c602fabSXin LI * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit 293c602fabSXin LI * sequence number 303c602fabSXin LI * 313c602fabSXin LI * @dccph_sport - Relevant port on the endpoint that sent this packet 323c602fabSXin LI * @dccph_dport - Relevant port on the other endpoint 333c602fabSXin LI * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words 343c602fabSXin LI * @dccph_ccval - Used by the HC-Sender CCID 353c602fabSXin LI * @dccph_cscov - Parts of the packet that are covered by the Checksum field 363c602fabSXin LI * @dccph_checksum - Internet checksum, depends on dccph_cscov 373c602fabSXin LI * @dccph_x - 0 = 24 bit sequence number, 1 = 48 383c602fabSXin LI * @dccph_type - packet type, see DCCP_PKT_ prefixed macros 393c602fabSXin LI * @dccph_seq - 24-bit sequence number 403c602fabSXin LI */ 413c602fabSXin LI struct dccp_hdr { 42*ee67461eSJoseph Mingrone nd_uint16_t dccph_sport, 433c602fabSXin LI dccph_dport; 44*ee67461eSJoseph Mingrone nd_uint8_t dccph_doff; 45*ee67461eSJoseph Mingrone nd_uint8_t dccph_ccval_cscov; 46*ee67461eSJoseph Mingrone nd_uint16_t dccph_checksum; 47*ee67461eSJoseph Mingrone nd_uint8_t dccph_xtr; 48*ee67461eSJoseph Mingrone nd_uint24_t dccph_seq; 49*ee67461eSJoseph Mingrone }; 503c602fabSXin LI 513c602fabSXin LI /** 523c602fabSXin LI * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit 533c602fabSXin LI * sequence number 543c602fabSXin LI * 553c602fabSXin LI * @dccph_sport - Relevant port on the endpoint that sent this packet 563c602fabSXin LI * @dccph_dport - Relevant port on the other endpoint 573c602fabSXin LI * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words 583c602fabSXin LI * @dccph_ccval - Used by the HC-Sender CCID 593c602fabSXin LI * @dccph_cscov - Parts of the packet that are covered by the Checksum field 603c602fabSXin LI * @dccph_checksum - Internet checksum, depends on dccph_cscov 613c602fabSXin LI * @dccph_x - 0 = 24 bit sequence number, 1 = 48 623c602fabSXin LI * @dccph_type - packet type, see DCCP_PKT_ prefixed macros 633c602fabSXin LI * @dccph_seq - 48-bit sequence number 643c602fabSXin LI */ 653c602fabSXin LI struct dccp_hdr_ext { 66*ee67461eSJoseph Mingrone nd_uint16_t dccph_sport, 673c602fabSXin LI dccph_dport; 68*ee67461eSJoseph Mingrone nd_uint8_t dccph_doff; 69*ee67461eSJoseph Mingrone nd_uint8_t dccph_ccval_cscov; 70*ee67461eSJoseph Mingrone nd_uint16_t dccph_checksum; 71*ee67461eSJoseph Mingrone nd_uint8_t dccph_xtr; 72*ee67461eSJoseph Mingrone nd_uint8_t reserved; 73*ee67461eSJoseph Mingrone nd_uint48_t dccph_seq; 74*ee67461eSJoseph Mingrone }; 753c602fabSXin LI 76*ee67461eSJoseph Mingrone #define DCCPH_CCVAL(dh) ((GET_U_1((dh)->dccph_ccval_cscov) >> 4) & 0xF) 77*ee67461eSJoseph Mingrone #define DCCPH_CSCOV(dh) (GET_U_1((dh)->dccph_ccval_cscov) & 0xF) 783c602fabSXin LI 79*ee67461eSJoseph Mingrone #define DCCPH_X(dh) (GET_U_1((dh)->dccph_xtr) & 1) 80*ee67461eSJoseph Mingrone #define DCCPH_TYPE(dh) ((GET_U_1((dh)->dccph_xtr) >> 1) & 0xF) 813c602fabSXin LI 823c602fabSXin LI /** 83*ee67461eSJoseph Mingrone * struct dccp_hdr_request - Connection initiation request header 843c602fabSXin LI * 853c602fabSXin LI * @dccph_req_service - Service to which the client app wants to connect 863c602fabSXin LI */ 873c602fabSXin LI struct dccp_hdr_request { 88*ee67461eSJoseph Mingrone nd_uint32_t dccph_req_service; 89*ee67461eSJoseph Mingrone }; 903c602fabSXin LI 913c602fabSXin LI /** 92*ee67461eSJoseph Mingrone * struct dccp_hdr_response - Connection initiation response header 933c602fabSXin LI * 943c602fabSXin LI * @dccph_resp_ack - 48 bit ack number, contains GSR 953c602fabSXin LI * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request 963c602fabSXin LI */ 973c602fabSXin LI struct dccp_hdr_response { 98*ee67461eSJoseph Mingrone nd_uint64_t dccph_resp_ack; /* always 8 bytes, first 2 reserved */ 99*ee67461eSJoseph Mingrone nd_uint32_t dccph_resp_service; 100*ee67461eSJoseph Mingrone }; 1013c602fabSXin LI 1023c602fabSXin LI /** 1033c602fabSXin LI * struct dccp_hdr_reset - Unconditionally shut down a connection 1043c602fabSXin LI * 1053c602fabSXin LI * @dccph_resp_ack - 48 bit ack number 1063c602fabSXin LI * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request 1073c602fabSXin LI */ 1083c602fabSXin LI struct dccp_hdr_reset { 109*ee67461eSJoseph Mingrone nd_uint64_t dccph_reset_ack; /* always 8 bytes, first 2 reserved */ 110*ee67461eSJoseph Mingrone nd_uint8_t dccph_reset_code; 111*ee67461eSJoseph Mingrone nd_uint8_t dccph_reset_data1; 112*ee67461eSJoseph Mingrone nd_uint8_t dccph_reset_data2; 113*ee67461eSJoseph Mingrone nd_uint8_t dccph_reset_data3; 114*ee67461eSJoseph Mingrone }; 1153c602fabSXin LI 1163c602fabSXin LI enum dccp_pkt_type { 1173c602fabSXin LI DCCP_PKT_REQUEST = 0, 1183c602fabSXin LI DCCP_PKT_RESPONSE, 1193c602fabSXin LI DCCP_PKT_DATA, 1203c602fabSXin LI DCCP_PKT_ACK, 1213c602fabSXin LI DCCP_PKT_DATAACK, 1223c602fabSXin LI DCCP_PKT_CLOSEREQ, 1233c602fabSXin LI DCCP_PKT_CLOSE, 1243c602fabSXin LI DCCP_PKT_RESET, 1253c602fabSXin LI DCCP_PKT_SYNC, 1268bdc5a62SPatrick Kelsey DCCP_PKT_SYNCACK 1278bdc5a62SPatrick Kelsey }; 1288bdc5a62SPatrick Kelsey 1298bdc5a62SPatrick Kelsey static const struct tok dccp_pkt_type_str[] = { 1308bdc5a62SPatrick Kelsey { DCCP_PKT_REQUEST, "DCCP-Request" }, 1318bdc5a62SPatrick Kelsey { DCCP_PKT_RESPONSE, "DCCP-Response" }, 1328bdc5a62SPatrick Kelsey { DCCP_PKT_DATA, "DCCP-Data" }, 1338bdc5a62SPatrick Kelsey { DCCP_PKT_ACK, "DCCP-Ack" }, 1348bdc5a62SPatrick Kelsey { DCCP_PKT_DATAACK, "DCCP-DataAck" }, 1358bdc5a62SPatrick Kelsey { DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" }, 1368bdc5a62SPatrick Kelsey { DCCP_PKT_CLOSE, "DCCP-Close" }, 1378bdc5a62SPatrick Kelsey { DCCP_PKT_RESET, "DCCP-Reset" }, 1388bdc5a62SPatrick Kelsey { DCCP_PKT_SYNC, "DCCP-Sync" }, 1398bdc5a62SPatrick Kelsey { DCCP_PKT_SYNCACK, "DCCP-SyncAck" }, 1408bdc5a62SPatrick Kelsey { 0, NULL} 1413c602fabSXin LI }; 1423c602fabSXin LI 1433c602fabSXin LI enum dccp_reset_codes { 1443c602fabSXin LI DCCP_RESET_CODE_UNSPECIFIED = 0, 1453c602fabSXin LI DCCP_RESET_CODE_CLOSED, 1463c602fabSXin LI DCCP_RESET_CODE_ABORTED, 1473c602fabSXin LI DCCP_RESET_CODE_NO_CONNECTION, 1483c602fabSXin LI DCCP_RESET_CODE_PACKET_ERROR, 1493c602fabSXin LI DCCP_RESET_CODE_OPTION_ERROR, 1503c602fabSXin LI DCCP_RESET_CODE_MANDATORY_ERROR, 1513c602fabSXin LI DCCP_RESET_CODE_CONNECTION_REFUSED, 1523c602fabSXin LI DCCP_RESET_CODE_BAD_SERVICE_CODE, 1533c602fabSXin LI DCCP_RESET_CODE_TOO_BUSY, 1543c602fabSXin LI DCCP_RESET_CODE_BAD_INIT_COOKIE, 1553c602fabSXin LI DCCP_RESET_CODE_AGGRESSION_PENALTY, 1563c602fabSXin LI __DCCP_RESET_CODE_LAST 1573c602fabSXin LI }; 1583c602fabSXin LI 1593c602fabSXin LI 1602ebc47dbSSam Leffler static const char *dccp_reset_codes[] = { 1612ebc47dbSSam Leffler "unspecified", 1622ebc47dbSSam Leffler "closed", 1632ebc47dbSSam Leffler "aborted", 1642ebc47dbSSam Leffler "no_connection", 1652ebc47dbSSam Leffler "packet_error", 1662ebc47dbSSam Leffler "option_error", 1672ebc47dbSSam Leffler "mandatory_error", 1682ebc47dbSSam Leffler "connection_refused", 1692ebc47dbSSam Leffler "bad_service_code", 1702ebc47dbSSam Leffler "too_busy", 1712ebc47dbSSam Leffler "bad_init_cookie", 1722ebc47dbSSam Leffler "aggression_penalty", 1732ebc47dbSSam Leffler }; 1742ebc47dbSSam Leffler 1752ebc47dbSSam Leffler static const char *dccp_feature_nums[] = { 1762ebc47dbSSam Leffler "reserved", 1772ebc47dbSSam Leffler "ccid", 1782ebc47dbSSam Leffler "allow_short_seqno", 1792ebc47dbSSam Leffler "sequence_window", 1802ebc47dbSSam Leffler "ecn_incapable", 1812ebc47dbSSam Leffler "ack_ratio", 1822ebc47dbSSam Leffler "send_ack_vector", 1832ebc47dbSSam Leffler "send_ndp_count", 1842ebc47dbSSam Leffler "minimum checksum coverage", 1852ebc47dbSSam Leffler "check data checksum", 1862ebc47dbSSam Leffler }; 1872ebc47dbSSam Leffler 188*ee67461eSJoseph Mingrone static u_int 189*ee67461eSJoseph Mingrone dccp_csum_coverage(netdissect_options *ndo, 190*ee67461eSJoseph Mingrone const struct dccp_hdr *dh, u_int len) 191a5779b6eSRui Paulo { 192a5779b6eSRui Paulo u_int cov; 193a5779b6eSRui Paulo 194a5779b6eSRui Paulo if (DCCPH_CSCOV(dh) == 0) 195a5779b6eSRui Paulo return len; 196*ee67461eSJoseph Mingrone cov = (GET_U_1(dh->dccph_doff) + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t); 197a5779b6eSRui Paulo return (cov > len)? len : cov; 198a5779b6eSRui Paulo } 199a5779b6eSRui Paulo 200*ee67461eSJoseph Mingrone static uint16_t dccp_cksum(netdissect_options *ndo, const struct ip *ip, 2012ebc47dbSSam Leffler const struct dccp_hdr *dh, u_int len) 2022ebc47dbSSam Leffler { 2033340d773SGleb Smirnoff return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len, 204*ee67461eSJoseph Mingrone dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP); 2052ebc47dbSSam Leffler } 2062ebc47dbSSam Leffler 207*ee67461eSJoseph Mingrone static uint16_t dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6, 2083340d773SGleb Smirnoff const struct dccp_hdr *dh, u_int len) 2092ebc47dbSSam Leffler { 2103340d773SGleb Smirnoff return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len, 211*ee67461eSJoseph Mingrone dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP); 2122ebc47dbSSam Leffler } 2132ebc47dbSSam Leffler 2143c602fabSXin LI static const char *dccp_reset_code(uint8_t code) 2152ebc47dbSSam Leffler { 2162ebc47dbSSam Leffler if (code >= __DCCP_RESET_CODE_LAST) 2172ebc47dbSSam Leffler return "invalid"; 2182ebc47dbSSam Leffler return dccp_reset_codes[code]; 2192ebc47dbSSam Leffler } 2202ebc47dbSSam Leffler 221*ee67461eSJoseph Mingrone static uint64_t 222*ee67461eSJoseph Mingrone dccp_seqno(netdissect_options *ndo, const u_char *bp) 2232ebc47dbSSam Leffler { 2243c602fabSXin LI const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 2253c602fabSXin LI uint64_t seqno; 2262ebc47dbSSam Leffler 2272ebc47dbSSam Leffler if (DCCPH_X(dh) != 0) { 2283c602fabSXin LI const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp; 229*ee67461eSJoseph Mingrone seqno = GET_BE_U_6(dhx->dccph_seq); 2303c602fabSXin LI } else { 231*ee67461eSJoseph Mingrone seqno = GET_BE_U_3(dh->dccph_seq); 2322ebc47dbSSam Leffler } 2332ebc47dbSSam Leffler 2342ebc47dbSSam Leffler return seqno; 2352ebc47dbSSam Leffler } 2362ebc47dbSSam Leffler 237*ee67461eSJoseph Mingrone static unsigned int 238*ee67461eSJoseph Mingrone dccp_basic_hdr_len(netdissect_options *ndo, const struct dccp_hdr *dh) 2392ebc47dbSSam Leffler { 2403c602fabSXin LI return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr); 241b5bfcb5dSMax Laier } 242b5bfcb5dSMax Laier 2433c602fabSXin LI static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp) 244b5bfcb5dSMax Laier { 245b5bfcb5dSMax Laier const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 246*ee67461eSJoseph Mingrone const u_char *ackp = bp + dccp_basic_hdr_len(ndo, dh); 2473c602fabSXin LI uint64_t ackno; 2482ebc47dbSSam Leffler 2492ebc47dbSSam Leffler if (DCCPH_X(dh) != 0) { 250*ee67461eSJoseph Mingrone ackno = GET_BE_U_6(ackp + 2); 2513c602fabSXin LI } else { 252*ee67461eSJoseph Mingrone ackno = GET_BE_U_3(ackp + 1); 2532ebc47dbSSam Leffler } 2542ebc47dbSSam Leffler 255*ee67461eSJoseph Mingrone ND_PRINT("(ack=%" PRIu64 ") ", ackno); 2562ebc47dbSSam Leffler } 2572ebc47dbSSam Leffler 258*ee67461eSJoseph Mingrone static u_int dccp_print_option(netdissect_options *, const u_char *, u_int); 2592ebc47dbSSam Leffler 2602ebc47dbSSam Leffler /** 2612ebc47dbSSam Leffler * dccp_print - show dccp packet 2622ebc47dbSSam Leffler * @bp - beginning of dccp packet 2632ebc47dbSSam Leffler * @data2 - beginning of enclosing 264*ee67461eSJoseph Mingrone * @len - length of ip packet 2652ebc47dbSSam Leffler */ 266*ee67461eSJoseph Mingrone void 267*ee67461eSJoseph Mingrone dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2, 2683c602fabSXin LI u_int len) 2692ebc47dbSSam Leffler { 2702ebc47dbSSam Leffler const struct dccp_hdr *dh; 2712ebc47dbSSam Leffler const struct ip *ip; 2722ebc47dbSSam Leffler const struct ip6_hdr *ip6; 2732ebc47dbSSam Leffler const u_char *cp; 2742ebc47dbSSam Leffler u_short sport, dport; 2752ebc47dbSSam Leffler u_int hlen; 2763c602fabSXin LI u_int fixed_hdrlen; 2778bdc5a62SPatrick Kelsey uint8_t dccph_type; 2782ebc47dbSSam Leffler 279*ee67461eSJoseph Mingrone ndo->ndo_protocol = "dccp"; 2802ebc47dbSSam Leffler dh = (const struct dccp_hdr *)bp; 2812ebc47dbSSam Leffler 2823340d773SGleb Smirnoff ip = (const struct ip *)data2; 2832ebc47dbSSam Leffler if (IP_V(ip) == 6) 2842ebc47dbSSam Leffler ip6 = (const struct ip6_hdr *)data2; 2852ebc47dbSSam Leffler else 2862ebc47dbSSam Leffler ip6 = NULL; 2873c602fabSXin LI 2883c602fabSXin LI /* make sure we have enough data to look at the X bit */ 2892ebc47dbSSam Leffler cp = (const u_char *)(dh + 1); 290*ee67461eSJoseph Mingrone if (cp > ndo->ndo_snapend) 291*ee67461eSJoseph Mingrone goto trunc; 2923c602fabSXin LI if (len < sizeof(struct dccp_hdr)) { 293*ee67461eSJoseph Mingrone ND_PRINT("truncated-dccp - %zu bytes missing!", 294*ee67461eSJoseph Mingrone sizeof(struct dccp_hdr) - len); 2952ebc47dbSSam Leffler return; 2962ebc47dbSSam Leffler } 2972ebc47dbSSam Leffler 2983c602fabSXin LI /* get the length of the generic header */ 299*ee67461eSJoseph Mingrone fixed_hdrlen = dccp_basic_hdr_len(ndo, dh); 3003c602fabSXin LI if (len < fixed_hdrlen) { 301*ee67461eSJoseph Mingrone ND_PRINT("truncated-dccp - %u bytes missing!", 302*ee67461eSJoseph Mingrone fixed_hdrlen - len); 3032ebc47dbSSam Leffler return; 3042ebc47dbSSam Leffler } 305*ee67461eSJoseph Mingrone ND_TCHECK_LEN(dh, fixed_hdrlen); 3062ebc47dbSSam Leffler 307*ee67461eSJoseph Mingrone sport = GET_BE_U_2(dh->dccph_sport); 308*ee67461eSJoseph Mingrone dport = GET_BE_U_2(dh->dccph_dport); 309*ee67461eSJoseph Mingrone hlen = GET_U_1(dh->dccph_doff) * 4; 3102ebc47dbSSam Leffler 3112ebc47dbSSam Leffler if (ip6) { 312*ee67461eSJoseph Mingrone ND_PRINT("%s.%u > %s.%u: ", 313*ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(ip6->ip6_src), sport, 314*ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(ip6->ip6_dst), dport); 3153340d773SGleb Smirnoff } else { 316*ee67461eSJoseph Mingrone ND_PRINT("%s.%u > %s.%u: ", 317*ee67461eSJoseph Mingrone GET_IPADDR_STRING(ip->ip_src), sport, 318*ee67461eSJoseph Mingrone GET_IPADDR_STRING(ip->ip_dst), dport); 3192ebc47dbSSam Leffler } 3202ebc47dbSSam Leffler 321*ee67461eSJoseph Mingrone nd_print_protocol_caps(ndo); 3228bdc5a62SPatrick Kelsey 3233c602fabSXin LI if (ndo->ndo_qflag) { 324*ee67461eSJoseph Mingrone ND_PRINT(" %u", len - hlen); 3252ebc47dbSSam Leffler if (hlen > len) { 326*ee67461eSJoseph Mingrone ND_PRINT(" [bad hdr length %u - too long, > %u]", 327*ee67461eSJoseph Mingrone hlen, len); 3282ebc47dbSSam Leffler } 3292ebc47dbSSam Leffler return; 3302ebc47dbSSam Leffler } 3312ebc47dbSSam Leffler 3322ebc47dbSSam Leffler /* other variables in generic header */ 3333c602fabSXin LI if (ndo->ndo_vflag) { 334*ee67461eSJoseph Mingrone ND_PRINT(" (CCVal %u, CsCov %u", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)); 3352ebc47dbSSam Leffler } 3362ebc47dbSSam Leffler 3372ebc47dbSSam Leffler /* checksum calculation */ 338*ee67461eSJoseph Mingrone if (ndo->ndo_vflag && ND_TTEST_LEN(bp, len)) { 3393c602fabSXin LI uint16_t sum = 0, dccp_sum; 3402ebc47dbSSam Leffler 341*ee67461eSJoseph Mingrone dccp_sum = GET_BE_U_2(dh->dccph_checksum); 342*ee67461eSJoseph Mingrone ND_PRINT(", cksum 0x%04x ", dccp_sum); 343a5779b6eSRui Paulo if (IP_V(ip) == 4) 3443c602fabSXin LI sum = dccp_cksum(ndo, ip, dh, len); 345a5779b6eSRui Paulo else if (IP_V(ip) == 6) 3463340d773SGleb Smirnoff sum = dccp6_cksum(ndo, ip6, dh, len); 347a5779b6eSRui Paulo if (sum != 0) 348*ee67461eSJoseph Mingrone ND_PRINT("(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum)); 349a5779b6eSRui Paulo else 350*ee67461eSJoseph Mingrone ND_PRINT("(correct)"); 3512ebc47dbSSam Leffler } 3522ebc47dbSSam Leffler 3538bdc5a62SPatrick Kelsey if (ndo->ndo_vflag) 354*ee67461eSJoseph Mingrone ND_PRINT(")"); 355*ee67461eSJoseph Mingrone ND_PRINT(" "); 3568bdc5a62SPatrick Kelsey 3578bdc5a62SPatrick Kelsey dccph_type = DCCPH_TYPE(dh); 3588bdc5a62SPatrick Kelsey switch (dccph_type) { 3592ebc47dbSSam Leffler case DCCP_PKT_REQUEST: { 3603340d773SGleb Smirnoff const struct dccp_hdr_request *dhr = 3613340d773SGleb Smirnoff (const struct dccp_hdr_request *)(bp + fixed_hdrlen); 3623c602fabSXin LI fixed_hdrlen += 4; 3633c602fabSXin LI if (len < fixed_hdrlen) { 364*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 3658bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 366*ee67461eSJoseph Mingrone fixed_hdrlen - len); 3673c602fabSXin LI return; 3683c602fabSXin LI } 369*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(dhr); 370*ee67461eSJoseph Mingrone ND_PRINT("%s (service=%u) ", 3718bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 372*ee67461eSJoseph Mingrone GET_BE_U_4(dhr->dccph_req_service)); 3732ebc47dbSSam Leffler break; 3742ebc47dbSSam Leffler } 3752ebc47dbSSam Leffler case DCCP_PKT_RESPONSE: { 3763340d773SGleb Smirnoff const struct dccp_hdr_response *dhr = 3773340d773SGleb Smirnoff (const struct dccp_hdr_response *)(bp + fixed_hdrlen); 3783c602fabSXin LI fixed_hdrlen += 12; 3793c602fabSXin LI if (len < fixed_hdrlen) { 380*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 3818bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 382*ee67461eSJoseph Mingrone fixed_hdrlen - len); 3833c602fabSXin LI return; 3843c602fabSXin LI } 385*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(dhr); 386*ee67461eSJoseph Mingrone ND_PRINT("%s (service=%u) ", 3878bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 388*ee67461eSJoseph Mingrone GET_BE_U_4(dhr->dccph_resp_service)); 3892ebc47dbSSam Leffler break; 3902ebc47dbSSam Leffler } 3912ebc47dbSSam Leffler case DCCP_PKT_DATA: 392*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 3932ebc47dbSSam Leffler break; 3942ebc47dbSSam Leffler case DCCP_PKT_ACK: { 3953c602fabSXin LI fixed_hdrlen += 8; 3963c602fabSXin LI if (len < fixed_hdrlen) { 397*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 3988bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 399*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4003c602fabSXin LI return; 4013c602fabSXin LI } 402*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 4032ebc47dbSSam Leffler break; 4042ebc47dbSSam Leffler } 4052ebc47dbSSam Leffler case DCCP_PKT_DATAACK: { 4063c602fabSXin LI fixed_hdrlen += 8; 4073c602fabSXin LI if (len < fixed_hdrlen) { 408*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 4098bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 410*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4113c602fabSXin LI return; 4123c602fabSXin LI } 413*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 4142ebc47dbSSam Leffler break; 4152ebc47dbSSam Leffler } 4162ebc47dbSSam Leffler case DCCP_PKT_CLOSEREQ: 4173c602fabSXin LI fixed_hdrlen += 8; 4183c602fabSXin LI if (len < fixed_hdrlen) { 419*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 4208bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 421*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4223c602fabSXin LI return; 4233c602fabSXin LI } 424*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 4252ebc47dbSSam Leffler break; 4262ebc47dbSSam Leffler case DCCP_PKT_CLOSE: 4273c602fabSXin LI fixed_hdrlen += 8; 4283c602fabSXin LI if (len < fixed_hdrlen) { 429*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 4308bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 431*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4323c602fabSXin LI return; 4333c602fabSXin LI } 434*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 4352ebc47dbSSam Leffler break; 4362ebc47dbSSam Leffler case DCCP_PKT_RESET: { 4373340d773SGleb Smirnoff const struct dccp_hdr_reset *dhr = 4383340d773SGleb Smirnoff (const struct dccp_hdr_reset *)(bp + fixed_hdrlen); 4393c602fabSXin LI fixed_hdrlen += 12; 4403c602fabSXin LI if (len < fixed_hdrlen) { 441*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 4428bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 443*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4443c602fabSXin LI return; 4453c602fabSXin LI } 446*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(dhr); 447*ee67461eSJoseph Mingrone ND_PRINT("%s (code=%s) ", 4488bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 449*ee67461eSJoseph Mingrone dccp_reset_code(GET_U_1(dhr->dccph_reset_code))); 4502ebc47dbSSam Leffler break; 4512ebc47dbSSam Leffler } 4522ebc47dbSSam Leffler case DCCP_PKT_SYNC: 4533c602fabSXin LI fixed_hdrlen += 8; 4543c602fabSXin LI if (len < fixed_hdrlen) { 455*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 4568bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 457*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4583c602fabSXin LI return; 4593c602fabSXin LI } 460*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 4612ebc47dbSSam Leffler break; 4622ebc47dbSSam Leffler case DCCP_PKT_SYNCACK: 4633c602fabSXin LI fixed_hdrlen += 8; 4643c602fabSXin LI if (len < fixed_hdrlen) { 465*ee67461eSJoseph Mingrone ND_PRINT("truncated-%s - %u bytes missing!", 4668bdc5a62SPatrick Kelsey tok2str(dccp_pkt_type_str, "", dccph_type), 467*ee67461eSJoseph Mingrone fixed_hdrlen - len); 4683c602fabSXin LI return; 4693c602fabSXin LI } 470*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); 4712ebc47dbSSam Leffler break; 4722ebc47dbSSam Leffler default: 473*ee67461eSJoseph Mingrone ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type)); 4742ebc47dbSSam Leffler break; 4752ebc47dbSSam Leffler } 4762ebc47dbSSam Leffler 477b5bfcb5dSMax Laier if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) && 478b5bfcb5dSMax Laier (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST)) 4793c602fabSXin LI dccp_print_ack_no(ndo, bp); 480b5bfcb5dSMax Laier 4813c602fabSXin LI if (ndo->ndo_vflag < 2) 4822ebc47dbSSam Leffler return; 4832ebc47dbSSam Leffler 484*ee67461eSJoseph Mingrone ND_PRINT("seq %" PRIu64, dccp_seqno(ndo, bp)); 4852ebc47dbSSam Leffler 4862ebc47dbSSam Leffler /* process options */ 4873c602fabSXin LI if (hlen > fixed_hdrlen){ 4882ebc47dbSSam Leffler u_int optlen; 4893c602fabSXin LI cp = bp + fixed_hdrlen; 490*ee67461eSJoseph Mingrone ND_PRINT(" <"); 4912ebc47dbSSam Leffler 4923c602fabSXin LI hlen -= fixed_hdrlen; 4932ebc47dbSSam Leffler while(1){ 4943c602fabSXin LI optlen = dccp_print_option(ndo, cp, hlen); 4953c602fabSXin LI if (!optlen) 4963c602fabSXin LI break; 4973c602fabSXin LI if (hlen <= optlen) 4983c602fabSXin LI break; 4992ebc47dbSSam Leffler hlen -= optlen; 5002ebc47dbSSam Leffler cp += optlen; 501*ee67461eSJoseph Mingrone ND_PRINT(", "); 5022ebc47dbSSam Leffler } 503*ee67461eSJoseph Mingrone ND_PRINT(">"); 5042ebc47dbSSam Leffler } 5052ebc47dbSSam Leffler return; 5062ebc47dbSSam Leffler trunc: 507*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 5082ebc47dbSSam Leffler } 5092ebc47dbSSam Leffler 5103c602fabSXin LI static const struct tok dccp_option_values[] = { 5113c602fabSXin LI { 0, "nop" }, 5123c602fabSXin LI { 1, "mandatory" }, 5133c602fabSXin LI { 2, "slowreceiver" }, 5143c602fabSXin LI { 32, "change_l" }, 5153c602fabSXin LI { 33, "confirm_l" }, 5163c602fabSXin LI { 34, "change_r" }, 5173c602fabSXin LI { 35, "confirm_r" }, 5183c602fabSXin LI { 36, "initcookie" }, 5193c602fabSXin LI { 37, "ndp_count" }, 5203c602fabSXin LI { 38, "ack_vector0" }, 5213c602fabSXin LI { 39, "ack_vector1" }, 5223c602fabSXin LI { 40, "data_dropped" }, 5233c602fabSXin LI { 41, "timestamp" }, 5243c602fabSXin LI { 42, "timestamp_echo" }, 5253c602fabSXin LI { 43, "elapsed_time" }, 5263c602fabSXin LI { 44, "data_checksum" }, 5273c602fabSXin LI { 0, NULL } 5283c602fabSXin LI }; 5292ebc47dbSSam Leffler 530*ee67461eSJoseph Mingrone static u_int 53139e421e8SCy Schubert dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen) 5323c602fabSXin LI { 5333c602fabSXin LI uint8_t optlen, i; 5343c602fabSXin LI 535*ee67461eSJoseph Mingrone if (GET_U_1(option) >= 32) { 536*ee67461eSJoseph Mingrone optlen = GET_U_1(option + 1); 5372ebc47dbSSam Leffler if (optlen < 2) { 538*ee67461eSJoseph Mingrone if (GET_U_1(option) >= 128) 539*ee67461eSJoseph Mingrone ND_PRINT("CCID option %u optlen too short", 540*ee67461eSJoseph Mingrone GET_U_1(option)); 5413c602fabSXin LI else 542*ee67461eSJoseph Mingrone ND_PRINT("%s optlen too short", 543*ee67461eSJoseph Mingrone tok2str(dccp_option_values, "Option %u", GET_U_1(option))); 5443c602fabSXin LI return 0; 5452ebc47dbSSam Leffler } 5463c602fabSXin LI } else 5473c602fabSXin LI optlen = 1; 5482ebc47dbSSam Leffler 5493c602fabSXin LI if (hlen < optlen) { 550*ee67461eSJoseph Mingrone if (GET_U_1(option) >= 128) 551*ee67461eSJoseph Mingrone ND_PRINT("CCID option %u optlen goes past header length", 552*ee67461eSJoseph Mingrone GET_U_1(option)); 5533c602fabSXin LI else 554*ee67461eSJoseph Mingrone ND_PRINT("%s optlen goes past header length", 555*ee67461eSJoseph Mingrone tok2str(dccp_option_values, "Option %u", GET_U_1(option))); 5563c602fabSXin LI return 0; 5573c602fabSXin LI } 558*ee67461eSJoseph Mingrone ND_TCHECK_LEN(option, optlen); 5592ebc47dbSSam Leffler 560*ee67461eSJoseph Mingrone if (GET_U_1(option) >= 128) { 561*ee67461eSJoseph Mingrone ND_PRINT("CCID option %u", GET_U_1(option)); 5623c602fabSXin LI switch (optlen) { 5633c602fabSXin LI case 4: 564*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_2(option + 2)); 5653c602fabSXin LI break; 5663c602fabSXin LI case 6: 567*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(option + 2)); 5683c602fabSXin LI break; 5693c602fabSXin LI default: 5703c602fabSXin LI break; 5713c602fabSXin LI } 5723c602fabSXin LI } else { 573*ee67461eSJoseph Mingrone ND_PRINT("%s", 574*ee67461eSJoseph Mingrone tok2str(dccp_option_values, "Option %u", GET_U_1(option))); 575*ee67461eSJoseph Mingrone switch (GET_U_1(option)) { 5762ebc47dbSSam Leffler case 32: 5772ebc47dbSSam Leffler case 33: 5782ebc47dbSSam Leffler case 34: 5792ebc47dbSSam Leffler case 35: 5803c602fabSXin LI if (optlen < 3) { 581*ee67461eSJoseph Mingrone ND_PRINT(" optlen too short"); 5823c602fabSXin LI return optlen; 5833c602fabSXin LI } 584*ee67461eSJoseph Mingrone if (GET_U_1(option + 2) < 10){ 585*ee67461eSJoseph Mingrone ND_PRINT(" %s", 586*ee67461eSJoseph Mingrone dccp_feature_nums[GET_U_1(option + 2)]); 5873c602fabSXin LI for (i = 0; i < optlen - 3; i++) 588*ee67461eSJoseph Mingrone ND_PRINT(" %u", 589*ee67461eSJoseph Mingrone GET_U_1(option + 3 + i)); 5902ebc47dbSSam Leffler } 5912ebc47dbSSam Leffler break; 5922ebc47dbSSam Leffler case 36: 5933c602fabSXin LI if (optlen > 2) { 594*ee67461eSJoseph Mingrone ND_PRINT(" 0x"); 5953c602fabSXin LI for (i = 0; i < optlen - 2; i++) 596*ee67461eSJoseph Mingrone ND_PRINT("%02x", 597*ee67461eSJoseph Mingrone GET_U_1(option + 2 + i)); 5983c602fabSXin LI } 5992ebc47dbSSam Leffler break; 6002ebc47dbSSam Leffler case 37: 6013c602fabSXin LI for (i = 0; i < optlen - 2; i++) 602*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_U_1(option + 2 + i)); 6032ebc47dbSSam Leffler break; 6042ebc47dbSSam Leffler case 38: 6053c602fabSXin LI if (optlen > 2) { 606*ee67461eSJoseph Mingrone ND_PRINT(" 0x"); 6073c602fabSXin LI for (i = 0; i < optlen - 2; i++) 608*ee67461eSJoseph Mingrone ND_PRINT("%02x", 609*ee67461eSJoseph Mingrone GET_U_1(option + 2 + i)); 6103c602fabSXin LI } 6112ebc47dbSSam Leffler break; 6122ebc47dbSSam Leffler case 39: 6133c602fabSXin LI if (optlen > 2) { 614*ee67461eSJoseph Mingrone ND_PRINT(" 0x"); 6153c602fabSXin LI for (i = 0; i < optlen - 2; i++) 616*ee67461eSJoseph Mingrone ND_PRINT("%02x", 617*ee67461eSJoseph Mingrone GET_U_1(option + 2 + i)); 6183c602fabSXin LI } 6192ebc47dbSSam Leffler break; 6202ebc47dbSSam Leffler case 40: 6213c602fabSXin LI if (optlen > 2) { 622*ee67461eSJoseph Mingrone ND_PRINT(" 0x"); 6233c602fabSXin LI for (i = 0; i < optlen - 2; i++) 624*ee67461eSJoseph Mingrone ND_PRINT("%02x", 625*ee67461eSJoseph Mingrone GET_U_1(option + 2 + i)); 6263c602fabSXin LI } 6272ebc47dbSSam Leffler break; 6282ebc47dbSSam Leffler case 41: 62939e421e8SCy Schubert /* 63039e421e8SCy Schubert * 13.1. Timestamp Option 63139e421e8SCy Schubert * 63239e421e8SCy Schubert * +--------+--------+--------+--------+--------+--------+ 63339e421e8SCy Schubert * |00101001|00000110| Timestamp Value | 63439e421e8SCy Schubert * +--------+--------+--------+--------+--------+--------+ 63539e421e8SCy Schubert * Type=41 Length=6 63639e421e8SCy Schubert */ 63739e421e8SCy Schubert if (optlen == 6) 638*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(option + 2)); 6393c602fabSXin LI else 640*ee67461eSJoseph Mingrone ND_PRINT(" [optlen != 6]"); 6412ebc47dbSSam Leffler break; 6422ebc47dbSSam Leffler case 42: 64339e421e8SCy Schubert /* 64439e421e8SCy Schubert * 13.3. Timestamp Echo Option 64539e421e8SCy Schubert * 64639e421e8SCy Schubert * +--------+--------+--------+--------+--------+--------+ 64739e421e8SCy Schubert * |00101010|00000110| Timestamp Echo | 64839e421e8SCy Schubert * +--------+--------+--------+--------+--------+--------+ 64939e421e8SCy Schubert * Type=42 Len=6 65039e421e8SCy Schubert * 65139e421e8SCy Schubert * +--------+--------+------- ... -------+--------+--------+ 65239e421e8SCy Schubert * |00101010|00001000| Timestamp Echo | Elapsed Time | 65339e421e8SCy Schubert * +--------+--------+------- ... -------+--------+--------+ 65439e421e8SCy Schubert * Type=42 Len=8 (4 bytes) 65539e421e8SCy Schubert * 65639e421e8SCy Schubert * +--------+--------+------- ... -------+------- ... -------+ 65739e421e8SCy Schubert * |00101010|00001010| Timestamp Echo | Elapsed Time | 65839e421e8SCy Schubert * +--------+--------+------- ... -------+------- ... -------+ 65939e421e8SCy Schubert * Type=42 Len=10 (4 bytes) (4 bytes) 66039e421e8SCy Schubert */ 66139e421e8SCy Schubert switch (optlen) { 66239e421e8SCy Schubert case 6: 663*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(option + 2)); 66439e421e8SCy Schubert break; 66539e421e8SCy Schubert case 8: 666*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(option + 2)); 667*ee67461eSJoseph Mingrone ND_PRINT(" (elapsed time %u)", 668*ee67461eSJoseph Mingrone GET_BE_U_2(option + 6)); 66939e421e8SCy Schubert break; 67039e421e8SCy Schubert case 10: 671*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(option + 2)); 672*ee67461eSJoseph Mingrone ND_PRINT(" (elapsed time %u)", 673*ee67461eSJoseph Mingrone GET_BE_U_4(option + 6)); 67439e421e8SCy Schubert break; 67539e421e8SCy Schubert default: 676*ee67461eSJoseph Mingrone ND_PRINT(" [optlen != 6 or 8 or 10]"); 67739e421e8SCy Schubert break; 67839e421e8SCy Schubert } 6792ebc47dbSSam Leffler break; 6802ebc47dbSSam Leffler case 43: 68127df3f5dSRui Paulo if (optlen == 6) 682*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(option + 2)); 6833c602fabSXin LI else if (optlen == 4) 684*ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_2(option + 2)); 68527df3f5dSRui Paulo else 686*ee67461eSJoseph Mingrone ND_PRINT(" [optlen != 4 or 6]"); 6872ebc47dbSSam Leffler break; 6882ebc47dbSSam Leffler case 44: 6893c602fabSXin LI if (optlen > 2) { 690*ee67461eSJoseph Mingrone ND_PRINT(" "); 6913c602fabSXin LI for (i = 0; i < optlen - 2; i++) 692*ee67461eSJoseph Mingrone ND_PRINT("%02x", 693*ee67461eSJoseph Mingrone GET_U_1(option + 2 + i)); 6942ebc47dbSSam Leffler } 6952ebc47dbSSam Leffler break; 6962ebc47dbSSam Leffler } 6972ebc47dbSSam Leffler } 6982ebc47dbSSam Leffler 6992ebc47dbSSam Leffler return optlen; 7002ebc47dbSSam Leffler trunc: 701*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 7022ebc47dbSSam Leffler return 0; 7032ebc47dbSSam Leffler } 704