Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (C) Arnaldo Carvalho de Melo 2004
      3  * Copyright (C) Ian McDonald 2005
      4  * Copyright (C) Yoshifumi Nishida 2005
      5  *
      6  * This software may be distributed either under the terms of the
      7  * BSD-style license that accompanies tcpdump or the GNU GPL version 2
      8  */
      9 
     10 /* \summary: Datagram Congestion Control Protocol (DCCP) printer */
     11 
     12 #ifdef HAVE_CONFIG_H
     13 #include "config.h"
     14 #endif
     15 
     16 #include <netdissect-stdinc.h>
     17 
     18 #include <stdio.h>
     19 #include <string.h>
     20 
     21 #include "netdissect.h"
     22 #include "addrtoname.h"
     23 #include "extract.h"
     24 #include "ip.h"
     25 #include "ip6.h"
     26 #include "ipproto.h"
     27 
     28 /* RFC4340: Datagram Congestion Control Protocol (DCCP) */
     29 
     30 /**
     31  * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit
     32  * sequence number
     33  *
     34  * @dccph_sport - Relevant port on the endpoint that sent this packet
     35  * @dccph_dport - Relevant port on the other endpoint
     36  * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
     37  * @dccph_ccval - Used by the HC-Sender CCID
     38  * @dccph_cscov - Parts of the packet that are covered by the Checksum field
     39  * @dccph_checksum - Internet checksum, depends on dccph_cscov
     40  * @dccph_x - 0 = 24 bit sequence number, 1 = 48
     41  * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
     42  * @dccph_seq - 24-bit sequence number
     43  */
     44 struct dccp_hdr {
     45 	uint16_t	dccph_sport,
     46 			dccph_dport;
     47 	uint8_t		dccph_doff;
     48 	uint8_t		dccph_ccval_cscov;
     49 	uint16_t	dccph_checksum;
     50 	uint8_t		dccph_xtr;
     51 	uint8_t		dccph_seq[3];
     52 } UNALIGNED;
     53 
     54 /**
     55  * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit
     56  * sequence number
     57  *
     58  * @dccph_sport - Relevant port on the endpoint that sent this packet
     59  * @dccph_dport - Relevant port on the other endpoint
     60  * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
     61  * @dccph_ccval - Used by the HC-Sender CCID
     62  * @dccph_cscov - Parts of the packet that are covered by the Checksum field
     63  * @dccph_checksum - Internet checksum, depends on dccph_cscov
     64  * @dccph_x - 0 = 24 bit sequence number, 1 = 48
     65  * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
     66  * @dccph_seq - 48-bit sequence number
     67  */
     68 struct dccp_hdr_ext {
     69 	uint16_t	dccph_sport,
     70 			dccph_dport;
     71 	uint8_t		dccph_doff;
     72 	uint8_t		dccph_ccval_cscov;
     73 	uint16_t	dccph_checksum;
     74 	uint8_t		dccph_xtr;
     75 	uint8_t		reserved;
     76 	uint8_t		dccph_seq[6];
     77 } UNALIGNED;
     78 
     79 #define DCCPH_CCVAL(dh)	(((dh)->dccph_ccval_cscov >> 4) & 0xF)
     80 #define DCCPH_CSCOV(dh)	(((dh)->dccph_ccval_cscov) & 0xF)
     81 
     82 #define DCCPH_X(dh)	((dh)->dccph_xtr & 1)
     83 #define DCCPH_TYPE(dh)	(((dh)->dccph_xtr >> 1) & 0xF)
     84 
     85 /**
     86  * struct dccp_hdr_request - Conection initiation request header
     87  *
     88  * @dccph_req_service - Service to which the client app wants to connect
     89  */
     90 struct dccp_hdr_request {
     91 	uint32_t	dccph_req_service;
     92 } UNALIGNED;
     93 
     94 /**
     95  * struct dccp_hdr_response - Conection initiation response header
     96  *
     97  * @dccph_resp_ack - 48 bit ack number, contains GSR
     98  * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request
     99  */
    100 struct dccp_hdr_response {
    101 	uint8_t				dccph_resp_ack[8];	/* always 8 bytes */
    102 	uint32_t			dccph_resp_service;
    103 } UNALIGNED;
    104 
    105 /**
    106  * struct dccp_hdr_reset - Unconditionally shut down a connection
    107  *
    108  * @dccph_resp_ack - 48 bit ack number
    109  * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request
    110  */
    111 struct dccp_hdr_reset {
    112 	uint8_t				dccph_reset_ack[8];	/* always 8 bytes */
    113 	uint8_t				dccph_reset_code,
    114 					dccph_reset_data[3];
    115 } UNALIGNED;
    116 
    117 enum dccp_pkt_type {
    118 	DCCP_PKT_REQUEST = 0,
    119 	DCCP_PKT_RESPONSE,
    120 	DCCP_PKT_DATA,
    121 	DCCP_PKT_ACK,
    122 	DCCP_PKT_DATAACK,
    123 	DCCP_PKT_CLOSEREQ,
    124 	DCCP_PKT_CLOSE,
    125 	DCCP_PKT_RESET,
    126 	DCCP_PKT_SYNC,
    127 	DCCP_PKT_SYNCACK
    128 };
    129 
    130 static const struct tok dccp_pkt_type_str[] = {
    131 	{ DCCP_PKT_REQUEST, "DCCP-Request" },
    132 	{ DCCP_PKT_RESPONSE, "DCCP-Response" },
    133 	{ DCCP_PKT_DATA, "DCCP-Data" },
    134 	{ DCCP_PKT_ACK, "DCCP-Ack" },
    135 	{ DCCP_PKT_DATAACK, "DCCP-DataAck" },
    136 	{ DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" },
    137 	{ DCCP_PKT_CLOSE, "DCCP-Close" },
    138 	{ DCCP_PKT_RESET, "DCCP-Reset" },
    139 	{ DCCP_PKT_SYNC, "DCCP-Sync" },
    140 	{ DCCP_PKT_SYNCACK, "DCCP-SyncAck" },
    141 	{ 0, NULL}
    142 };
    143 
    144 enum dccp_reset_codes {
    145 	DCCP_RESET_CODE_UNSPECIFIED = 0,
    146 	DCCP_RESET_CODE_CLOSED,
    147 	DCCP_RESET_CODE_ABORTED,
    148 	DCCP_RESET_CODE_NO_CONNECTION,
    149 	DCCP_RESET_CODE_PACKET_ERROR,
    150 	DCCP_RESET_CODE_OPTION_ERROR,
    151 	DCCP_RESET_CODE_MANDATORY_ERROR,
    152 	DCCP_RESET_CODE_CONNECTION_REFUSED,
    153 	DCCP_RESET_CODE_BAD_SERVICE_CODE,
    154 	DCCP_RESET_CODE_TOO_BUSY,
    155 	DCCP_RESET_CODE_BAD_INIT_COOKIE,
    156 	DCCP_RESET_CODE_AGGRESSION_PENALTY,
    157 	__DCCP_RESET_CODE_LAST
    158 };
    159 
    160 static const char tstr[] = "[|dccp]";
    161 
    162 static const char *dccp_reset_codes[] = {
    163 	"unspecified",
    164 	"closed",
    165 	"aborted",
    166 	"no_connection",
    167 	"packet_error",
    168 	"option_error",
    169 	"mandatory_error",
    170 	"connection_refused",
    171 	"bad_service_code",
    172 	"too_busy",
    173 	"bad_init_cookie",
    174 	"aggression_penalty",
    175 };
    176 
    177 static const char *dccp_feature_nums[] = {
    178 	"reserved",
    179 	"ccid",
    180 	"allow_short_seqno",
    181 	"sequence_window",
    182 	"ecn_incapable",
    183 	"ack_ratio",
    184 	"send_ack_vector",
    185 	"send_ndp_count",
    186 	"minimum checksum coverage",
    187 	"check data checksum",
    188 };
    189 
    190 static inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len)
    191 {
    192 	u_int cov;
    193 
    194 	if (DCCPH_CSCOV(dh) == 0)
    195 		return len;
    196 	cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t);
    197 	return (cov > len)? len : cov;
    198 }
    199 
    200 static int dccp_cksum(netdissect_options *ndo, const struct ip *ip,
    201 	const struct dccp_hdr *dh, u_int len)
    202 {
    203 	return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len,
    204 				dccp_csum_coverage(dh, len), IPPROTO_DCCP);
    205 }
    206 
    207 static int dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
    208 	const struct dccp_hdr *dh, u_int len)
    209 {
    210 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len,
    211 				dccp_csum_coverage(dh, len), IPPROTO_DCCP);
    212 }
    213 
    214 static const char *dccp_reset_code(uint8_t code)
    215 {
    216 	if (code >= __DCCP_RESET_CODE_LAST)
    217 		return "invalid";
    218 	return dccp_reset_codes[code];
    219 }
    220 
    221 static uint64_t dccp_seqno(const u_char *bp)
    222 {
    223 	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
    224 	uint64_t seqno;
    225 
    226 	if (DCCPH_X(dh) != 0) {
    227 		const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp;
    228 		seqno = EXTRACT_48BITS(dhx->dccph_seq);
    229 	} else {
    230 		seqno = EXTRACT_24BITS(dh->dccph_seq);
    231 	}
    232 
    233 	return seqno;
    234 }
    235 
    236 static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh)
    237 {
    238 	return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr);
    239 }
    240 
    241 static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp)
    242 {
    243 	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
    244 	const u_char *ackp = bp + dccp_basic_hdr_len(dh);
    245 	uint64_t ackno;
    246 
    247 	if (DCCPH_X(dh) != 0) {
    248 		ND_TCHECK2(*ackp, 8);
    249 		ackno = EXTRACT_48BITS(ackp + 2);
    250 	} else {
    251 		ND_TCHECK2(*ackp, 4);
    252 		ackno = EXTRACT_24BITS(ackp + 1);
    253 	}
    254 
    255 	ND_PRINT((ndo, "(ack=%" PRIu64 ") ", ackno));
    256 trunc:
    257 	return;
    258 }
    259 
    260 static int dccp_print_option(netdissect_options *, const u_char *, u_int);
    261 
    262 /**
    263  * dccp_print - show dccp packet
    264  * @bp - beginning of dccp packet
    265  * @data2 - beginning of enclosing
    266  * @len - lenght of ip packet
    267  */
    268 void dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2,
    269 		u_int len)
    270 {
    271 	const struct dccp_hdr *dh;
    272 	const struct ip *ip;
    273 	const struct ip6_hdr *ip6;
    274 	const u_char *cp;
    275 	u_short sport, dport;
    276 	u_int hlen;
    277 	u_int fixed_hdrlen;
    278 	uint8_t	dccph_type;
    279 
    280 	dh = (const struct dccp_hdr *)bp;
    281 
    282 	ip = (const struct ip *)data2;
    283 	if (IP_V(ip) == 6)
    284 		ip6 = (const struct ip6_hdr *)data2;
    285 	else
    286 		ip6 = NULL;
    287 
    288 	/* make sure we have enough data to look at the X bit */
    289 	cp = (const u_char *)(dh + 1);
    290 	if (cp > ndo->ndo_snapend) {
    291 		ND_PRINT((ndo, "[Invalid packet|dccp]"));
    292 		return;
    293 	}
    294 	if (len < sizeof(struct dccp_hdr)) {
    295 		ND_PRINT((ndo, "truncated-dccp - %u bytes missing!",
    296 			  len - (u_int)sizeof(struct dccp_hdr)));
    297 		return;
    298 	}
    299 
    300 	/* get the length of the generic header */
    301 	fixed_hdrlen = dccp_basic_hdr_len(dh);
    302 	if (len < fixed_hdrlen) {
    303 		ND_PRINT((ndo, "truncated-dccp - %u bytes missing!",
    304 			  len - fixed_hdrlen));
    305 		return;
    306 	}
    307 	ND_TCHECK2(*dh, fixed_hdrlen);
    308 
    309 	sport = EXTRACT_16BITS(&dh->dccph_sport);
    310 	dport = EXTRACT_16BITS(&dh->dccph_dport);
    311 	hlen = dh->dccph_doff * 4;
    312 
    313 	if (ip6) {
    314 		ND_PRINT((ndo, "%s.%d > %s.%d: ",
    315 			  ip6addr_string(ndo, &ip6->ip6_src), sport,
    316 			  ip6addr_string(ndo, &ip6->ip6_dst), dport));
    317 	} else {
    318 		ND_PRINT((ndo, "%s.%d > %s.%d: ",
    319 			  ipaddr_string(ndo, &ip->ip_src), sport,
    320 			  ipaddr_string(ndo, &ip->ip_dst), dport));
    321 	}
    322 
    323 	ND_PRINT((ndo, "DCCP"));
    324 
    325 	if (ndo->ndo_qflag) {
    326 		ND_PRINT((ndo, " %d", len - hlen));
    327 		if (hlen > len) {
    328 			ND_PRINT((ndo, " [bad hdr length %u - too long, > %u]",
    329 				  hlen, len));
    330 		}
    331 		return;
    332 	}
    333 
    334 	/* other variables in generic header */
    335 	if (ndo->ndo_vflag) {
    336 		ND_PRINT((ndo, " (CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)));
    337 	}
    338 
    339 	/* checksum calculation */
    340 	if (ndo->ndo_vflag && ND_TTEST2(bp[0], len)) {
    341 		uint16_t sum = 0, dccp_sum;
    342 
    343 		dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
    344 		ND_PRINT((ndo, "cksum 0x%04x ", dccp_sum));
    345 		if (IP_V(ip) == 4)
    346 			sum = dccp_cksum(ndo, ip, dh, len);
    347 		else if (IP_V(ip) == 6)
    348 			sum = dccp6_cksum(ndo, ip6, dh, len);
    349 		if (sum != 0)
    350 			ND_PRINT((ndo, "(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum)));
    351 		else
    352 			ND_PRINT((ndo, "(correct)"));
    353 	}
    354 
    355 	if (ndo->ndo_vflag)
    356 		ND_PRINT((ndo, ")"));
    357 	ND_PRINT((ndo, " "));
    358 
    359 	dccph_type = DCCPH_TYPE(dh);
    360 	switch (dccph_type) {
    361 	case DCCP_PKT_REQUEST: {
    362 		const struct dccp_hdr_request *dhr =
    363 			(const struct dccp_hdr_request *)(bp + fixed_hdrlen);
    364 		fixed_hdrlen += 4;
    365 		if (len < fixed_hdrlen) {
    366 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    367 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    368 				  len - fixed_hdrlen));
    369 			return;
    370 		}
    371 		ND_TCHECK(*dhr);
    372 		ND_PRINT((ndo, "%s (service=%d) ",
    373 			  tok2str(dccp_pkt_type_str, "", dccph_type),
    374 			  EXTRACT_32BITS(&dhr->dccph_req_service)));
    375 		break;
    376 	}
    377 	case DCCP_PKT_RESPONSE: {
    378 		const struct dccp_hdr_response *dhr =
    379 			(const struct dccp_hdr_response *)(bp + fixed_hdrlen);
    380 		fixed_hdrlen += 12;
    381 		if (len < fixed_hdrlen) {
    382 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    383 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    384 				  len - fixed_hdrlen));
    385 			return;
    386 		}
    387 		ND_TCHECK(*dhr);
    388 		ND_PRINT((ndo, "%s (service=%d) ",
    389 			  tok2str(dccp_pkt_type_str, "", dccph_type),
    390 			  EXTRACT_32BITS(&dhr->dccph_resp_service)));
    391 		break;
    392 	}
    393 	case DCCP_PKT_DATA:
    394 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    395 		break;
    396 	case DCCP_PKT_ACK: {
    397 		fixed_hdrlen += 8;
    398 		if (len < fixed_hdrlen) {
    399 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    400 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    401 				  len - fixed_hdrlen));
    402 			return;
    403 		}
    404 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    405 		break;
    406 	}
    407 	case DCCP_PKT_DATAACK: {
    408 		fixed_hdrlen += 8;
    409 		if (len < fixed_hdrlen) {
    410 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    411 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    412 				  len - fixed_hdrlen));
    413 			return;
    414 		}
    415 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    416 		break;
    417 	}
    418 	case DCCP_PKT_CLOSEREQ:
    419 		fixed_hdrlen += 8;
    420 		if (len < fixed_hdrlen) {
    421 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    422 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    423 				  len - fixed_hdrlen));
    424 			return;
    425 		}
    426 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    427 		break;
    428 	case DCCP_PKT_CLOSE:
    429 		fixed_hdrlen += 8;
    430 		if (len < fixed_hdrlen) {
    431 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    432 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    433 				  len - fixed_hdrlen));
    434 			return;
    435 		}
    436 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    437 		break;
    438 	case DCCP_PKT_RESET: {
    439 		const struct dccp_hdr_reset *dhr =
    440 			(const struct dccp_hdr_reset *)(bp + fixed_hdrlen);
    441 		fixed_hdrlen += 12;
    442 		if (len < fixed_hdrlen) {
    443 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    444 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    445 				  len - fixed_hdrlen));
    446 			return;
    447 		}
    448 		ND_TCHECK(*dhr);
    449 		ND_PRINT((ndo, "%s (code=%s) ",
    450 			  tok2str(dccp_pkt_type_str, "", dccph_type),
    451 			  dccp_reset_code(dhr->dccph_reset_code)));
    452 		break;
    453 	}
    454 	case DCCP_PKT_SYNC:
    455 		fixed_hdrlen += 8;
    456 		if (len < fixed_hdrlen) {
    457 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    458 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    459 				  len - fixed_hdrlen));
    460 			return;
    461 		}
    462 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    463 		break;
    464 	case DCCP_PKT_SYNCACK:
    465 		fixed_hdrlen += 8;
    466 		if (len < fixed_hdrlen) {
    467 			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
    468 				  tok2str(dccp_pkt_type_str, "", dccph_type),
    469 				  len - fixed_hdrlen));
    470 			return;
    471 		}
    472 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
    473 		break;
    474 	default:
    475 		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type)));
    476 		break;
    477 	}
    478 
    479 	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
    480 			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
    481 		dccp_print_ack_no(ndo, bp);
    482 
    483 	if (ndo->ndo_vflag < 2)
    484 		return;
    485 
    486 	ND_PRINT((ndo, "seq %" PRIu64, dccp_seqno(bp)));
    487 
    488 	/* process options */
    489 	if (hlen > fixed_hdrlen){
    490 		u_int optlen;
    491 		cp = bp + fixed_hdrlen;
    492 		ND_PRINT((ndo, " <"));
    493 
    494 		hlen -= fixed_hdrlen;
    495 		while(1){
    496 			optlen = dccp_print_option(ndo, cp, hlen);
    497 			if (!optlen)
    498 				break;
    499 			if (hlen <= optlen)
    500 				break;
    501 			hlen -= optlen;
    502 			cp += optlen;
    503 			ND_PRINT((ndo, ", "));
    504 		}
    505 		ND_PRINT((ndo, ">"));
    506 	}
    507 	return;
    508 trunc:
    509 	ND_PRINT((ndo, "%s", tstr));
    510 	return;
    511 }
    512 
    513 static const struct tok dccp_option_values[] = {
    514 	{ 0, "nop" },
    515 	{ 1, "mandatory" },
    516 	{ 2, "slowreceiver" },
    517 	{ 32, "change_l" },
    518 	{ 33, "confirm_l" },
    519 	{ 34, "change_r" },
    520 	{ 35, "confirm_r" },
    521 	{ 36, "initcookie" },
    522 	{ 37, "ndp_count" },
    523 	{ 38, "ack_vector0" },
    524 	{ 39, "ack_vector1" },
    525 	{ 40, "data_dropped" },
    526 	{ 41, "timestamp" },
    527 	{ 42, "timestamp_echo" },
    528 	{ 43, "elapsed_time" },
    529 	{ 44, "data_checksum" },
    530 	{ 0, NULL }
    531 };
    532 
    533 static int dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
    534 {
    535 	uint8_t optlen, i;
    536 
    537 	ND_TCHECK(*option);
    538 
    539 	if (*option >= 32) {
    540 		ND_TCHECK(*(option+1));
    541 		optlen = *(option +1);
    542 		if (optlen < 2) {
    543 			if (*option >= 128)
    544 				ND_PRINT((ndo, "CCID option %u optlen too short", *option));
    545 			else
    546 				ND_PRINT((ndo, "%s optlen too short",
    547 					  tok2str(dccp_option_values, "Option %u", *option)));
    548 			return 0;
    549 		}
    550 	} else
    551 		optlen = 1;
    552 
    553 	if (hlen < optlen) {
    554 		if (*option >= 128)
    555 			ND_PRINT((ndo, "CCID option %u optlen goes past header length",
    556 				  *option));
    557 		else
    558 			ND_PRINT((ndo, "%s optlen goes past header length",
    559 				  tok2str(dccp_option_values, "Option %u", *option)));
    560 		return 0;
    561 	}
    562 	ND_TCHECK2(*option, optlen);
    563 
    564 	if (*option >= 128) {
    565 		ND_PRINT((ndo, "CCID option %d", *option));
    566 		switch (optlen) {
    567 			case 4:
    568 				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
    569 				break;
    570 			case 6:
    571 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
    572 				break;
    573 			default:
    574 				break;
    575 		}
    576 	} else {
    577 		ND_PRINT((ndo, "%s", tok2str(dccp_option_values, "Option %u", *option)));
    578 		switch (*option) {
    579 		case 32:
    580 		case 33:
    581 		case 34:
    582 		case 35:
    583 			if (optlen < 3) {
    584 				ND_PRINT((ndo, " optlen too short"));
    585 				return optlen;
    586 			}
    587 			if (*(option + 2) < 10){
    588 				ND_PRINT((ndo, " %s", dccp_feature_nums[*(option + 2)]));
    589 				for (i = 0; i < optlen - 3; i++)
    590 					ND_PRINT((ndo, " %d", *(option + 3 + i)));
    591 			}
    592 			break;
    593 		case 36:
    594 			if (optlen > 2) {
    595 				ND_PRINT((ndo, " 0x"));
    596 				for (i = 0; i < optlen - 2; i++)
    597 					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
    598 			}
    599 			break;
    600 		case 37:
    601 			for (i = 0; i < optlen - 2; i++)
    602 				ND_PRINT((ndo, " %d", *(option + 2 + i)));
    603 			break;
    604 		case 38:
    605 			if (optlen > 2) {
    606 				ND_PRINT((ndo, " 0x"));
    607 				for (i = 0; i < optlen - 2; i++)
    608 					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
    609 			}
    610 			break;
    611 		case 39:
    612 			if (optlen > 2) {
    613 				ND_PRINT((ndo, " 0x"));
    614 				for (i = 0; i < optlen - 2; i++)
    615 					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
    616 			}
    617 			break;
    618 		case 40:
    619 			if (optlen > 2) {
    620 				ND_PRINT((ndo, " 0x"));
    621 				for (i = 0; i < optlen - 2; i++)
    622 					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
    623 			}
    624 			break;
    625 		case 41:
    626 			if (optlen == 4)
    627 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
    628 			else
    629 				ND_PRINT((ndo, " optlen != 4"));
    630 			break;
    631 		case 42:
    632 			if (optlen == 4)
    633 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
    634 			else
    635 				ND_PRINT((ndo, " optlen != 4"));
    636 			break;
    637 		case 43:
    638 			if (optlen == 6)
    639 				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
    640 			else if (optlen == 4)
    641 				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
    642 			else
    643 				ND_PRINT((ndo, " optlen != 4 or 6"));
    644 			break;
    645 		case 44:
    646 			if (optlen > 2) {
    647 				ND_PRINT((ndo, " "));
    648 				for (i = 0; i < optlen - 2; i++)
    649 					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
    650 			}
    651 			break;
    652 		}
    653 	}
    654 
    655 	return optlen;
    656 trunc:
    657 	ND_PRINT((ndo, "%s", tstr));
    658 	return 0;
    659 }
    660