X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/3625533c9acb33b9a9d57f3d38290b1408a96341..refs/heads/master:/print-dccp.c diff --git a/print-dccp.c b/print-dccp.c index 68d0a978..2ae46a97 100644 --- a/print-dccp.c +++ b/print-dccp.c @@ -7,24 +7,24 @@ * BSD-style license that accompanies tcpdump or the GNU GPL version 2 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +/* \summary: Datagram Congestion Control Protocol (DCCP) printer */ -#include +/* specification: RFC 4340 */ -#include -#include +#include -#include "interface.h" +#include "netdissect-stdinc.h" + +#define ND_LONGJMP_FROM_TCHECK +#include "netdissect.h" #include "addrtoname.h" -#include "extract.h" /* must come after interface.h */ +#include "extract.h" #include "ip.h" -#ifdef INET6 #include "ip6.h" -#endif #include "ipproto.h" +/* RFC4340: Datagram Congestion Control Protocol (DCCP) */ + /** * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit * sequence number @@ -40,14 +40,14 @@ * @dccph_seq - 24-bit sequence number */ struct dccp_hdr { - u_int16_t dccph_sport, + nd_uint16_t dccph_sport, dccph_dport; - u_int8_t dccph_doff; - u_int8_t dccph_ccval_cscov; - u_int16_t dccph_checksum; - u_int8_t dccph_xtr; - u_int8_t dccph_seq[3]; -} UNALIGNED; + nd_uint8_t dccph_doff; + nd_uint8_t dccph_ccval_cscov; + nd_uint16_t dccph_checksum; + nd_uint8_t dccph_xtr; + nd_uint24_t dccph_seq; +}; /** * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit @@ -64,41 +64,41 @@ struct dccp_hdr { * @dccph_seq - 48-bit sequence number */ struct dccp_hdr_ext { - u_int16_t dccph_sport, + nd_uint16_t dccph_sport, dccph_dport; - u_int8_t dccph_doff; - u_int8_t dccph_ccval_cscov; - u_int16_t dccph_checksum; - u_int8_t dccph_xtr; - u_int8_t reserved; - u_int8_t dccph_seq[6]; -} UNALIGNED; + nd_uint8_t dccph_doff; + nd_uint8_t dccph_ccval_cscov; + nd_uint16_t dccph_checksum; + nd_uint8_t dccph_xtr; + nd_uint8_t reserved; + nd_uint48_t dccph_seq; +}; -#define DCCPH_CCVAL(dh) (((dh)->dccph_ccval_cscov >> 4) & 0xF) -#define DCCPH_CSCOV(dh) (((dh)->dccph_ccval_cscov) & 0xF) +#define DCCPH_CCVAL(dh) ((GET_U_1((dh)->dccph_ccval_cscov) >> 4) & 0xF) +#define DCCPH_CSCOV(dh) (GET_U_1((dh)->dccph_ccval_cscov) & 0xF) -#define DCCPH_X(dh) ((dh)->dccph_xtr & 1) -#define DCCPH_TYPE(dh) (((dh)->dccph_xtr >> 1) & 0xF) +#define DCCPH_X(dh) (GET_U_1((dh)->dccph_xtr) & 1) +#define DCCPH_TYPE(dh) ((GET_U_1((dh)->dccph_xtr) >> 1) & 0xF) /** - * struct dccp_hdr_request - Conection initiation request header + * struct dccp_hdr_request - Connection initiation request header * * @dccph_req_service - Service to which the client app wants to connect */ struct dccp_hdr_request { - u_int32_t dccph_req_service; -} UNALIGNED; + nd_uint32_t dccph_req_service; +}; /** - * struct dccp_hdr_response - Conection initiation response header + * struct dccp_hdr_response - Connection initiation response header * * @dccph_resp_ack - 48 bit ack number, contains GSR * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request */ struct dccp_hdr_response { - u_int8_t dccph_resp_ack[8]; /* always 8 bytes */ - u_int32_t dccph_resp_service; -} UNALIGNED; + nd_uint64_t dccph_resp_ack; /* always 8 bytes, first 2 reserved */ + nd_uint32_t dccph_resp_service; +}; /** * struct dccp_hdr_reset - Unconditionally shut down a connection @@ -107,10 +107,12 @@ struct dccp_hdr_response { * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request */ struct dccp_hdr_reset { - u_int8_t dccph_reset_ack[8]; /* always 8 bytes */ - u_int8_t dccph_reset_code, - dccph_reset_data[3]; -} UNALIGNED; + nd_uint64_t dccph_reset_ack; /* always 8 bytes, first 2 reserved */ + nd_uint8_t dccph_reset_code; + nd_uint8_t dccph_reset_data1; + nd_uint8_t dccph_reset_data2; + nd_uint8_t dccph_reset_data3; +}; enum dccp_pkt_type { DCCP_PKT_REQUEST = 0, @@ -122,8 +124,21 @@ enum dccp_pkt_type { DCCP_PKT_CLOSE, DCCP_PKT_RESET, DCCP_PKT_SYNC, - DCCP_PKT_SYNCACK, - DCCP_PKT_INVALID + DCCP_PKT_SYNCACK +}; + +static const struct tok dccp_pkt_type_str[] = { + { DCCP_PKT_REQUEST, "DCCP-Request" }, + { DCCP_PKT_RESPONSE, "DCCP-Response" }, + { DCCP_PKT_DATA, "DCCP-Data" }, + { DCCP_PKT_ACK, "DCCP-Ack" }, + { DCCP_PKT_DATAACK, "DCCP-DataAck" }, + { DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" }, + { DCCP_PKT_CLOSE, "DCCP-Close" }, + { DCCP_PKT_RESET, "DCCP-Reset" }, + { DCCP_PKT_SYNC, "DCCP-Sync" }, + { DCCP_PKT_SYNCACK, "DCCP-SyncAck" }, + { 0, NULL} }; enum dccp_reset_codes { @@ -139,412 +154,472 @@ enum dccp_reset_codes { DCCP_RESET_CODE_TOO_BUSY, DCCP_RESET_CODE_BAD_INIT_COOKIE, DCCP_RESET_CODE_AGGRESSION_PENALTY, - __DCCP_RESET_CODE_LAST }; -static const char tstr[] = "[|dccp]"; - -static const char *dccp_reset_codes[] = { - "unspecified", - "closed", - "aborted", - "no_connection", - "packet_error", - "option_error", - "mandatory_error", - "connection_refused", - "bad_service_code", - "too_busy", - "bad_init_cookie", - "aggression_penalty", +static const struct tok dccp_reset_code_str[] = { + { DCCP_RESET_CODE_UNSPECIFIED, "unspecified" }, + { DCCP_RESET_CODE_CLOSED, "closed" }, + { DCCP_RESET_CODE_ABORTED, "aborted" }, + { DCCP_RESET_CODE_NO_CONNECTION, "no_connection" }, + { DCCP_RESET_CODE_PACKET_ERROR, "packet_error" }, + { DCCP_RESET_CODE_OPTION_ERROR, "option_error" }, + { DCCP_RESET_CODE_MANDATORY_ERROR, "mandatory_error" }, + { DCCP_RESET_CODE_CONNECTION_REFUSED, "connection_refused" }, + { DCCP_RESET_CODE_BAD_SERVICE_CODE, "bad_service_code" }, + { DCCP_RESET_CODE_TOO_BUSY, "too_busy" }, + { DCCP_RESET_CODE_BAD_INIT_COOKIE, "bad_init_cookie" }, + { DCCP_RESET_CODE_AGGRESSION_PENALTY, "aggression_penalty" }, + { 0, NULL } }; -static const char *dccp_feature_nums[] = { - "reserved", - "ccid", - "allow_short_seqno", - "sequence_window", - "ecn_incapable", - "ack_ratio", - "send_ack_vector", - "send_ndp_count", - "minimum checksum coverage", - "check data checksum", +static const struct tok dccp_feature_num_str[] = { + { 0, "reserved" }, + { 1, "ccid" }, + { 2, "allow_short_seqno" }, + { 3, "sequence_window" }, + { 4, "ecn_incapable" }, + { 5, "ack_ratio" }, + { 6, "send_ack_vector" }, + { 7, "send_ndp_count" }, + { 8, "minimum_checksum_coverage" }, + { 9, "check_data_checksum" }, + { 0, NULL } }; -static inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len) +static u_int +dccp_csum_coverage(netdissect_options *ndo, + const struct dccp_hdr *dh, u_int len) { u_int cov; if (DCCPH_CSCOV(dh) == 0) return len; - cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t); + cov = (GET_U_1(dh->dccph_doff) + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t); return (cov > len)? len : cov; } -static int dccp_cksum(const struct ip *ip, +static uint16_t dccp_cksum(netdissect_options *ndo, const struct ip *ip, const struct dccp_hdr *dh, u_int len) { - return nextproto4_cksum(ip, (const u_int8_t *)(void *)dh, len, - dccp_csum_coverage(dh, len), IPPROTO_DCCP); + return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len, + dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP); } -#ifdef INET6 -static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len) -{ - return nextproto6_cksum(ip6, (const u_int8_t *)(void *)dh, len, - dccp_csum_coverage(dh, len), IPPROTO_DCCP); -} -#endif - -static const char *dccp_reset_code(u_int8_t code) +static uint16_t dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6, + const struct dccp_hdr *dh, u_int len) { - if (code >= __DCCP_RESET_CODE_LAST) - return "invalid"; - return dccp_reset_codes[code]; + return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len, + dccp_csum_coverage(ndo, dh, len), IPPROTO_DCCP); } -static u_int64_t dccp_seqno(const u_char *bp) +static uint64_t +dccp_seqno(netdissect_options *ndo, const u_char *bp) { const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; - u_int64_t seqno; + uint64_t seqno; if (DCCPH_X(dh) != 0) { const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp; - seqno = EXTRACT_48BITS(dhx->dccph_seq); + seqno = GET_BE_U_6(dhx->dccph_seq); } else { - seqno = EXTRACT_24BITS(dh->dccph_seq); + seqno = GET_BE_U_3(dh->dccph_seq); } return seqno; } -static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh) +static unsigned int +dccp_basic_hdr_len(netdissect_options *ndo, const struct dccp_hdr *dh) { return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr); } -static void dccp_print_ack_no(const u_char *bp) +static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp) { const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; - const u_char *ackp = bp + dccp_basic_hdr_len(dh); - u_int64_t ackno; + const u_char *ackp = bp + dccp_basic_hdr_len(ndo, dh); + uint64_t ackno; if (DCCPH_X(dh) != 0) { - TCHECK2(*ackp, 8); - ackno = EXTRACT_48BITS(ackp + 2); + ackno = GET_BE_U_6(ackp + 2); } else { - TCHECK2(*ackp, 4); - ackno = EXTRACT_24BITS(ackp + 1); + ackno = GET_BE_U_3(ackp + 1); } - (void)printf("(ack=%" PRIu64 ") ", ackno); -trunc: - return; + ND_PRINT("(ack=%" PRIu64 ") ", ackno); } -static int dccp_print_option(const u_char *option); +static u_int dccp_print_option(netdissect_options *, const u_char *, u_int); /** * dccp_print - show dccp packet * @bp - beginning of dccp packet * @data2 - beginning of enclosing - * @len - lenght of ip packet + * @len - length of ip packet */ -void dccp_print(const u_char *bp, const u_char *data2, u_int len) +void +dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2, + u_int length) { const struct dccp_hdr *dh; const struct ip *ip; -#ifdef INET6 const struct ip6_hdr *ip6; -#endif const u_char *cp; u_short sport, dport; u_int hlen; - u_int extlen = 0; + u_int fixed_hdrlen; + uint8_t dccph_type; + ndo->ndo_protocol = "dccp"; dh = (const struct dccp_hdr *)bp; - ip = (struct ip *)data2; -#ifdef INET6 + ip = (const struct ip *)data2; if (IP_V(ip) == 6) ip6 = (const struct ip6_hdr *)data2; else ip6 = NULL; -#endif /*INET6*/ + cp = (const u_char *)(dh + 1); - if (cp > snapend) { - printf("[Invalid packet|dccp]"); - return; - } + ND_ICHECK_ZU(length, <, sizeof(struct dccp_hdr)); - if (len < sizeof(struct dccp_hdr)) { - printf("truncated-dccp - %ld bytes missing!", - (long)len - sizeof(struct dccp_hdr)); - return; - } + /* get the length of the generic header */ + fixed_hdrlen = dccp_basic_hdr_len(ndo, dh); + ND_ICHECK_U(length, <, fixed_hdrlen); + ND_TCHECK_LEN(dh, fixed_hdrlen); - sport = EXTRACT_16BITS(&dh->dccph_sport); - dport = EXTRACT_16BITS(&dh->dccph_dport); - hlen = dh->dccph_doff * 4; + sport = GET_BE_U_2(dh->dccph_sport); + dport = GET_BE_U_2(dh->dccph_dport); + hlen = GET_U_1(dh->dccph_doff) * 4; -#ifdef INET6 if (ip6) { - (void)printf("%s.%d > %s.%d: ", - ip6addr_string(&ip6->ip6_src), sport, - ip6addr_string(&ip6->ip6_dst), dport); - } else -#endif /*INET6*/ - { - (void)printf("%s.%d > %s.%d: ", - ipaddr_string(&ip->ip_src), sport, - ipaddr_string(&ip->ip_dst), dport); + ND_PRINT("%s.%u > %s.%u: ", + GET_IP6ADDR_STRING(ip6->ip6_src), sport, + GET_IP6ADDR_STRING(ip6->ip6_dst), dport); + } else { + ND_PRINT("%s.%u > %s.%u: ", + GET_IPADDR_STRING(ip->ip_src), sport, + GET_IPADDR_STRING(ip->ip_dst), dport); } - fflush(stdout); - if (qflag) { - (void)printf(" %d", len - hlen); - if (hlen > len) { - (void)printf("dccp [bad hdr length %u - too long, > %u]", - hlen, len); - } + nd_print_protocol_caps(ndo); + + if (ndo->ndo_qflag) { + ND_ICHECK_U(length, <, hlen); + ND_PRINT(" %u", length - hlen); return; } /* other variables in generic header */ - if (vflag) { - (void)printf("CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)); - } - - /* checksum calculation */ - if (vflag && TTEST2(bp[0], len)) { - u_int16_t sum = 0, dccp_sum; - - dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum); - (void)printf("cksum 0x%04x ", dccp_sum); - if (IP_V(ip) == 4) - sum = dccp_cksum(ip, dh, len); -#ifdef INET6 - else if (IP_V(ip) == 6) - sum = dccp6_cksum(ip6, dh, len); -#endif - if (sum != 0) - (void)printf("(incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum)); - else - (void)printf("(correct), "); + if (ndo->ndo_vflag) { + ND_PRINT(" (CCVal %u, CsCov %u", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)); + /* checksum calculation */ + if (ND_TTEST_LEN(bp, length)) { + uint16_t sum = 0, dccp_sum; + + dccp_sum = GET_BE_U_2(dh->dccph_checksum); + ND_PRINT(", cksum 0x%04x ", dccp_sum); + if (IP_V(ip) == 4) + sum = dccp_cksum(ndo, ip, dh, length); + else if (IP_V(ip) == 6) + sum = dccp6_cksum(ndo, ip6, dh, length); + if (sum != 0) + ND_PRINT("(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum)); + else + ND_PRINT("(correct)"); + } + ND_PRINT(")"); } - switch (DCCPH_TYPE(dh)) { + dccph_type = DCCPH_TYPE(dh); + ND_PRINT(" %s ", tok2str(dccp_pkt_type_str, "packet-type-%u", + dccph_type)); + switch (dccph_type) { case DCCP_PKT_REQUEST: { - struct dccp_hdr_request *dhr = - (struct dccp_hdr_request *)(bp + dccp_basic_hdr_len(dh)); - TCHECK(*dhr); - (void)printf("request (service=%d) ", - EXTRACT_32BITS(&dhr->dccph_req_service)); - extlen += 4; + const struct dccp_hdr_request *dhr = + (const struct dccp_hdr_request *)(bp + fixed_hdrlen); + fixed_hdrlen += 4; + ND_ICHECK_U(length, <, fixed_hdrlen); + ND_PRINT("(service=%u) ", GET_BE_U_4(dhr->dccph_req_service)); break; } case DCCP_PKT_RESPONSE: { - struct dccp_hdr_response *dhr = - (struct dccp_hdr_response *)(bp + dccp_basic_hdr_len(dh)); - TCHECK(*dhr); - (void)printf("response (service=%d) ", - EXTRACT_32BITS(&dhr->dccph_resp_service)); - extlen += 12; + const struct dccp_hdr_response *dhr = + (const struct dccp_hdr_response *)(bp + fixed_hdrlen); + fixed_hdrlen += 12; + ND_ICHECK_U(length, <, fixed_hdrlen); + ND_PRINT("(service=%u) ", GET_BE_U_4(dhr->dccph_resp_service)); break; } case DCCP_PKT_DATA: - (void)printf("data "); break; case DCCP_PKT_ACK: { - (void)printf("ack "); - extlen += 8; + fixed_hdrlen += 8; + ND_ICHECK_U(length, <, fixed_hdrlen); break; } case DCCP_PKT_DATAACK: { - (void)printf("dataack "); - extlen += 8; + fixed_hdrlen += 8; + ND_ICHECK_U(length, <, fixed_hdrlen); break; } case DCCP_PKT_CLOSEREQ: - (void)printf("closereq "); - extlen += 8; + fixed_hdrlen += 8; + ND_ICHECK_U(length, <, fixed_hdrlen); break; case DCCP_PKT_CLOSE: - (void)printf("close "); - extlen += 8; + fixed_hdrlen += 8; + ND_ICHECK_U(length, <, fixed_hdrlen); break; case DCCP_PKT_RESET: { - struct dccp_hdr_reset *dhr = - (struct dccp_hdr_reset *)(bp + dccp_basic_hdr_len(dh)); - TCHECK(*dhr); - (void)printf("reset (code=%s) ", - dccp_reset_code(dhr->dccph_reset_code)); - extlen += 12; + const struct dccp_hdr_reset *dhr = + (const struct dccp_hdr_reset *)(bp + fixed_hdrlen); + fixed_hdrlen += 12; + ND_ICHECK_U(length, <, fixed_hdrlen); + ND_TCHECK_SIZE(dhr); + ND_PRINT("(code=%s) ", tok2str(dccp_reset_code_str, + "reset-code-%u (invalid)", GET_U_1(dhr->dccph_reset_code))); break; } case DCCP_PKT_SYNC: - (void)printf("sync "); - extlen += 8; + fixed_hdrlen += 8; + ND_ICHECK_U(length, <, fixed_hdrlen); break; case DCCP_PKT_SYNCACK: - (void)printf("syncack "); - extlen += 8; + fixed_hdrlen += 8; + ND_ICHECK_U(length, <, fixed_hdrlen); break; default: - (void)printf("invalid "); - break; + goto invalid; } if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) && (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST)) - dccp_print_ack_no(bp); + dccp_print_ack_no(ndo, bp); - if (vflag < 2) + if (ndo->ndo_vflag < 2) return; - (void)printf("seq %" PRIu64, dccp_seqno(bp)); + ND_PRINT("seq %" PRIu64, dccp_seqno(ndo, bp)); /* process options */ - if (hlen > dccp_basic_hdr_len(dh) + extlen){ - const u_char *cp; + if (hlen > fixed_hdrlen){ u_int optlen; - cp = bp + dccp_basic_hdr_len(dh) + extlen; - printf(" <"); + cp = bp + fixed_hdrlen; + ND_PRINT(" <"); - hlen -= dccp_basic_hdr_len(dh) + extlen; + hlen -= fixed_hdrlen; while(1){ - TCHECK(*cp); - optlen = dccp_print_option(cp); - if (!optlen) goto trunc2; - if (hlen <= optlen) break; + optlen = dccp_print_option(ndo, cp, hlen); + if (!optlen) + goto invalid; + if (hlen <= optlen) + break; hlen -= optlen; cp += optlen; - printf(", "); + ND_PRINT(", "); } - printf(">"); + ND_PRINT(">"); } return; -trunc: - printf("%s", tstr); -trunc2: - return; +invalid: + nd_print_invalid(ndo); } -static int dccp_print_option(const u_char *option) -{ - u_int8_t optlen, i; - - TCHECK(*option); +enum dccp_option_type { + DCCP_OPTION_PADDING = 0, + DCCP_OPTION_MANDATORY = 1, + DCCP_OPTION_SLOW_RECEIVER = 2, + DCCP_OPTION_CHANGE_L = 32, + DCCP_OPTION_CONFIRM_L = 33, + DCCP_OPTION_CHANGE_R = 34, + DCCP_OPTION_CONFIRM_R = 35, + DCCP_OPTION_INIT_COOKIE = 36, + DCCP_OPTION_NDP_COUNT = 37, + DCCP_OPTION_ACK_VECTOR_NONCE_0 = 38, + DCCP_OPTION_ACK_VECTOR_NONCE_1 = 39, + DCCP_OPTION_DATA_DROPPED = 40, + DCCP_OPTION_TIMESTAMP = 41, + DCCP_OPTION_TIMESTAMP_ECHO = 42, + DCCP_OPTION_ELAPSED_TIME = 43, + DCCP_OPTION_DATA_CHECKSUM = 44 +}; - if (*option >= 32) { - TCHECK(*(option+1)); - optlen = *(option +1); - if (optlen < 2) { - printf("Option %d optlen too short",*option); - return 1; - } - } else optlen = 1; +static const struct tok dccp_option_values[] = { + { DCCP_OPTION_PADDING, "nop" }, + { DCCP_OPTION_MANDATORY, "mandatory" }, + { DCCP_OPTION_SLOW_RECEIVER, "slowreceiver" }, + { DCCP_OPTION_CHANGE_L, "change_l" }, + { DCCP_OPTION_CONFIRM_L, "confirm_l" }, + { DCCP_OPTION_CHANGE_R, "change_r" }, + { DCCP_OPTION_CONFIRM_R, "confirm_r" }, + { DCCP_OPTION_INIT_COOKIE, "initcookie" }, + { DCCP_OPTION_NDP_COUNT, "ndp_count" }, + { DCCP_OPTION_ACK_VECTOR_NONCE_0, "ack_vector0" }, + { DCCP_OPTION_ACK_VECTOR_NONCE_1, "ack_vector1" }, + { DCCP_OPTION_DATA_DROPPED, "data_dropped" }, + { DCCP_OPTION_TIMESTAMP, "timestamp" }, + { DCCP_OPTION_TIMESTAMP_ECHO, "timestamp_echo" }, + { DCCP_OPTION_ELAPSED_TIME, "elapsed_time" }, + { DCCP_OPTION_DATA_CHECKSUM, "data_checksum" }, + { 0, NULL } +}; - TCHECK2(*option,optlen); +static u_int +dccp_print_option(netdissect_options *ndo, const u_char *bp, u_int hlen) +{ + uint8_t option, optlen, i; - switch (*option){ - case 0: - printf("nop"); - break; - case 1: - printf("mandatory"); - break; - case 2: - printf("slowreceiver"); - break; - case 32: - printf("change_l"); - if (*(option +2) < 10){ - printf(" %s", dccp_feature_nums[*(option +2)]); - for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); - } - break; - case 33: - printf("confirm_l"); - if (*(option +2) < 10){ - printf(" %s", dccp_feature_nums[*(option +2)]); - for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); - } - break; - case 34: - printf("change_r"); - if (*(option +2) < 10){ - printf(" %s", dccp_feature_nums[*(option +2)]); - for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); - } - break; - case 35: - printf("confirm_r"); - if (*(option +2) < 10){ - printf(" %s", dccp_feature_nums[*(option +2)]); - for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); + option = GET_U_1(bp); + if (option >= 128) + ND_PRINT("CCID option %u", option); + else + ND_PRINT("%s", + tok2str(dccp_option_values, "option-type-%u", option)); + if (option >= 32) { + optlen = GET_U_1(bp + 1); + ND_ICHECK_U(optlen, <, 2); + } else + optlen = 1; + + ND_ICHECKMSG_U("remaining length", hlen, <, optlen); + + if (option >= 128) { + switch (optlen) { + case 4: + ND_PRINT(" %u", GET_BE_U_2(bp + 2)); + break; + case 6: + ND_PRINT(" %u", GET_BE_U_4(bp + 2)); + break; + default: + ND_PRINT(" 0x"); + for (i = 0; i < optlen - 2; i++) + ND_PRINT("%02x", GET_U_1(bp + 2 + i)); + break; } - break; - case 36: - printf("initcookie 0x"); - for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); - break; - case 37: - printf("ndp_count"); - for (i = 0; i < optlen -2; i ++) printf(" %d", *(option +2 + i)); - break; - case 38: - printf("ack_vector0 0x"); - for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); - break; - case 39: - printf("ack_vector1 0x"); - for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); - break; - case 40: - printf("data_dropped 0x"); - for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); - break; - case 41: - printf("timestamp %u", EXTRACT_32BITS(option + 2)); - break; - case 42: - printf("timestamp_echo %u", EXTRACT_32BITS(option + 2)); - break; - case 43: - printf("elapsed_time "); - if (optlen == 6) - printf("%u", EXTRACT_32BITS(option + 2)); - else - printf("%u", EXTRACT_16BITS(option + 2)); - break; - case 44: - printf("data_checksum "); - for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); - break; - default : - if (*option >= 128) { - printf("CCID option %d",*option); + } else { + switch (option) { + case DCCP_OPTION_PADDING: + case DCCP_OPTION_MANDATORY: + case DCCP_OPTION_SLOW_RECEIVER: + ND_TCHECK_1(bp); + break; + case DCCP_OPTION_CHANGE_L: + case DCCP_OPTION_CHANGE_R: + ND_ICHECK_U(optlen, <, 4); + ND_PRINT(" %s", tok2str(dccp_feature_num_str, + "feature-number-%u (invalid)", GET_U_1(bp + 2))); + for (i = 0; i < optlen - 3; i++) + ND_PRINT(" %u", GET_U_1(bp + 3 + i)); + break; + case DCCP_OPTION_CONFIRM_L: + case DCCP_OPTION_CONFIRM_R: + ND_ICHECK_U(optlen, <, 3); + ND_PRINT(" %s", tok2str(dccp_feature_num_str, + "feature-number-%u (invalid)", GET_U_1(bp + 2))); + for (i = 0; i < optlen - 3; i++) + ND_PRINT(" %u", GET_U_1(bp + 3 + i)); + break; + case DCCP_OPTION_INIT_COOKIE: + ND_ICHECK_U(optlen, <, 3); + ND_PRINT(" 0x"); + for (i = 0; i < optlen - 2; i++) + ND_PRINT("%02x", GET_U_1(bp + 2 + i)); + break; + case DCCP_OPTION_NDP_COUNT: + ND_ICHECK_U(optlen, <, 3); + ND_ICHECK_U(optlen, >, 8); + for (i = 0; i < optlen - 2; i++) + ND_PRINT(" %u", GET_U_1(bp + 2 + i)); + break; + case DCCP_OPTION_ACK_VECTOR_NONCE_0: + case DCCP_OPTION_ACK_VECTOR_NONCE_1: + ND_ICHECK_U(optlen, <, 3); + ND_PRINT(" 0x"); + for (i = 0; i < optlen - 2; i++) + ND_PRINT("%02x", GET_U_1(bp + 2 + i)); + break; + case DCCP_OPTION_DATA_DROPPED: + ND_ICHECK_U(optlen, <, 3); + ND_PRINT(" 0x"); + for (i = 0; i < optlen - 2; i++) + ND_PRINT("%02x", GET_U_1(bp + 2 + i)); + break; + case DCCP_OPTION_TIMESTAMP: + /* + * 13.1. Timestamp Option + * + * +--------+--------+--------+--------+--------+--------+ + * |00101001|00000110| Timestamp Value | + * +--------+--------+--------+--------+--------+--------+ + * Type=41 Length=6 + */ + ND_ICHECK_U(optlen, !=, 6); + ND_PRINT(" %u", GET_BE_U_4(bp + 2)); + break; + case DCCP_OPTION_TIMESTAMP_ECHO: + /* + * 13.3. Timestamp Echo Option + * + * +--------+--------+--------+--------+--------+--------+ + * |00101010|00000110| Timestamp Echo | + * +--------+--------+--------+--------+--------+--------+ + * Type=42 Len=6 + * + * +--------+--------+------- ... -------+--------+--------+ + * |00101010|00001000| Timestamp Echo | Elapsed Time | + * +--------+--------+------- ... -------+--------+--------+ + * Type=42 Len=8 (4 bytes) + * + * +--------+--------+------- ... -------+------- ... -------+ + * |00101010|00001010| Timestamp Echo | Elapsed Time | + * +--------+--------+------- ... -------+------- ... -------+ + * Type=42 Len=10 (4 bytes) (4 bytes) + */ + switch (optlen) { + case 6: + ND_PRINT(" %u", GET_BE_U_4(bp + 2)); + break; + case 8: + ND_PRINT(" %u", GET_BE_U_4(bp + 2)); + ND_PRINT(" (elapsed time %u)", + GET_BE_U_2(bp + 6)); + break; + case 10: + ND_PRINT(" %u", GET_BE_U_4(bp + 2)); + ND_PRINT(" (elapsed time %u)", + GET_BE_U_4(bp + 6)); + break; + default: + ND_PRINT(" [optlen != 6 or 8 or 10]"); + goto invalid; + } + break; + case DCCP_OPTION_ELAPSED_TIME: switch (optlen) { - case 4: - printf(" %u", EXTRACT_16BITS(option + 2)); - break; - case 6: - printf(" %u", EXTRACT_32BITS(option + 2)); - break; - default: - break; + case 4: + ND_PRINT(" %u", GET_BE_U_2(bp + 2)); + break; + case 6: + ND_PRINT(" %u", GET_BE_U_4(bp + 2)); + break; + default: + ND_PRINT(" [optlen != 4 or 6]"); + goto invalid; } break; + case DCCP_OPTION_DATA_CHECKSUM: + ND_ICHECK_U(optlen, !=, 6); + ND_PRINT(" 0x"); + for (i = 0; i < optlen - 2; i++) + ND_PRINT("%02x", GET_U_1(bp + 2 + i)); + break; + default: + goto invalid; } - - printf("unknown_opt %d", *option); - break; } return optlen; -trunc: - printf("%s", tstr); +invalid: return 0; }