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